From 7f89c7c32dcee0e01bb1eda00fbdb77a9ab5e281 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 23 Mar 2023 05:40:50 +0000 Subject: [PATCH 1/2] Make EvalCtxt's infcx private --- .../src/solve/canonical/mod.rs | 57 ++------- .../src/solve/eval_ctxt.rs | 112 +++++++++++++++++- .../rustc_trait_selection/src/solve/mod.rs | 24 ++-- .../src/solve/project_goals.rs | 16 ++- 4 files changed, 134 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs index efecaf33ef987..d393ab1ba4a85 100644 --- a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs @@ -8,17 +8,15 @@ /// section of the [rustc-dev-guide][c]. /// /// [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html -use self::canonicalize::{CanonicalizeMode, Canonicalizer}; +pub use self::canonicalize::{CanonicalizeMode, Canonicalizer}; + use super::{CanonicalGoal, Certainty, EvalCtxt, Goal}; -use super::{CanonicalResponse, ExternalConstraints, QueryResult, Response}; -use rustc_infer::infer::canonical::query_response::make_query_region_constraints; +use super::{CanonicalResponse, QueryResult, Response}; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::ExternalConstraintsData; -use rustc_infer::traits::ObligationCause; use rustc_middle::ty::{self, GenericArgKind}; -use rustc_span::DUMMY_SP; use std::iter; use std::ops::Deref; @@ -32,12 +30,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> (Vec>, CanonicalGoal<'tcx>) { let mut orig_values = Default::default(); - let canonical_goal = Canonicalizer::canonicalize( - self.infcx, - CanonicalizeMode::Input, - &mut orig_values, - goal, - ); + let canonical_goal = self.canonicalize(CanonicalizeMode::Input, &mut orig_values, goal); (orig_values, canonical_goal) } @@ -58,8 +51,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let external_constraints = self.compute_external_query_constraints()?; let response = Response { var_values: self.var_values, external_constraints, certainty }; - let canonical = Canonicalizer::canonicalize( - self.infcx, + let canonical = self.canonicalize( CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, &mut Default::default(), response, @@ -67,26 +59,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok(canonical) } - #[instrument(level = "debug", skip(self), ret)] - fn compute_external_query_constraints(&self) -> Result, NoSolution> { - // Cannot use `take_registered_region_obligations` as we may compute the response - // inside of a `probe` whenever we have multiple choices inside of the solver. - let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); - let region_constraints = self.infcx.with_region_constraints(|region_constraints| { - make_query_region_constraints( - self.tcx(), - region_obligations - .iter() - .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), - region_constraints, - ) - }); - let opaque_types = self.infcx.clone_opaque_types_for_query_response(); - Ok(self - .tcx() - .mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types })) - } - /// After calling a canonical query, we apply the constraints returned /// by the query using this function. /// @@ -126,10 +98,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // 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 = self.infcx.universe(); + let prev_universe = self.universe(); let universes_created_in_query = response.max_universe.index() + 1; for _ in 0..universes_created_in_query { - self.infcx.create_next_universe(); + self.create_next_universe(); } let var_values = response.value.var_values; @@ -172,7 +144,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all (see the FIXME at the start of this method), we have to deal with // them for now. - self.infcx.instantiate_canonical_var(DUMMY_SP, info, |idx| { + self.instantiate_canonical_var(info, |idx| { ty::UniverseIndex::from(prev_universe.index() + idx.index()) }) } else if info.is_existential() { @@ -186,7 +158,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if let Some(v) = opt_values[index] { v } else { - self.infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe) + self.instantiate_canonical_var(info, |_| prev_universe) } } else { // For placeholders which were already part of the input, we simply map this @@ -219,15 +191,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) { for &(ty::OutlivesPredicate(lhs, rhs), _) in ®ion_constraints.outlives { match lhs.unpack() { - GenericArgKind::Lifetime(lhs) => self.infcx.region_outlives_predicate( - &ObligationCause::dummy(), - ty::Binder::dummy(ty::OutlivesPredicate(lhs, rhs)), - ), - GenericArgKind::Type(lhs) => self.infcx.register_region_obligation_with_cause( - lhs, - rhs, - &ObligationCause::dummy(), - ), + GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs), + GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs), GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"), } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index e47b5ae21b5af..92aff517fbb8b 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -1,14 +1,17 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; -use rustc_infer::infer::canonical::CanonicalVarValues; +use rustc_infer::infer::canonical::query_response::make_query_region_constraints; +use rustc_infer::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarValues}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt, }; use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult}; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::traits::solve::{ + CanonicalGoal, Certainty, ExternalConstraints, ExternalConstraintsData, MaybeCause, QueryResult, +}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -16,13 +19,31 @@ use rustc_middle::ty::{ use rustc_span::DUMMY_SP; use std::ops::ControlFlow; +use crate::traits::specialization_graph; + +use super::canonical::{CanonicalizeMode, Canonicalizer}; use super::search_graph::{self, OverflowHandler}; use super::SolverMode; use super::{search_graph::SearchGraph, Goal}; pub struct EvalCtxt<'a, 'tcx> { - // FIXME: should be private. - pub(super) infcx: &'a InferCtxt<'tcx>, + /// The inference context that backs (mostly) inference and placeholder terms + /// instantiated while solving goals. + /// + /// NOTE: The `InferCtxt` that backs the `EvalCtxt` is intentionally private, + /// because the `InferCtxt` is much more general than `EvalCtxt`. Methods such + /// as `take_registered_region_obligations` can mess up query responses, + /// using `At::normalize` is totally wrong, calling `evaluate_root_goal` can + /// cause coinductive unsoundness, etc. + /// + /// Methods that are generally of use for trait solving are *intentionally* + /// re-declared through the `EvalCtxt` below, often with cleaner signatures + /// since we don't care about things like `ObligationCause`s and `Span`s here. + /// If some `InferCtxt` method is missing, please first think defensively about + /// the method's compatibility with this solver, or if an existing one does + /// the job already. + infcx: &'a InferCtxt<'tcx>, + pub(super) var_values: CanonicalVarValues<'tcx>, /// The highest universe index nameable by the caller. /// @@ -548,4 +569,87 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn universe(&self) -> ty::UniverseIndex { self.infcx.universe() } + + pub(super) fn create_next_universe(&self) -> ty::UniverseIndex { + self.infcx.create_next_universe() + } + + pub(super) fn instantiate_canonical_var( + &self, + cv_info: CanonicalVarInfo<'tcx>, + universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, + ) -> ty::GenericArg<'tcx> { + self.infcx.instantiate_canonical_var(DUMMY_SP, cv_info, universe_map) + } + + pub(super) fn translate_substs( + &self, + param_env: ty::ParamEnv<'tcx>, + source_impl: DefId, + source_substs: ty::SubstsRef<'tcx>, + target_node: specialization_graph::Node, + ) -> ty::SubstsRef<'tcx> { + crate::traits::translate_substs( + self.infcx, + param_env, + source_impl, + source_substs, + target_node, + ) + } + + pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) { + self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy()); + } + + pub(super) fn register_region_outlives(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) { + // `b : a` ==> `a <= b` + // (inlined from `InferCtxt::region_outlives_predicate`) + self.infcx.sub_regions( + rustc_infer::infer::SubregionOrigin::RelateRegionParamBound(DUMMY_SP), + b, + a, + ); + } + + /// Computes the list of goals required for `arg` to be well-formed + pub(super) fn well_formed_goals( + &self, + param_env: ty::ParamEnv<'tcx>, + arg: ty::GenericArg<'tcx>, + ) -> Option>>> { + crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg) + .map(|obligations| obligations.into_iter().map(|obligation| obligation.into())) + } + + #[instrument(level = "debug", skip(self), ret)] + pub(super) fn compute_external_query_constraints( + &self, + ) -> Result, NoSolution> { + // Cannot use `take_registered_region_obligations` as we may compute the response + // inside of a `probe` whenever we have multiple choices inside of the solver. + let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); + let region_constraints = self.infcx.with_region_constraints(|region_constraints| { + make_query_region_constraints( + self.tcx(), + region_obligations + .iter() + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), + region_constraints, + ) + }); + let opaque_types = self.infcx.clone_opaque_types_for_query_response(); + Ok(self + .tcx() + .mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types })) + } + + pub(super) fn canonicalize>>( + &self, + canonicalize_mode: CanonicalizeMode, + variables: &mut Vec>, + value: T, + ) -> Canonical<'tcx, T> { + Canonicalizer::canonicalize(self.infcx, canonicalize_mode, variables, value) + } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 6a64dfdedd42f..7c01d5d2bef92 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -15,16 +15,14 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::traits::query::NoSolution; use rustc_middle::traits::solve::{ - CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData, - Goal, QueryResult, Response, + CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult, + Response, }; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate, }; -use crate::traits::ObligationCause; - mod assembly; mod canonical; mod eval_ctxt; @@ -68,7 +66,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, ) -> QueryResult<'tcx> { let ty::OutlivesPredicate(ty, lt) = goal.predicate; - self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy()); + self.register_ty_outlives(ty, lt); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } @@ -77,10 +75,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { &mut self, goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, ) -> QueryResult<'tcx> { - self.infcx.region_outlives_predicate( - &ObligationCause::dummy(), - ty::Binder::dummy(goal.predicate), - ); + let ty::OutlivesPredicate(a, b) = goal.predicate; + self.register_region_outlives(a, b); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } @@ -146,13 +142,9 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { &mut self, goal: Goal<'tcx, ty::GenericArg<'tcx>>, ) -> QueryResult<'tcx> { - match crate::traits::wf::unnormalized_obligations( - self.infcx, - goal.param_env, - goal.predicate, - ) { - Some(obligations) => { - self.add_goals(obligations.into_iter().map(|o| o.into())); + match self.well_formed_goals(goal.param_env, goal.predicate) { + Some(goals) => { + self.add_goals(goals); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } None => self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS), diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 525b3105538d0..4c61a2cb2cc78 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -1,4 +1,4 @@ -use crate::traits::{specialization_graph, translate_substs}; +use crate::traits::specialization_graph; use super::assembly; use super::trait_goals::structural_traits; @@ -7,7 +7,6 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; -use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; @@ -168,7 +167,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { // return ambiguity this would otherwise be incomplete, resulting in // unsoundness during coherence (#105782). let Some(assoc_def) = fetch_eligible_assoc_item_def( - ecx.infcx, + ecx, goal.param_env, goal_trait_ref, goal.predicate.def_id(), @@ -199,8 +198,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal_trait_ref.def_id, impl_substs, ); - let substs = translate_substs( - ecx.infcx, + let substs = ecx.translate_substs( goal.param_env, impl_def_id, impl_substs_with_gat, @@ -500,15 +498,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { /// /// FIXME: We should merge these 3 implementations as it's likely that they otherwise /// diverge. -#[instrument(level = "debug", skip(infcx, param_env), ret)] +#[instrument(level = "debug", skip(ecx, param_env), ret)] fn fetch_eligible_assoc_item_def<'tcx>( - infcx: &InferCtxt<'tcx>, + ecx: &EvalCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, goal_trait_ref: ty::TraitRef<'tcx>, trait_assoc_def_id: DefId, impl_def_id: DefId, ) -> Result, NoSolution> { - let node_item = specialization_graph::assoc_def(infcx.tcx, impl_def_id, trait_assoc_def_id) + let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id) .map_err(|ErrorGuaranteed { .. }| NoSolution)?; let eligible = if node_item.is_final() { @@ -520,7 +518,7 @@ fn fetch_eligible_assoc_item_def<'tcx>( // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. if param_env.reveal() == Reveal::All { - let poly_trait_ref = infcx.resolve_vars_if_possible(goal_trait_ref); + let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref); !poly_trait_ref.still_further_specializable() } else { debug!(?node_item.item.def_id, "not eligible due to default"); From a61616a016aadb41cb18cc898f1ce9ff70709607 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 24 Mar 2023 17:27:06 +0000 Subject: [PATCH 2/2] Move canonicalization code around --- .../src/solve/{canonical => }/canonicalize.rs | 0 .../src/solve/eval_ctxt.rs | 61 ++----------------- .../mod.rs => eval_ctxt/canonical.rs} | 53 +++++++++++----- .../rustc_trait_selection/src/solve/mod.rs | 5 +- 4 files changed, 47 insertions(+), 72 deletions(-) rename compiler/rustc_trait_selection/src/solve/{canonical => }/canonicalize.rs (100%) rename compiler/rustc_trait_selection/src/solve/{canonical/mod.rs => eval_ctxt/canonical.rs} (81%) diff --git a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs similarity index 100% rename from compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs rename to compiler/rustc_trait_selection/src/solve/canonicalize.rs diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 92aff517fbb8b..e64b4a7656f25 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -1,7 +1,6 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; -use rustc_infer::infer::canonical::query_response::make_query_region_constraints; -use rustc_infer::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarValues}; +use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt, @@ -9,9 +8,7 @@ use rustc_infer::infer::{ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::traits::solve::{ - CanonicalGoal, Certainty, ExternalConstraints, ExternalConstraintsData, MaybeCause, QueryResult, -}; +use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -21,11 +18,12 @@ use std::ops::ControlFlow; use crate::traits::specialization_graph; -use super::canonical::{CanonicalizeMode, Canonicalizer}; use super::search_graph::{self, OverflowHandler}; use super::SolverMode; use super::{search_graph::SearchGraph, Goal}; +mod canonical; + pub struct EvalCtxt<'a, 'tcx> { /// The inference context that backs (mostly) inference and placeholder terms /// instantiated while solving goals. @@ -414,7 +412,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { match self.infcx.probe_ty_var(vid) { Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"), - Err(universe) => universe == self.universe(), + Err(universe) => universe == self.infcx.universe(), } } else { false @@ -424,7 +422,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { match self.infcx.probe_const_var(vid) { Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"), - Err(universe) => universe == self.universe(), + Err(universe) => universe == self.infcx.universe(), } } else { false @@ -566,22 +564,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.infcx.fresh_substs_for_item(DUMMY_SP, def_id) } - pub(super) fn universe(&self) -> ty::UniverseIndex { - self.infcx.universe() - } - - pub(super) fn create_next_universe(&self) -> ty::UniverseIndex { - self.infcx.create_next_universe() - } - - pub(super) fn instantiate_canonical_var( - &self, - cv_info: CanonicalVarInfo<'tcx>, - universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, - ) -> ty::GenericArg<'tcx> { - self.infcx.instantiate_canonical_var(DUMMY_SP, cv_info, universe_map) - } - pub(super) fn translate_substs( &self, param_env: ty::ParamEnv<'tcx>, @@ -621,35 +603,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg) .map(|obligations| obligations.into_iter().map(|obligation| obligation.into())) } - - #[instrument(level = "debug", skip(self), ret)] - pub(super) fn compute_external_query_constraints( - &self, - ) -> Result, NoSolution> { - // Cannot use `take_registered_region_obligations` as we may compute the response - // inside of a `probe` whenever we have multiple choices inside of the solver. - let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); - let region_constraints = self.infcx.with_region_constraints(|region_constraints| { - make_query_region_constraints( - self.tcx(), - region_obligations - .iter() - .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), - region_constraints, - ) - }); - let opaque_types = self.infcx.clone_opaque_types_for_query_response(); - Ok(self - .tcx() - .mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types })) - } - - pub(super) fn canonicalize>>( - &self, - canonicalize_mode: CanonicalizeMode, - variables: &mut Vec>, - value: T, - ) -> Canonical<'tcx, T> { - Canonicalizer::canonicalize(self.infcx, canonicalize_mode, variables, value) - } } diff --git a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs similarity index 81% rename from compiler/rustc_trait_selection/src/solve/canonical/mod.rs rename to compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index d393ab1ba4a85..ee90488730a64 100644 --- a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -8,20 +8,19 @@ /// section of the [rustc-dev-guide][c]. /// /// [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html -pub use self::canonicalize::{CanonicalizeMode, Canonicalizer}; - use super::{CanonicalGoal, Certainty, EvalCtxt, Goal}; -use super::{CanonicalResponse, QueryResult, Response}; +use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer}; +use crate::solve::{CanonicalResponse, QueryResult, Response}; +use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; -use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::solve::ExternalConstraintsData; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData}; use rustc_middle::ty::{self, GenericArgKind}; +use rustc_span::DUMMY_SP; use std::iter; use std::ops::Deref; -mod canonicalize; - impl<'tcx> EvalCtxt<'_, 'tcx> { /// Canonicalizes the goal remembering the original values /// for each bound variable. @@ -30,7 +29,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> (Vec>, CanonicalGoal<'tcx>) { let mut orig_values = Default::default(); - let canonical_goal = self.canonicalize(CanonicalizeMode::Input, &mut orig_values, goal); + let canonical_goal = Canonicalizer::canonicalize( + self.infcx, + CanonicalizeMode::Input, + &mut orig_values, + goal, + ); (orig_values, canonical_goal) } @@ -41,7 +45,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// - `external_constraints`: additional constraints which aren't expressable /// using simple unification of inference variables. #[instrument(level = "debug", skip(self))] - pub(super) fn evaluate_added_goals_and_make_canonical_response( + pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( &mut self, certainty: Certainty, ) -> QueryResult<'tcx> { @@ -51,7 +55,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let external_constraints = self.compute_external_query_constraints()?; let response = Response { var_values: self.var_values, external_constraints, certainty }; - let canonical = self.canonicalize( + let canonical = Canonicalizer::canonicalize( + self.infcx, CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, &mut Default::default(), response, @@ -59,6 +64,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok(canonical) } + #[instrument(level = "debug", skip(self), ret)] + fn compute_external_query_constraints(&self) -> Result, NoSolution> { + // Cannot use `take_registered_region_obligations` as we may compute the response + // inside of a `probe` whenever we have multiple choices inside of the solver. + let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); + let region_constraints = self.infcx.with_region_constraints(|region_constraints| { + make_query_region_constraints( + self.tcx(), + region_obligations + .iter() + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), + region_constraints, + ) + }); + let opaque_types = self.infcx.clone_opaque_types_for_query_response(); + Ok(self + .tcx() + .mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types })) + } + /// After calling a canonical query, we apply the constraints returned /// by the query using this function. /// @@ -98,10 +123,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // 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 = self.universe(); + let prev_universe = self.infcx.universe(); let universes_created_in_query = response.max_universe.index() + 1; for _ in 0..universes_created_in_query { - self.create_next_universe(); + self.infcx.create_next_universe(); } let var_values = response.value.var_values; @@ -144,7 +169,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all (see the FIXME at the start of this method), we have to deal with // them for now. - self.instantiate_canonical_var(info, |idx| { + self.infcx.instantiate_canonical_var(DUMMY_SP, info, |idx| { ty::UniverseIndex::from(prev_universe.index() + idx.index()) }) } else if info.is_existential() { @@ -158,7 +183,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if let Some(v) = opt_values[index] { v } else { - self.instantiate_canonical_var(info, |_| prev_universe) + self.infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe) } } else { // For placeholders which were already part of the input, we simply map this diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 7c01d5d2bef92..1925043e5fdcc 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -15,8 +15,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::traits::query::NoSolution; use rustc_middle::traits::solve::{ - CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult, - Response, + CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult, Response, }; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ @@ -24,7 +23,7 @@ use rustc_middle::ty::{ }; mod assembly; -mod canonical; +mod canonicalize; mod eval_ctxt; mod fulfill; mod project_goals;