From 563cd20203fdcd63ede878e70cc65dfca9de422c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicente=20Gusm=C3=A3o?= Date: Mon, 23 Mar 2026 23:16:43 +0000 Subject: [PATCH 1/2] Fix: Diagnostics ICE when replaying proof trees with next-solver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When diagnostics replay proof tree state, rebuilding a canonical state can fail to match the current inference state. With -Znext-solver=globally, this could panic while reporting an error. Make proof tree replay fallible in diagnostics and fall back to the current obligation when replay fails. Add a regression test for the higher-ranked PartialEq and PartialOrd case. Signed-off-by: Vicente Gusmão --- .../src/canonical/mod.rs | 46 +++++++++++++++--- .../src/solve/fulfill/derive_errors.rs | 29 +++++++---- .../src/solve/inspect/analyse.rs | 48 ++++++++++++++++++- .../foreach-partial-eq-next-solver.rs | 14 ++++++ .../foreach-partial-eq-next-solver.stderr | 19 ++++++++ 5 files changed, 140 insertions(+), 16 deletions(-) create mode 100644 tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.rs create mode 100644 tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.stderr diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 4eea0f2c2198d..d97f7619e92ca 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -13,6 +13,7 @@ use std::iter; use canonicalizer::Canonicalizer; use rustc_index::IndexVec; +use rustc_type_ir::error::TypeError; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::{ @@ -246,23 +247,39 @@ where /// from the solver we assume that the solver correctly handled aliases and therefore /// always relate them structurally here. #[instrument(level = "trace", skip(delegate))] -fn unify_query_var_values( +fn try_unify_query_var_values( delegate: &D, param_env: I::ParamEnv, original_values: &[I::GenericArg], var_values: CanonicalVarValues, span: I::Span, -) where +) -> Result<(), TypeError> +where D: SolverDelegate, I: Interner, { assert_eq!(original_values.len(), var_values.len()); for (&orig, response) in iter::zip(original_values, var_values.var_values.iter()) { - let goals = - delegate.eq_structurally_relating_aliases(param_env, orig, response, span).unwrap(); + let goals = delegate.eq_structurally_relating_aliases(param_env, orig, response, span)?; assert!(goals.is_empty()); } + + Ok(()) +} + +#[instrument(level = "trace", skip(delegate))] +fn unify_query_var_values( + delegate: &D, + param_env: I::ParamEnv, + original_values: &[I::GenericArg], + var_values: CanonicalVarValues, + span: I::Span, +) where + D: SolverDelegate, + I: Interner, +{ + try_unify_query_var_values(delegate, param_env, original_values, var_values, span).unwrap(); } fn register_region_constraints( @@ -340,6 +357,23 @@ pub fn instantiate_canonical_state( orig_values: &mut Vec, state: inspect::CanonicalState, ) -> T +where + D: SolverDelegate, + I: Interner, + T: TypeFoldable, +{ + try_instantiate_canonical_state(delegate, span, param_env, orig_values, state).unwrap() +} + +// FIXME: needs to be pub to be accessed by downstream +// `rustc_trait_selection::solve::inspect::analyse`. +pub fn try_instantiate_canonical_state( + delegate: &D, + span: I::Span, + param_env: I::ParamEnv, + orig_values: &mut Vec, + state: inspect::CanonicalState, +) -> Result> where D: SolverDelegate, I: Interner, @@ -358,8 +392,8 @@ where let inspect::State { var_values, data } = delegate.instantiate_canonical(state, instantiation); - unify_query_var_values(delegate, param_env, orig_values, var_values, span); - data + try_unify_query_var_values(delegate, param_env, orig_values, var_values, span)?; + Ok(data) } pub fn response_no_constraints_raw( diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 12dfe730aa303..a0071731b9b1f 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -235,14 +235,20 @@ impl<'tcx> BestObligation<'tcx> { if candidates.len() > 1 { candidates.retain(|candidate| { goal.infcx().probe(|_| { - candidate.instantiate_nested_goals(self.span()).iter().any( - |nested_goal| { - matches!( - nested_goal.source(), - GoalSource::ImplWhereBound - | GoalSource::AliasBoundConstCondition - | GoalSource::AliasWellFormed - ) && nested_goal.result().is_err() + // Replaying proof-tree state is only a diagnostics aid. If the + // canonical state no longer reproduces cleanly in the current + // inference context, keep the candidate rather than changing the + // observable error into an ICE. + candidate.try_instantiate_nested_goals(self.span()).is_none_or( + |nested_goals| { + nested_goals.iter().any(|nested_goal| { + matches!( + nested_goal.source(), + GoalSource::ImplWhereBound + | GoalSource::AliasBoundConstCondition + | GoalSource::AliasWellFormed + ) && nested_goal.result().is_err() + }) }, ) }) @@ -485,7 +491,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { _ => ChildMode::PassThrough, }; - let nested_goals = candidate.instantiate_nested_goals(self.span()); + let Some(nested_goals) = candidate.try_instantiate_nested_goals(self.span()) else { + // We failed to replay this proof-tree candidate in the current inference state. + // Fall back to the current obligation instead of trying to derive a more specific + // nested error from diagnostics-only reconstruction. + return ControlFlow::Break(self.obligation.clone()); + }; // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as // an actual candidate, instead we should treat them as if the impl was never considered to diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index ad66078025bc4..5bcfadb663032 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -18,7 +18,9 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit}; use rustc_middle::{bug, ty}; -use rustc_next_trait_solver::canonical::instantiate_canonical_state; +use rustc_next_trait_solver::canonical::{ + instantiate_canonical_state, try_instantiate_canonical_state, +}; use rustc_next_trait_solver::resolve::eager_resolve_vars; use rustc_next_trait_solver::solve::{MaybeCause, MaybeInfo, SolverDelegateEvalExt as _, inspect}; use rustc_span::Span; @@ -175,6 +177,50 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { .collect() } + /// Like [`Self::instantiate_nested_goals`], but returns `None` if replaying the + /// canonical state no longer matches the caller's inference state. + pub fn try_instantiate_nested_goals(&self, span: Span) -> Option>> { + let infcx = self.goal.infcx; + let param_env = self.goal.goal.param_env; + let mut orig_values = self.goal.orig_values.clone(); + + let mut instantiated_goals = vec![]; + for step in &self.steps { + match **step { + inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( + source, + try_instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal) + .ok()?, + )), + inspect::ProbeStep::RecordImplArgs { .. } => {} + inspect::ProbeStep::MakeCanonicalResponse { .. } + | inspect::ProbeStep::NestedProbe(_) => unreachable!(), + } + } + + let () = try_instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + self.final_state, + ) + .ok()?; + + if let Some(term_hack) = &self.goal.normalizes_to_term_hack { + let _ = term_hack.constrain_and(infcx, span, param_env, |_| {}); + } + + Some( + instantiated_goals + .into_iter() + .map(|(source, goal)| { + self.instantiate_proof_tree_for_nested_goal(source, goal, span) + }) + .collect(), + ) + } + /// Instantiate the args of an impl if this candidate came from a /// `CandidateSource::Impl`. This function modifies the state of the /// `infcx`. diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.rs b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.rs new file mode 100644 index 0000000000000..a48dd465750c6 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Znext-solver=globally + +#![allow(incomplete_features)] +#![feature(non_lifetime_binders)] + +fn auto_trait() +where + for T: PartialEq + PartialOrd, +{} + +fn main() { + auto_trait(); + //~^ ERROR can't compare `T` with `T` +} diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.stderr b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.stderr new file mode 100644 index 0000000000000..dc4dedd75c320 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.stderr @@ -0,0 +1,19 @@ +error[E0277]: can't compare `T` with `T` + --> $DIR/foreach-partial-eq-next-solver.rs:12:5 + | +LL | auto_trait(); + | ^^^^^^^^^^^^ no implementation for `T < T` and `T > T` + | + = help: the trait `PartialOrd` is not implemented for `T` +note: required by a bound in `auto_trait` + --> $DIR/foreach-partial-eq-next-solver.rs:8:27 + | +LL | fn auto_trait() + | ---------- required by a bound in this function +LL | where +LL | for T: PartialEq + PartialOrd, + | ^^^^^^^^^^ required by this bound in `auto_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 2a985eadd4bee2b263d2feac3ffd2d222140de16 Mon Sep 17 00:00:00 2001 From: vicentegusmao Date: Mon, 27 Apr 2026 21:57:32 +0100 Subject: [PATCH 2/2] Instead of falling back in diagnostics, the fix now addresses the actual universe mismatch during proof tree replay. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since my last implementation was not really fixing the problem I removed the functions: try_unify_query_var_values, try_instantiate_canonical_state and InspectCandidate::try_instantiate_nested_goals. I also reverted the diagnostic callers in derive_errors.rs to use instantiate_nested_goals again. For my new implementation, in the rustc_trait_selection I changed fresh_var_for_kind_with_span to fresh_var_for_kind_in_universe which now uses next_region_var_in_universe, next_ty_var_in_universe and next_const_var_in_universe. Also in instantiate_canonical_state it is now ensured that infcx has all the universes up to prev_universe + state.max_universe, and creates any replay-only fresh vars in that explicit universe. I also split out compute_query_response_instantiation_values_in_universe so replay uses that same explicit base universe when reconstructing placeholders from the canonical state. Signed-off-by: Vicente Gusmão --- .../src/canonical/mod.rs | 193 +++++++++++++----- .../rustc_next_trait_solver/src/delegate.rs | 3 +- .../src/solve/delegate.rs | 9 +- .../src/solve/fulfill/derive_errors.rs | 29 +-- .../src/solve/inspect/analyse.rs | 48 +---- 5 files changed, 161 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index d97f7619e92ca..93fe61422968d 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -10,15 +10,15 @@ //! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html use std::iter; +use std::marker::PhantomData; use canonicalizer::Canonicalizer; use rustc_index::IndexVec; -use rustc_type_ir::error::TypeError; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::{ self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, - TypeFoldable, TypingMode, TypingModeEqWrapper, + TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, TypingModeEqWrapper, }; use tracing::instrument; @@ -145,12 +145,29 @@ where // FIXME: Longterm canonical queries should deal with all placeholders // created inside of the query directly instead of returning them to the // caller. - let prev_universe = delegate.universe(); - let universes_created_in_query = response.max_universe.index(); - for _ in 0..universes_created_in_query { - delegate.create_next_universe(); - } + let prev_universe = create_universes_for_response(delegate, response); + compute_query_response_instantiation_values_in_universe( + delegate, + original_values, + response, + span, + prev_universe, + ) +} + +fn compute_query_response_instantiation_values_in_universe( + delegate: &D, + original_values: &[I::GenericArg], + response: &Canonical, + span: I::Span, + prev_universe: ty::UniverseIndex, +) -> CanonicalVarValues +where + D: SolverDelegate, + I: Interner, + T: ResponseT, +{ let var_values = response.value.var_values(); assert_eq!(original_values.len(), var_values.len()); @@ -234,6 +251,109 @@ where }) } +fn create_universes_for_response( + delegate: &D, + response: &Canonical, +) -> ty::UniverseIndex +where + D: SolverDelegate, + I: Interner, +{ + let prev_universe = delegate.universe(); + let universes_created_in_query = response.max_universe.index(); + for _ in 0..universes_created_in_query { + delegate.create_next_universe(); + } + prev_universe +} + +fn max_input_universe_for_replay( + delegate: &D, + orig_values: &[I::GenericArg], +) -> ty::UniverseIndex +where + D: SolverDelegate, + I: Interner, +{ + struct MaxUniverseVisitor<'a, D, I> { + delegate: &'a D, + max_universe: ty::UniverseIndex, + _interner: PhantomData, + } + + impl TypeVisitor for MaxUniverseVisitor<'_, D, I> + where + D: SolverDelegate, + I: Interner, + { + type Result = (); + + fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + match t.kind() { + ty::Placeholder(placeholder) => { + self.max_universe = self.max_universe.max(placeholder.universe()); + } + ty::Infer(ty::TyVar(vid)) => { + if let Some(universe) = self.delegate.universe_of_ty(vid) { + self.max_universe = self.max_universe.max(universe); + } + } + _ => {} + } + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: I::Region) -> Self::Result { + match r.kind() { + ty::RePlaceholder(placeholder) => { + self.max_universe = self.max_universe.max(placeholder.universe()); + } + ty::ReVar(vid) => { + if let Some(universe) = self.delegate.universe_of_lt(vid) { + self.max_universe = self.max_universe.max(universe); + } + } + _ => {} + } + } + + fn visit_const(&mut self, c: I::Const) -> Self::Result { + match c.kind() { + ty::ConstKind::Placeholder(placeholder) => { + self.max_universe = self.max_universe.max(placeholder.universe()); + } + ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { + if let Some(universe) = self.delegate.universe_of_ct(vid) { + self.max_universe = self.max_universe.max(universe); + } + } + _ => {} + } + c.super_visit_with(self) + } + } + + let mut visitor = MaxUniverseVisitor { + delegate, + max_universe: ty::UniverseIndex::ROOT, + _interner: PhantomData, + }; + for value in orig_values { + value.visit_with(&mut visitor); + } + visitor.max_universe +} + +fn ensure_universes_through(delegate: &D, max_universe: ty::UniverseIndex) +where + D: SolverDelegate, + I: Interner, +{ + while delegate.universe() < max_universe { + delegate.create_next_universe(); + } +} + /// Unify the `original_values` with the `var_values` returned by the canonical query.. /// /// This assumes that this unification will always succeed. This is the case when @@ -247,39 +367,23 @@ where /// from the solver we assume that the solver correctly handled aliases and therefore /// always relate them structurally here. #[instrument(level = "trace", skip(delegate))] -fn try_unify_query_var_values( +fn unify_query_var_values( delegate: &D, param_env: I::ParamEnv, original_values: &[I::GenericArg], var_values: CanonicalVarValues, span: I::Span, -) -> Result<(), TypeError> -where +) where D: SolverDelegate, I: Interner, { assert_eq!(original_values.len(), var_values.len()); for (&orig, response) in iter::zip(original_values, var_values.var_values.iter()) { - let goals = delegate.eq_structurally_relating_aliases(param_env, orig, response, span)?; + let goals = + delegate.eq_structurally_relating_aliases(param_env, orig, response, span).unwrap(); assert!(goals.is_empty()); } - - Ok(()) -} - -#[instrument(level = "trace", skip(delegate))] -fn unify_query_var_values( - delegate: &D, - param_env: I::ParamEnv, - original_values: &[I::GenericArg], - var_values: CanonicalVarValues, - span: I::Span, -) where - D: SolverDelegate, - I: Interner, -{ - try_unify_query_var_values(delegate, param_env, original_values, var_values, span).unwrap(); } fn register_region_constraints( @@ -357,23 +461,6 @@ pub fn instantiate_canonical_state( orig_values: &mut Vec, state: inspect::CanonicalState, ) -> T -where - D: SolverDelegate, - I: Interner, - T: TypeFoldable, -{ - try_instantiate_canonical_state(delegate, span, param_env, orig_values, state).unwrap() -} - -// FIXME: needs to be pub to be accessed by downstream -// `rustc_trait_selection::solve::inspect::analyse`. -pub fn try_instantiate_canonical_state( - delegate: &D, - span: I::Span, - param_env: I::ParamEnv, - orig_values: &mut Vec, - state: inspect::CanonicalState, -) -> Result> where D: SolverDelegate, I: Interner, @@ -381,19 +468,27 @@ where { // In case any fresh inference variables have been created between `state` // and the previous instantiation, extend `orig_values` for it. + let prev_universe = max_input_universe_for_replay(delegate, orig_values); + let max_universe = prev_universe + state.max_universe.index(); + ensure_universes_through(delegate, max_universe); orig_values.extend( state.value.var_values.var_values.as_slice()[orig_values.len()..] .iter() - .map(|&arg| delegate.fresh_var_for_kind_with_span(arg, span)), + .map(|&arg| delegate.fresh_var_for_kind_in_universe(arg, span, max_universe)), ); - let instantiation = - compute_query_response_instantiation_values(delegate, orig_values, &state, span); + let instantiation = compute_query_response_instantiation_values_in_universe( + delegate, + orig_values, + &state, + span, + prev_universe, + ); let inspect::State { var_values, data } = delegate.instantiate_canonical(state, instantiation); - try_unify_query_var_values(delegate, param_env, orig_values, var_values, span)?; - Ok(data) + unify_query_var_values(delegate, param_env, orig_values, var_values, span); + data } pub fn response_no_constraints_raw( diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 8fd7d6d0471c7..c899933895b21 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -25,10 +25,11 @@ pub trait SolverDelegate: Deref + Sized { span: ::Span, ) -> Option; - fn fresh_var_for_kind_with_span( + fn fresh_var_for_kind_in_universe( &self, arg: ::GenericArg, span: ::Span, + universe: ty::UniverseIndex, ) -> ::GenericArg; // FIXME: Uplift the leak check into this crate. diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 15762652da141..63341c9d85f1c 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -166,17 +166,18 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< } } - fn fresh_var_for_kind_with_span( + fn fresh_var_for_kind_in_universe( &self, arg: ty::GenericArg<'tcx>, span: Span, + universe: ty::UniverseIndex, ) -> ty::GenericArg<'tcx> { match arg.kind() { ty::GenericArgKind::Lifetime(_) => { - self.next_region_var(RegionVariableOrigin::Misc(span)).into() + self.next_region_var_in_universe(RegionVariableOrigin::Misc(span), universe).into() } - ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(), - ty::GenericArgKind::Const(_) => self.next_const_var(span).into(), + ty::GenericArgKind::Type(_) => self.next_ty_var_in_universe(span, universe).into(), + ty::GenericArgKind::Const(_) => self.next_const_var_in_universe(span, universe).into(), } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index a0071731b9b1f..12dfe730aa303 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -235,20 +235,14 @@ impl<'tcx> BestObligation<'tcx> { if candidates.len() > 1 { candidates.retain(|candidate| { goal.infcx().probe(|_| { - // Replaying proof-tree state is only a diagnostics aid. If the - // canonical state no longer reproduces cleanly in the current - // inference context, keep the candidate rather than changing the - // observable error into an ICE. - candidate.try_instantiate_nested_goals(self.span()).is_none_or( - |nested_goals| { - nested_goals.iter().any(|nested_goal| { - matches!( - nested_goal.source(), - GoalSource::ImplWhereBound - | GoalSource::AliasBoundConstCondition - | GoalSource::AliasWellFormed - ) && nested_goal.result().is_err() - }) + candidate.instantiate_nested_goals(self.span()).iter().any( + |nested_goal| { + matches!( + nested_goal.source(), + GoalSource::ImplWhereBound + | GoalSource::AliasBoundConstCondition + | GoalSource::AliasWellFormed + ) && nested_goal.result().is_err() }, ) }) @@ -491,12 +485,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { _ => ChildMode::PassThrough, }; - let Some(nested_goals) = candidate.try_instantiate_nested_goals(self.span()) else { - // We failed to replay this proof-tree candidate in the current inference state. - // Fall back to the current obligation instead of trying to derive a more specific - // nested error from diagnostics-only reconstruction. - return ControlFlow::Break(self.obligation.clone()); - }; + let nested_goals = candidate.instantiate_nested_goals(self.span()); // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as // an actual candidate, instead we should treat them as if the impl was never considered to diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 5bcfadb663032..ad66078025bc4 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -18,9 +18,7 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit}; use rustc_middle::{bug, ty}; -use rustc_next_trait_solver::canonical::{ - instantiate_canonical_state, try_instantiate_canonical_state, -}; +use rustc_next_trait_solver::canonical::instantiate_canonical_state; use rustc_next_trait_solver::resolve::eager_resolve_vars; use rustc_next_trait_solver::solve::{MaybeCause, MaybeInfo, SolverDelegateEvalExt as _, inspect}; use rustc_span::Span; @@ -177,50 +175,6 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { .collect() } - /// Like [`Self::instantiate_nested_goals`], but returns `None` if replaying the - /// canonical state no longer matches the caller's inference state. - pub fn try_instantiate_nested_goals(&self, span: Span) -> Option>> { - let infcx = self.goal.infcx; - let param_env = self.goal.goal.param_env; - let mut orig_values = self.goal.orig_values.clone(); - - let mut instantiated_goals = vec![]; - for step in &self.steps { - match **step { - inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( - source, - try_instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal) - .ok()?, - )), - inspect::ProbeStep::RecordImplArgs { .. } => {} - inspect::ProbeStep::MakeCanonicalResponse { .. } - | inspect::ProbeStep::NestedProbe(_) => unreachable!(), - } - } - - let () = try_instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - self.final_state, - ) - .ok()?; - - if let Some(term_hack) = &self.goal.normalizes_to_term_hack { - let _ = term_hack.constrain_and(infcx, span, param_env, |_| {}); - } - - Some( - instantiated_goals - .into_iter() - .map(|(source, goal)| { - self.instantiate_proof_tree_for_nested_goal(source, goal, span) - }) - .collect(), - ) - } - /// Instantiate the args of an impl if this candidate came from a /// `CandidateSource::Impl`. This function modifies the state of the /// `infcx`.