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 {
|
fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T {
|
||||||
self.expand_abstract_consts(t)
|
self.expand_abstract_consts(t)
|
||||||
}
|
}
|
||||||
|
@ -137,6 +137,8 @@ fn with_global_cache<R>(
|
|||||||
f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
|
f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
|
||||||
) -> R;
|
) -> R;
|
||||||
|
|
||||||
|
fn evaluation_is_concurrent(&self) -> bool;
|
||||||
|
|
||||||
fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T;
|
fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T;
|
||||||
|
|
||||||
type GenericsOf: GenericsOf<Self>;
|
type GenericsOf: GenericsOf<Self>;
|
||||||
@ -404,4 +406,7 @@ fn with_global_cache<R>(
|
|||||||
) -> R {
|
) -> R {
|
||||||
I::with_global_cache(self, mode, f)
|
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,
|
cx: X,
|
||||||
input: X::Input,
|
input: X::Input,
|
||||||
|
|
||||||
result: X::Result,
|
origin_result: X::Result,
|
||||||
dep_node: X::DepNodeIndex,
|
dep_node: X::DepNodeIndex,
|
||||||
|
|
||||||
additional_depth: usize,
|
additional_depth: usize,
|
||||||
encountered_overflow: bool,
|
encountered_overflow: bool,
|
||||||
nested_goals: NestedGoals<X>,
|
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();
|
let entry = self.map.entry(input).or_default();
|
||||||
if encountered_overflow {
|
if encountered_overflow {
|
||||||
let with_overflow = WithOverflow { nested_goals, result };
|
let with_overflow = WithOverflow { nested_goals, result };
|
||||||
let prev = entry.with_overflow.insert(additional_depth, with_overflow);
|
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 {
|
} else {
|
||||||
let prev = entry.success.replace(Success { additional_depth, nested_goals, result });
|
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,
|
mode: SolverMode,
|
||||||
f: impl FnOnce(&mut GlobalCache<Self>) -> R,
|
f: impl FnOnce(&mut GlobalCache<Self>) -> R,
|
||||||
) -> R;
|
) -> R;
|
||||||
|
|
||||||
|
fn evaluation_is_concurrent(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Delegate {
|
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