diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index a300558c0c9ce..654ca4e78d744 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -8,14 +8,13 @@ use std::ops::ControlFlow; use derive_where::derive_where; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::solve::SizedTraitKind; +use rustc_type_ir::solve::{SizedTraitKind, TraitGoalProvenVia}; use rustc_type_ir::{ self as ty, Interner, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _, TypeVisitor, TypingMode, Upcast as _, elaborate, }; use tracing::{debug, instrument}; -use super::trait_goals::TraitGoalProvenVia; use super::{has_only_region_constraints, inspect}; use crate::delegate::SolverDelegate; use crate::solve::inspect::ProbeKind; diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 1690c908d123b..d50a5deb92943 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -5,7 +5,6 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::SizedTraitKind; -use rustc_type_ir::solve::inspect::ProbeKind; use rustc_type_ir::{self as ty, Interner, elaborate}; use tracing::instrument; @@ -394,11 +393,8 @@ where &mut self, goal: Goal>, ) -> QueryResult { - let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { - let trait_goal: Goal> = - goal.with(ecx.cx(), goal.predicate.trait_ref); - ecx.compute_trait_goal(trait_goal) - })?; + let trait_goal = goal.with(self.cx(), goal.predicate.trait_ref); + let proven_via = self.trait_goal_proven_via(trait_goal)?; self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution)) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index cb7c498b94e2a..b367b3845787e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -15,6 +15,7 @@ use rustc_index::IndexVec; use rustc_type_ir::data_structures::HashSet; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::solver_relating::RelateExt; +use rustc_type_ir::solve::TraitGoalProvenVia; use rustc_type_ir::{ self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, }; @@ -178,6 +179,7 @@ where var_values, certainty, external_constraints: self.cx().mk_external_constraints(external_constraints), + trait_goal_proven_via: None, }, ); @@ -278,7 +280,7 @@ where param_env: I::ParamEnv, original_values: &[I::GenericArg], response: CanonicalResponse, - ) -> (NestedNormalizationGoals, Certainty) { + ) -> (NestedNormalizationGoals, Option, Certainty) { let instantiation = Self::compute_query_response_instantiation_values( self.delegate, &original_values, @@ -286,7 +288,7 @@ where self.origin_span, ); - let Response { var_values, external_constraints, certainty } = + let Response { var_values, external_constraints, certainty, trait_goal_proven_via } = self.delegate.instantiate_canonical(response, instantiation); Self::unify_query_var_values( @@ -306,7 +308,7 @@ where self.register_region_constraints(region_constraints); self.register_new_opaque_types(opaque_types); - (normalization_nested_goals.clone(), certainty) + (normalization_nested_goals.clone(), trait_goal_proven_via, certainty) } /// This returns the canonical variable values to instantiate the bound variables of diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 00fd3ba80465e..bb8bf40e43b95 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -9,6 +9,7 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::search_graph::PathKind; +use rustc_type_ir::solve::TraitGoalProvenVia; use rustc_type_ir::{ self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -233,6 +234,7 @@ where I::Span::dummy(), |ecx| { ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on) + .map(|(n, _, r)| (n, r)) }, ) } @@ -460,12 +462,27 @@ where goal: Goal, stalled_on: Option>, ) -> Result, NoSolution> { - let (normalization_nested_goals, goal_evaluation) = + let (normalization_nested_goals, _, goal_evaluation) = self.evaluate_goal_raw(goal_evaluation_kind, source, goal, stalled_on)?; assert!(normalization_nested_goals.is_empty()); Ok(goal_evaluation) } + pub(super) fn trait_goal_proven_via( + &mut self, + goal: Goal, + ) -> Result, NoSolution> { + let (_, canonical_goal) = self.canonicalize_goal(goal); + let canonical_response = EvalCtxt::evaluate_canonical_goal( + self.cx(), + self.search_graph, + canonical_goal, + self.step_kind_for_source(GoalSource::Misc), + &mut ProofTreeBuilder::new_noop(), + ); + canonical_response.map(|r| r.value.trait_goal_proven_via) + } + /// Recursively evaluates `goal`, returning the nested goals in case /// the nested goal is a `NormalizesTo` goal. /// @@ -479,7 +496,10 @@ where source: GoalSource, goal: Goal, stalled_on: Option>, - ) -> Result<(NestedNormalizationGoals, GoalEvaluation), NoSolution> { + ) -> Result< + (NestedNormalizationGoals, Option, GoalEvaluation), + NoSolution, + > { // If we have run this goal before, and it was stalled, check that any of the goal's // args have changed. Otherwise, we don't need to re-run the goal because it'll remain // stalled, since it'll canonicalize the same way and evaluation is pure. @@ -492,6 +512,7 @@ where { return Ok(( NestedNormalizationGoals::empty(), + None, GoalEvaluation { certainty: Certainty::Maybe(stalled_on.stalled_cause), has_changed: HasChanged::No, @@ -522,7 +543,7 @@ where let has_changed = if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No }; - let (normalization_nested_goals, certainty) = + let (normalization_nested_goals, trait_goal_proven_via, certainty) = self.instantiate_and_apply_query_response(goal.param_env, &orig_values, response); self.inspect.goal_evaluation(goal_evaluation); @@ -582,7 +603,11 @@ where }, }; - Ok((normalization_nested_goals, GoalEvaluation { certainty, has_changed, stalled_on })) + Ok(( + normalization_nested_goals, + trait_goal_proven_via, + GoalEvaluation { certainty, has_changed, stalled_on }, + )) } fn compute_goal(&mut self, goal: Goal) -> QueryResult { @@ -591,7 +616,7 @@ where if let Some(kind) = kind.no_bound_vars() { match kind { ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { - self.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r) + self.compute_trait_goal(Goal { param_env, predicate }) } ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => { self.compute_host_effect_goal(Goal { param_env, predicate }) @@ -715,6 +740,7 @@ where let ( NestedNormalizationGoals(nested_goals), + _proven_via, GoalEvaluation { certainty, stalled_on, has_changed: _ }, ) = self.evaluate_goal_raw( GoalEvaluationKind::Nested, diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index f22b275bc44a2..f7c55cbe386d3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -246,7 +246,7 @@ impl, I: Interner> ProofTreeBuilder { ProofTreeBuilder::new(DebugSolver::Root) } - fn new_noop() -> ProofTreeBuilder { + pub(crate) fn new_noop() -> ProofTreeBuilder { ProofTreeBuilder { state: None, _infcx: PhantomData } } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index e4e0aba7b5022..4332d1914d3b5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -363,6 +363,8 @@ fn response_no_constraints_raw( variables, value: Response { var_values: ty::CanonicalVarValues::make_identity(cx, variables), + // Cycles start out without knowing how the trait goal was proven. + trait_goal_proven_via: None, // FIXME: maybe we should store the "no response" version in cx, like // we do for cx.types and stuff. external_constraints: cx.mk_external_constraints(ExternalConstraintsData::default()), diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index d51c87fe68e60..9bb36acec7e23 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -34,11 +34,8 @@ where match goal.predicate.alias.kind(cx) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { let trait_ref = goal.predicate.alias.trait_ref(cx); - let (_, proven_via) = - self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { - let trait_goal: Goal> = goal.with(cx, trait_ref); - ecx.compute_trait_goal(trait_goal) - })?; + let trait_goal = goal.with(cx, trait_ref); + let proven_via = self.trait_goal_proven_via(trait_goal)?; self.assemble_and_merge_candidates(proven_via, goal, |ecx| { ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| { this.structurally_instantiate_normalizes_to_term( diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 8ee116b090dc8..18e6606d294b0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -4,7 +4,7 @@ use rustc_type_ir::data_structures::IndexSet; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind}; +use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind, TraitGoalProvenVia}; use rustc_type_ir::{ self as ty, Interner, Movability, TraitPredicate, TraitRef, TypeVisitableExt as _, TypingMode, Upcast as _, elaborate, @@ -1278,28 +1278,6 @@ where } } -/// How we've proven this trait goal. -/// -/// This is used by `NormalizesTo` goals to only normalize -/// by using the same 'kind of candidate' we've used to prove -/// its corresponding trait goal. Most notably, we do not -/// normalize by using an impl if the trait goal has been -/// proven via a `ParamEnv` candidate. -/// -/// This is necessary to avoid unnecessary region constraints, -/// see trait-system-refactor-initiative#125 for more details. -#[derive(Debug, Clone, Copy)] -pub(super) enum TraitGoalProvenVia { - /// We've proven the trait goal by something which is - /// is not a non-global where-bound or an alias-bound. - /// - /// This means we don't disable any candidates during - /// normalization. - Misc, - ParamEnv, - AliasBound, -} - impl EvalCtxt<'_, D> where D: SolverDelegate, @@ -1433,9 +1411,12 @@ where pub(super) fn compute_trait_goal( &mut self, goal: Goal>, - ) -> Result<(CanonicalResponse, Option), NoSolution> { + ) -> Result, NoSolution> { let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); - self.merge_trait_candidates(candidates) + self.merge_trait_candidates(candidates).map(|(mut r, proven_via)| { + r.value.trait_goal_proven_via = proven_via; + r + }) } fn try_stall_coroutine_witness( diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index bbbeaa29f84aa..61b40292eb6f6 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -225,6 +225,32 @@ pub struct Response { pub var_values: CanonicalVarValues, /// Additional constraints returned by this query. pub external_constraints: I::ExternalConstraints, + #[type_foldable(identity)] + #[type_visitable(ignore)] + pub trait_goal_proven_via: Option, +} + +/// How we've proven this trait goal. +/// +/// This is used by `NormalizesTo` goals to only normalize +/// by using the same 'kind of candidate' we've used to prove +/// its corresponding trait goal. Most notably, we do not +/// normalize by using an impl if the trait goal has been +/// proven via a `ParamEnv` candidate. +/// +/// This is necessary to avoid unnecessary region constraints, +/// see trait-system-refactor-initiative#125 for more details. +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub enum TraitGoalProvenVia { + /// We've proven the trait goal by something which is + /// is not a non-global where-bound or an alias-bound. + /// + /// This means we don't disable any candidates during + /// normalization. + Misc, + ParamEnv, + AliasBound, } /// Additional constraints returned on success.