diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 8e6376b22ce61..7c58cd7303ebc 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -916,10 +916,9 @@ impl, X: Cx> SearchGraph { /// heads from the stack. This may not necessarily mean that we've actually /// reached a fixpoint for that cycle head, which impacts the way we rebase /// provisional cache entries. -#[derive_where(Debug; X: Cx)] -enum RebaseReason { +#[derive(Debug)] +enum RebaseReason { NoCycleUsages, - Ambiguity(X::AmbiguityInfo), Overflow, /// We've actually reached a fixpoint. /// @@ -956,7 +955,7 @@ impl, X: Cx> SearchGraph { &mut self, cx: X, stack_entry: &StackEntry, - rebase_reason: RebaseReason, + rebase_reason: RebaseReason, ) { let popped_head_index = self.stack.next_index(); #[allow(rustc::potential_query_instability)] @@ -1035,9 +1034,6 @@ impl, X: Cx> SearchGraph { // is not actually equal to the final provisional result. We // need to discard the provisional cache entry in this case. RebaseReason::NoCycleUsages => return false, - RebaseReason::Ambiguity(info) => { - *result = D::propagate_ambiguity(cx, input, info); - } RebaseReason::Overflow => *result = D::fixpoint_overflow_result(cx, input), RebaseReason::ReachedFixpoint(None) => {} RebaseReason::ReachedFixpoint(Some(path_kind)) => { @@ -1352,27 +1348,6 @@ impl, X: Cx> SearchGraph { return EvaluationResult::finalize(stack_entry, encountered_overflow, result); } - // If computing this goal results in ambiguity with no constraints, - // we do not rerun it. It's incredibly difficult to get a different - // response in the next iteration in this case. These changes would - // likely either be caused by incompleteness or can change the maybe - // cause from ambiguity to overflow. Returning ambiguity always - // preserves soundness and completeness even if the goal is be known - // to succeed or fail. - // - // This prevents exponential blowup affecting multiple major crates. - // As we only get to this branch if we haven't yet reached a fixpoint, - // we also taint all provisional cache entries which depend on the - // current goal. - if let Some(info) = D::is_ambiguous_result(result) { - self.rebase_provisional_cache_entries( - cx, - &stack_entry, - RebaseReason::Ambiguity(info), - ); - return EvaluationResult::finalize(stack_entry, encountered_overflow, result); - }; - // If we've reached the fixpoint step limit, we bail with overflow and taint all // provisional cache entries which depend on the current goal. i += 1; diff --git a/tests/ui/traits/next-solver/global-where-bound-normalization.rs b/tests/ui/traits/next-solver/global-where-bound-normalization.rs new file mode 100644 index 0000000000000..e57fbf378a0d2 --- /dev/null +++ b/tests/ui/traits/next-solver/global-where-bound-normalization.rs @@ -0,0 +1,45 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +// Regression test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/257. + +#![feature(rustc_attrs)] +#![expect(internal_features)] +#![rustc_no_implicit_bounds] + +pub trait Bound {} +impl Bound for u8 {} + +pub trait Proj { + type Assoc; +} +impl Proj for U { + type Assoc = U; +} +impl Proj for MyField { + type Assoc = u8; +} + +// While wf-checking the global bounds of `fn foo`, elaborating this outlives predicate triggered a +// cycle in the search graph along a particular probe path, which was not an actual solution. +// That cycle then resulted in a forced false-positive ambiguity due to a performance hack in the +// search graph and then ended up floundering the root goal evaluation. +pub trait Field: Proj {} + +struct MyField; +impl Field for MyField {} + +trait IdReqField { + type This; +} +impl IdReqField for F { + type This = F; +} + +fn foo() +where + ::This: Field, +{ +} + +fn main() {}