Rollup merge of #130094 - workingjubilee:concurrency-is-real, r=lcnr
Inform the solver if evaluation is concurrent Parallel compilation of a program can cause unexpected event sequencing. Inform the solver when this is true so it can skip invalid asserts.
This commit is contained in:
commit
2859c24e64
@ -181,6 +181,10 @@ fn with_global_cache<R>(
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluation_is_concurrent(&self) -> bool {
|
||||
self.sess.threads() > 1
|
||||
}
|
||||
|
||||
fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T {
|
||||
self.expand_abstract_consts(t)
|
||||
}
|
||||
|
@ -137,6 +137,8 @@ fn with_global_cache<R>(
|
||||
f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
|
||||
) -> R;
|
||||
|
||||
fn evaluation_is_concurrent(&self) -> bool;
|
||||
|
||||
fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T;
|
||||
|
||||
type GenericsOf: GenericsOf<Self>;
|
||||
@ -404,4 +406,7 @@ fn with_global_cache<R>(
|
||||
) -> R {
|
||||
I::with_global_cache(self, mode, f)
|
||||
}
|
||||
fn evaluation_is_concurrent(&self) -> bool {
|
||||
self.evaluation_is_concurrent()
|
||||
}
|
||||
}
|
||||
|
@ -44,22 +44,28 @@ pub(super) fn insert(
|
||||
cx: X,
|
||||
input: X::Input,
|
||||
|
||||
result: X::Result,
|
||||
origin_result: X::Result,
|
||||
dep_node: X::DepNodeIndex,
|
||||
|
||||
additional_depth: usize,
|
||||
encountered_overflow: bool,
|
||||
nested_goals: NestedGoals<X>,
|
||||
) {
|
||||
let result = cx.mk_tracked(result, dep_node);
|
||||
let result = cx.mk_tracked(origin_result, dep_node);
|
||||
let entry = self.map.entry(input).or_default();
|
||||
if encountered_overflow {
|
||||
let with_overflow = WithOverflow { nested_goals, result };
|
||||
let prev = entry.with_overflow.insert(additional_depth, with_overflow);
|
||||
assert!(prev.is_none());
|
||||
if let Some(prev) = &prev {
|
||||
assert!(cx.evaluation_is_concurrent());
|
||||
assert_eq!(cx.get_tracked(&prev.result), origin_result);
|
||||
}
|
||||
} else {
|
||||
let prev = entry.success.replace(Success { additional_depth, nested_goals, result });
|
||||
assert!(prev.is_none());
|
||||
if let Some(prev) = &prev {
|
||||
assert!(cx.evaluation_is_concurrent());
|
||||
assert_eq!(cx.get_tracked(&prev.result), origin_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,8 @@ fn with_global_cache<R>(
|
||||
mode: SolverMode,
|
||||
f: impl FnOnce(&mut GlobalCache<Self>) -> R,
|
||||
) -> R;
|
||||
|
||||
fn evaluation_is_concurrent(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait Delegate {
|
||||
|
@ -0,0 +1,27 @@
|
||||
//@ compile-flags: -Zthreads=16
|
||||
|
||||
// original issue: https://github.com/rust-lang/rust/issues/129112
|
||||
// Previously, the "next" solver asserted that each successful solution is only obtained once.
|
||||
// This test exhibits a repro that, with next-solver + -Zthreads, triggered that old assert.
|
||||
// In the presence of multithreaded solving, it's possible to concurrently evaluate things twice,
|
||||
// which leads to replacing already-solved solutions in the global solution cache!
|
||||
// We assume this is fine if we check to make sure they are solved the same way each time.
|
||||
|
||||
// This test only nondeterministically fails but that's okay, as it will be rerun by CI many times,
|
||||
// so it should almost always fail before anything is merged. As other thread tests already exist,
|
||||
// we already face this difficulty, probably. If we need to fix this by reducing the error margin,
|
||||
// we should improve compiletest.
|
||||
|
||||
#[derive(Clone, Eq)] //~ ERROR [E0277]
|
||||
pub struct Struct<T>(T);
|
||||
|
||||
impl<T: Clone, U> PartialEq<U> for Struct<T>
|
||||
where
|
||||
U: Into<Struct<T>> + Clone
|
||||
{
|
||||
fn eq(&self, _other: &U) -> bool {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,24 @@
|
||||
error[E0277]: the trait bound `T: Clone` is not satisfied
|
||||
--> $DIR/global-cache-and-parallel-frontend.rs:15:17
|
||||
|
|
||||
LL | #[derive(Clone, Eq)]
|
||||
| ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq`
|
||||
|
|
||||
note: required for `Struct<T>` to implement `PartialEq`
|
||||
--> $DIR/global-cache-and-parallel-frontend.rs:18:19
|
||||
|
|
||||
LL | impl<T: Clone, U> PartialEq<U> for Struct<T>
|
||||
| ----- ^^^^^^^^^^^^ ^^^^^^^^^
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
note: required by a bound in `Eq`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | pub struct Struct<T: std::clone::Clone>(T);
|
||||
| +++++++++++++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user