diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 109c8476ccb16..ea45d50969909 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -99,19 +99,23 @@ where response_no_constraints(cx, input, Certainty::overflow(false)) } - fn is_ambiguous_result(result: QueryResult) -> bool { - result.is_ok_and(|response| { - has_no_inference_or_external_constraints(response) + fn is_ambiguous_result(result: QueryResult) -> Option { + result.ok().and_then(|response| { + if has_no_inference_or_external_constraints(response) && matches!(response.value.certainty, Certainty::Maybe { .. }) + { + Some(response.value.certainty) + } else { + None + } }) } fn propagate_ambiguity( cx: I, for_input: CanonicalInput, - from_result: QueryResult, + certainty: Certainty, ) -> QueryResult { - let certainty = from_result.unwrap().value.certainty; response_no_constraints(cx, for_input, certainty) } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 886d1a78bcbfd..322be31f4cb10 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -11,7 +11,7 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; use crate::relate::Relate; -use crate::solve::{CanonicalInput, ExternalConstraintsData, QueryResult, inspect}; +use crate::solve::{CanonicalInput, Certainty, ExternalConstraintsData, QueryResult, inspect}; use crate::visit::{Flags, TypeVisitable}; use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph}; @@ -548,6 +548,7 @@ impl CollectAndApply for Result { impl search_graph::Cx for I { type Input = CanonicalInput; type Result = QueryResult; + type AmbiguityInfo = Certainty; type DepNodeIndex = I::DepNodeIndex; type Tracked = I::Tracked; diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 7aa58d096d5c0..ad8b643d976c7 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -40,6 +40,7 @@ pub use global_cache::GlobalCache; pub trait Cx: Copy { type Input: Debug + Eq + Hash + Copy; type Result: Debug + Eq + Hash + Copy; + type AmbiguityInfo: Debug + Eq + Hash + Copy; type DepNodeIndex; type Tracked: Debug; @@ -96,11 +97,13 @@ pub trait Delegate: Sized { input: ::Input, ) -> ::Result; - fn is_ambiguous_result(result: ::Result) -> bool; + fn is_ambiguous_result( + result: ::Result, + ) -> Option<::AmbiguityInfo>; fn propagate_ambiguity( cx: Self::Cx, for_input: ::Input, - from_result: ::Result, + ambiguity_info: ::AmbiguityInfo, ) -> ::Result; fn compute_goal( @@ -913,9 +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. -enum RebaseReason { +enum RebaseReason { NoCycleUsages, - Ambiguity, + Ambiguity(X::AmbiguityInfo), Overflow, /// We've actually reached a fixpoint. /// @@ -951,7 +954,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)] @@ -969,10 +972,6 @@ impl, X: Cx> SearchGraph { return true; }; - let Some(new_highest_head_index) = heads.opt_highest_cycle_head_index() else { - return false; - }; - // We're rebasing an entry `e` over a head `p`. This head // has a number of own heads `h` it depends on. // @@ -1033,8 +1032,8 @@ 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 => { - *result = D::propagate_ambiguity(cx, input, *result); + RebaseReason::Ambiguity(info) => { + *result = D::propagate_ambiguity(cx, input, info); } RebaseReason::Overflow => *result = D::fixpoint_overflow_result(cx, input), RebaseReason::ReachedFixpoint(None) => {} @@ -1046,6 +1045,10 @@ impl, X: Cx> SearchGraph { }; } + let Some(new_highest_head_index) = heads.opt_highest_cycle_head_index() else { + return false; + }; + // We now care about the path from the next highest cycle head to the // provisional cache entry. *path_from_head = path_from_head.extend(Self::cycle_path_kind( @@ -1268,6 +1271,7 @@ impl, X: Cx> SearchGraph { } /// Whether we've reached a fixpoint when evaluating a cycle head. + #[instrument(level = "trace", skip(self, stack_entry), ret)] fn reached_fixpoint( &mut self, stack_entry: &StackEntry, @@ -1355,8 +1359,12 @@ impl, X: Cx> SearchGraph { // 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 D::is_ambiguous_result(result) { - self.rebase_provisional_cache_entries(cx, &stack_entry, RebaseReason::Ambiguity); + 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); }; diff --git a/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.rs b/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.rs new file mode 100644 index 0000000000000..aa5893d621cdb --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.rs @@ -0,0 +1,44 @@ +//@ compile-flags: -Znext-solver +#![feature(rustc_attrs)] +#![rustc_no_implicit_bounds] + +// A regression test making sure that when forcing dependent +// provisional cache entries to ambiguous, we use the `MaybeCause` +// of the cycle head. We ended up trying to use the current result +// of the provisional cache entry, which is incorrect and caused an +// ICE when trying to unwrap it. + +struct Root(T); +struct Head(T); +struct Error(T); +struct NotImplemented(T); + +#[rustc_coinductive] +trait Trait {} +impl Trait for Root +where + Head: Trait, +{} + +impl Trait for Head +where + Root: Trait, + T: Trait, // ambiguous +{} + +impl Trait for Head +where + Error: Trait, + NotImplemented: Trait, +{} + +impl Trait for Error +where + Head: Trait, + NotImplemented: Trait, +{} + +fn impls_trait() {} +fn main() { + impls_trait::>() //~ ERROR type annotations needed +} diff --git a/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.stderr b/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.stderr new file mode 100644 index 0000000000000..dd4049a66d0b4 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.stderr @@ -0,0 +1,27 @@ +error[E0283]: type annotations needed + --> $DIR/forced_ambiguity-use-head-maybe-cause.rs:43:19 + | +LL | impls_trait::>() + | ^^^^^^^ cannot infer type for struct `Head<_>` + | + = note: cannot satisfy `Head<_>: Trait` + = help: the trait `Trait` is implemented for `Head` +note: required for `Root<_>` to implement `Trait` + --> $DIR/forced_ambiguity-use-head-maybe-cause.rs:18:9 + | +LL | impl Trait for Root + | ^^^^^ ^^^^^^^ +LL | where +LL | Head: Trait, + | ----- unsatisfied trait bound introduced here + = note: 8 redundant requirements hidden + = note: required for `Root<_>` to implement `Trait` +note: required by a bound in `impls_trait` + --> $DIR/forced_ambiguity-use-head-maybe-cause.rs:41:19 + | +LL | fn impls_trait() {} + | ^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`.