diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 841169ac78d7d..d55aebf1a2696 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,6 +1,5 @@ //! Code shared by trait and projection goals for candidate assembly. -use super::infcx_ext::InferCtxtExt; #[cfg(doc)] use super::trait_goals::structural_traits::*; use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; @@ -206,7 +205,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, G>, ) -> Vec> { - debug_assert_eq!(goal, self.infcx.resolve_vars_if_possible(goal)); + debug_assert_eq!(goal, self.resolve_vars_if_possible(goal)); // HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule, // object bound, alias bound, etc. We are unable to determine this until we can at @@ -250,8 +249,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else { return }; - self.infcx.probe(|_| { - let normalized_ty = self.infcx.next_ty_infer(); + self.probe(|this| { + let normalized_ty = this.next_ty_infer(); let normalizes_to_goal = goal.with( tcx, ty::Binder::dummy(ty::ProjectionPredicate { @@ -259,16 +258,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { term: normalized_ty.into(), }), ); - let normalization_certainty = match self.evaluate_goal(normalizes_to_goal) { + let normalization_certainty = match this.evaluate_goal(normalizes_to_goal) { Ok((_, certainty)) => certainty, Err(NoSolution) => return, }; - let normalized_ty = self.infcx.resolve_vars_if_possible(normalized_ty); + let normalized_ty = this.resolve_vars_if_possible(normalized_ty); // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. // This doesn't work as long as we use `CandidateSource` in winnowing. let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - let normalized_candidates = self.assemble_and_evaluate_candidates(goal); + let normalized_candidates = this.assemble_and_evaluate_candidates(goal); for mut normalized_candidate in normalized_candidates { normalized_candidate.result = normalized_candidate.result.unchecked_map(|mut response| { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs new file mode 100644 index 0000000000000..67addd732d0ad --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -0,0 +1,172 @@ +use rustc_hir::def_id::DefId; +use rustc_infer::infer::at::ToTrace; +use rustc_infer::infer::canonical::CanonicalVarValues; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; +use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::ObligationCause; +use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::ty::{self, ir::TypeVisitor, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable}; +use rustc_span::DUMMY_SP; +use std::ops::ControlFlow; + +use super::search_graph::SearchGraph; +use super::Goal; + +pub struct EvalCtxt<'a, 'tcx> { + // FIXME: should be private. + pub(super) infcx: &'a InferCtxt<'tcx>, + + pub(super) var_values: CanonicalVarValues<'tcx>, + + pub(super) search_graph: &'a mut SearchGraph<'tcx>, + + /// This field is used by a debug assertion in [`EvalCtxt::evaluate_goal`], + /// see the comment in that method for more details. + pub in_projection_eq_hack: bool, +} + +impl<'tcx> EvalCtxt<'_, 'tcx> { + pub(super) fn probe(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T { + self.infcx.probe(|_| f(self)) + } + + pub(super) fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + pub(super) fn next_ty_infer(&self) -> Ty<'tcx> { + self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: DUMMY_SP, + }) + } + + pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> { + self.infcx.next_const_var( + ty, + ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span: DUMMY_SP }, + ) + } + + /// Is the projection predicate is of the form `exists ::Assoc = T`. + /// + /// This is the case if the `term` is an inference variable in the innermost universe + /// and does not occur in any other part of the predicate. + pub(super) fn term_is_fully_unconstrained( + &self, + goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>, + ) -> bool { + let term_is_infer = match goal.predicate.term.unpack() { + ty::TermKind::Ty(ty) => { + 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(), + } + } else { + false + } + } + ty::TermKind::Const(ct) => { + 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(), + } + } else { + false + } + } + }; + + // Guard against `>::Assoc = ?0>`. + struct ContainsTerm<'tcx> { + term: ty::Term<'tcx>, + } + impl<'tcx> TypeVisitor> for ContainsTerm<'tcx> { + type BreakTy = (); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + if t.needs_infer() { + if ty::Term::from(t) == self.term { + ControlFlow::Break(()) + } else { + t.super_visit_with(self) + } + } else { + ControlFlow::Continue(()) + } + } + + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { + if c.needs_infer() { + if ty::Term::from(c) == self.term { + ControlFlow::Break(()) + } else { + c.super_visit_with(self) + } + } else { + ControlFlow::Continue(()) + } + } + } + + let mut visitor = ContainsTerm { term: goal.predicate.term }; + + term_is_infer + && goal.predicate.projection_ty.visit_with(&mut visitor).is_continue() + && goal.param_env.visit_with(&mut visitor).is_continue() + } + + #[instrument(level = "debug", skip(self, param_env), ret)] + pub(super) fn eq>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution> { + self.infcx + .at(&ObligationCause::dummy(), param_env) + .eq(lhs, rhs) + .map(|InferOk { value: (), obligations }| { + obligations.into_iter().map(|o| o.into()).collect() + }) + .map_err(|e| { + debug!(?e, "failed to equate"); + NoSolution + }) + } + + pub(super) fn instantiate_binder_with_infer + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T { + self.infcx.instantiate_binder_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::HigherRankedType, + value, + ) + } + + pub(super) fn instantiate_binder_with_placeholders + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T { + self.infcx.instantiate_binder_with_placeholders(value) + } + + pub(super) fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + self.infcx.resolve_vars_if_possible(value) + } + + pub(super) fn fresh_substs_for_item(&self, def_id: DefId) -> ty::SubstsRef<'tcx> { + self.infcx.fresh_substs_for_item(DUMMY_SP, def_id) + } + + pub(super) fn universe(&self) -> ty::UniverseIndex { + self.infcx.universe() + } +} diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs deleted file mode 100644 index 06570e1f4b41c..0000000000000 --- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs +++ /dev/null @@ -1,77 +0,0 @@ -use rustc_infer::infer::at::ToTrace; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; -use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::ObligationCause; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::ty::{self, Ty, TypeFoldable}; -use rustc_span::DUMMY_SP; - -use super::Goal; - -/// Methods used inside of the canonical queries of the solver. -/// -/// Most notably these do not care about diagnostics information. -/// If you find this while looking for methods to use outside of the -/// solver, you may look at the implementation of these method for -/// help. -pub(super) trait InferCtxtExt<'tcx> { - fn next_ty_infer(&self) -> Ty<'tcx>; - fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx>; - - fn eq>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result>>, NoSolution>; - - fn instantiate_binder_with_infer + Copy>( - &self, - value: ty::Binder<'tcx, T>, - ) -> T; -} - -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { - fn next_ty_infer(&self) -> Ty<'tcx> { - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: DUMMY_SP, - }) - } - fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> { - self.next_const_var( - ty, - ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span: DUMMY_SP }, - ) - } - - #[instrument(level = "debug", skip(self, param_env), ret)] - fn eq>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env) - .eq(lhs, rhs) - .map(|InferOk { value: (), obligations }| { - obligations.into_iter().map(|o| o.into()).collect() - }) - .map_err(|e| { - debug!(?e, "failed to equate"); - NoSolution - }) - } - - fn instantiate_binder_with_infer + Copy>( - &self, - value: ty::Binder<'tcx, T>, - ) -> T { - self.instantiate_binder_with_fresh_vars( - DUMMY_SP, - LateBoundRegionConversionTime::HigherRankedType, - value, - ) - } -} diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 6890811fd046e..c080f7e59fa22 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -35,16 +35,15 @@ use crate::solve::search_graph::OverflowHandler; use crate::traits::ObligationCause; mod assembly; +mod eval_ctxt; mod fulfill; -mod infcx_ext; mod project_goals; mod search_graph; mod trait_goals; +pub use eval_ctxt::EvalCtxt; pub use fulfill::FulfillmentCtxt; -use self::infcx_ext::InferCtxtExt; - /// A goal is a statement, i.e. `predicate`, we want to prove /// given some assumptions, i.e. `param_env`. /// @@ -180,22 +179,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { } } -struct EvalCtxt<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, - var_values: CanonicalVarValues<'tcx>, - - search_graph: &'a mut search_graph::SearchGraph<'tcx>, - - /// This field is used by a debug assertion in [`EvalCtxt::evaluate_goal`], - /// see the comment in that method for more details. - in_projection_eq_hack: bool, -} - impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - /// The entry point of the solver. /// /// This function deals with (coinductive) cycles, overflow, and caching @@ -427,7 +411,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| { debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other); - let r = ecx.infcx.probe(|_| { + let r = ecx.probe(|ecx| { let (_, certainty) = ecx.evaluate_goal(goal.with( tcx, ty::Binder::dummy(ty::ProjectionPredicate { @@ -462,10 +446,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // Evaluate all 3 potential candidates for the alias' being equal candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1)); candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0)); - candidates.push(self.infcx.probe(|_| { + candidates.push(self.probe(|this| { debug!("compute_alias_eq_goal: alias defids are equal, equating substs"); - let nested_goals = self.infcx.eq(goal.param_env, alias_lhs, alias_rhs)?; - self.evaluate_all_and_make_canonical_response(nested_goals) + let nested_goals = this.eq(goal.param_env, alias_lhs, alias_rhs)?; + this.evaluate_all_and_make_canonical_response(nested_goals) })); debug!(?candidates); @@ -481,7 +465,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>, ) -> QueryResult<'tcx> { let (ct, ty) = goal.predicate; - let nested_goals = self.infcx.eq(goal.param_env, ct.ty(), ty)?; + let nested_goals = self.eq(goal.param_env, ct.ty(), ty)?; self.evaluate_all_and_make_canonical_response(nested_goals) } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 48153b465b7ec..9f83bfa1ccb9b 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -1,7 +1,6 @@ use crate::traits::{specialization_graph, translate_substs}; use super::assembly; -use super::infcx_ext::InferCtxtExt; use super::trait_goals::structural_traits; use super::{Certainty, EvalCtxt, Goal, QueryResult}; use rustc_errors::ErrorGuaranteed; @@ -13,12 +12,11 @@ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::ProjectionPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{ir::TypeVisitor, ProjectionPredicate, TypeSuperVisitable}; use rustc_middle::ty::{ToPredicate, TypeVisitable}; use rustc_span::{sym, DUMMY_SP}; use std::iter; -use std::ops::ControlFlow; impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn compute_projection_goal( @@ -38,8 +36,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } else { let predicate = goal.predicate; let unconstrained_rhs = match predicate.term.unpack() { - ty::TermKind::Ty(_) => self.infcx.next_ty_infer().into(), - ty::TermKind::Const(ct) => self.infcx.next_const_infer(ct.ty()).into(), + ty::TermKind::Ty(_) => self.next_ty_infer().into(), + ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(), }; let unconstrained_predicate = ty::Clause::Projection(ProjectionPredicate { projection_ty: goal.predicate.projection_ty, @@ -49,8 +47,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { this.evaluate_goal(goal.with(this.tcx(), unconstrained_predicate)) })?; - let nested_eq_goals = - self.infcx.eq(goal.param_env, unconstrained_rhs, predicate.term)?; + let nested_eq_goals = self.eq(goal.param_env, unconstrained_rhs, predicate.term)?; let eval_certainty = self.evaluate_all(nested_eq_goals)?; self.make_canonical_response(normalize_certainty.unify_and(eval_certainty)) } @@ -65,73 +62,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { result } - /// Is the projection predicate is of the form `exists ::Assoc = T`. - /// - /// This is the case if the `term` is an inference variable in the innermost universe - /// and does not occur in any other part of the predicate. - fn term_is_fully_unconstrained(&self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>) -> bool { - let infcx = self.infcx; - let term_is_infer = match goal.predicate.term.unpack() { - ty::TermKind::Ty(ty) => { - if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { - match infcx.probe_ty_var(vid) { - Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"), - Err(universe) => universe == infcx.universe(), - } - } else { - false - } - } - ty::TermKind::Const(ct) => { - 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 == infcx.universe(), - } - } else { - false - } - } - }; - - // Guard against `>::Assoc = ?0>`. - struct ContainsTerm<'tcx> { - term: ty::Term<'tcx>, - } - impl<'tcx> TypeVisitor> for ContainsTerm<'tcx> { - type BreakTy = (); - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if t.needs_infer() { - if ty::Term::from(t) == self.term { - ControlFlow::Break(()) - } else { - t.super_visit_with(self) - } - } else { - ControlFlow::Continue(()) - } - } - - fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { - if c.needs_infer() { - if ty::Term::from(c) == self.term { - ControlFlow::Break(()) - } else { - c.super_visit_with(self) - } - } else { - ControlFlow::Continue(()) - } - } - } - - let mut visitor = ContainsTerm { term: goal.predicate.term }; - - term_is_infer - && goal.predicate.projection_ty.visit_with(&mut visitor).is_continue() - && goal.param_env.visit_with(&mut visitor).is_continue() - } - /// After normalizing the projection to `normalized_alias` with the given /// `normalization_certainty`, constrain the inference variable `term` to it /// and return a query response. @@ -145,7 +75,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // // It can however be ambiguous when the `normalized_alias` contains a projection. let nested_goals = self - .infcx .eq(goal.param_env, goal.predicate.term, normalized_alias.into()) .expect("failed to unify with unconstrained term"); let rhs_certainty = @@ -177,10 +106,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() && poly_projection_pred.projection_def_id() == goal.predicate.def_id() { - ecx.infcx.probe(|_| { + ecx.probe(|ecx| { let assumption_projection_pred = - ecx.infcx.instantiate_binder_with_infer(poly_projection_pred); - let mut nested_goals = ecx.infcx.eq( + ecx.instantiate_binder_with_infer(poly_projection_pred); + let mut nested_goals = ecx.eq( goal.param_env, goal.predicate.projection_ty, assumption_projection_pred.projection_ty, @@ -215,11 +144,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { return Err(NoSolution); } - ecx.infcx.probe(|_| { - let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); + ecx.probe(|ecx| { + let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let mut nested_goals = ecx.infcx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; + let mut nested_goals = ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx .predicates_of(impl_def_id) .instantiate(tcx, impl_substs) @@ -367,7 +296,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - ecx.infcx.probe(|_| { + ecx.probe(|ecx| { let metadata_ty = match goal.predicate.self_ty().kind() { ty::Bool | ty::Char @@ -546,8 +475,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { let discriminant = goal.predicate.self_ty().discriminant_ty(ecx.tcx()); - ecx.infcx - .probe(|_| ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, discriminant)) + ecx.probe(|ecx| ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, discriminant)) } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index f2f25ef850a9a..6d1381bbf0c9f 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -3,11 +3,9 @@ use std::iter; use super::assembly; -use super::infcx_ext::InferCtxtExt; use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult}; 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::util::supertraits; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; @@ -45,12 +43,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - ecx.infcx.probe(|_| { - let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); + ecx.probe(|ecx| { + let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); let mut nested_goals = - ecx.infcx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; + ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx .predicates_of(impl_def_id) .instantiate(tcx, impl_substs) @@ -72,10 +70,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { && poly_trait_pred.def_id() == goal.predicate.def_id() { // FIXME: Constness and polarity - ecx.infcx.probe(|_| { + ecx.probe(|ecx| { let assumption_trait_pred = - ecx.infcx.instantiate_binder_with_infer(poly_trait_pred); - let mut nested_goals = ecx.infcx.eq( + ecx.instantiate_binder_with_infer(poly_trait_pred); + let mut nested_goals = ecx.eq( goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref, @@ -118,7 +116,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - ecx.infcx.probe(|_| { + ecx.probe(|ecx| { let nested_obligations = tcx .predicates_of(goal.predicate.def_id()) .instantiate(tcx, goal.predicate.trait_ref.substs); @@ -275,7 +273,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { if b_ty.is_ty_var() { return ecx.make_canonical_response(Certainty::AMBIGUOUS); } - ecx.infcx.probe(|_| { + ecx.probe(|ecx| { match (a_ty.kind(), b_ty.kind()) { // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b` (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => { @@ -318,7 +316,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // `[T; n]` -> `[T]` unsizing (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { // We just require that the element type stays the same - let nested_goals = ecx.infcx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; + let nested_goals = ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; ecx.evaluate_all_and_make_canonical_response(nested_goals) } // Struct unsizing `Struct` -> `Struct` where `T: Unsize` @@ -352,7 +350,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Finally, we require that `TailA: Unsize` for the tail field // types. - let mut nested_goals = ecx.infcx.eq(goal.param_env, unsized_a_ty, b_ty)?; + let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; nested_goals.push(goal.with( tcx, ty::Binder::dummy( @@ -371,7 +369,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Substitute just the tail field of B., and require that they're equal. let unsized_a_ty = tcx.mk_tup(a_rest_tys.iter().chain([b_last_ty]).copied()); - let mut nested_goals = ecx.infcx.eq(goal.param_env, unsized_a_ty, b_ty)?; + let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; // Similar to ADTs, require that the rest of the fields are equal. nested_goals.push(goal.with( @@ -411,7 +409,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } let mut unsize_dyn_to_principal = |principal: Option>| { - ecx.infcx.probe(|_| -> Result<_, NoSolution> { + ecx.probe(|ecx| -> Result<_, NoSolution> { // Require that all of the trait predicates from A match B, except for // the auto traits. We do this by constructing a new A type with B's // auto traits, and equating these types. @@ -431,7 +429,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn); // We also require that A's lifetime outlives B's lifetime. - let mut nested_obligations = ecx.infcx.eq(goal.param_env, new_a_ty, b_ty)?; + let mut nested_obligations = ecx.eq(goal.param_env, new_a_ty, b_ty)?; nested_obligations.push( goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region))), ); @@ -482,16 +480,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { fn probe_and_evaluate_goal_for_constituent_tys( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, - constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result>, NoSolution>, + constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result>, NoSolution>, ) -> QueryResult<'tcx> { - self.infcx.probe(|_| { - self.evaluate_all_and_make_canonical_response( - constituent_tys(self.infcx, goal.predicate.self_ty())? + self.probe(|this| { + this.evaluate_all_and_make_canonical_response( + constituent_tys(this, goal.predicate.self_ty())? .into_iter() .map(|ty| { goal.with( - self.tcx(), - ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)), + this.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(this.tcx(), ty)), ) }) .collect(), diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index 3662463178f85..2c13465d347c4 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -1,16 +1,18 @@ use rustc_hir::{Movability, Mutability}; -use rustc_infer::{infer::InferCtxt, traits::query::NoSolution}; +use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::{self, Ty, TyCtxt}; +use crate::solve::EvalCtxt; + // Calculates the constituent types of a type for `auto trait` purposes. // // For types with an "existential" binder, i.e. generator witnesses, we also // instantiate the binder with placeholders eagerly. pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( - infcx: &InferCtxt<'tcx>, + ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, ) -> Result>, NoSolution> { - let tcx = infcx.tcx; + let tcx = ecx.tcx(); match *ty.kind() { ty::Uint(_) | ty::Int(_) @@ -53,9 +55,7 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()]) } - ty::GeneratorWitness(types) => { - Ok(infcx.instantiate_binder_with_placeholders(types).to_vec()) - } + ty::GeneratorWitness(types) => Ok(ecx.instantiate_binder_with_placeholders(types).to_vec()), ty::GeneratorWitnessMIR(..) => todo!(), @@ -74,7 +74,7 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( } pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( - infcx: &InferCtxt<'tcx>, + ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, ) -> Result>, NoSolution> { match *ty.kind() { @@ -113,18 +113,18 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ty::Tuple(tys) => Ok(tys.to_vec()), ty::Adt(def, substs) => { - let sized_crit = def.sized_constraint(infcx.tcx); + let sized_crit = def.sized_constraint(ecx.tcx()); Ok(sized_crit .0 .iter() - .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs)) + .map(|ty| sized_crit.rebind(*ty).subst(ecx.tcx(), substs)) .collect()) } } } pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( - infcx: &InferCtxt<'tcx>, + ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, ) -> Result>, NoSolution> { match *ty.kind() { @@ -165,7 +165,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), ty::Generator(_, substs, Movability::Movable) => { - if infcx.tcx.features().generator_clone { + if ecx.tcx().features().generator_clone { let generator = substs.as_generator(); Ok(vec![generator.tupled_upvars_ty(), generator.witness()]) } else { @@ -173,9 +173,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( } } - ty::GeneratorWitness(types) => { - Ok(infcx.instantiate_binder_with_placeholders(types).to_vec()) - } + ty::GeneratorWitness(types) => Ok(ecx.instantiate_binder_with_placeholders(types).to_vec()), ty::GeneratorWitnessMIR(..) => todo!(), }