about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-03-23 05:40:50 +0000
committerMichael Goulet <michael@errs.io>2023-03-24 16:00:27 +0000
commit7f89c7c32dcee0e01bb1eda00fbdb77a9ab5e281 (patch)
tree9ad9a6d93f5965dc3e1bc96b4f4603c939b815d9
parentf421586eed77de266a3f99ffa8a5687b7d2d893c (diff)
downloadrust-7f89c7c32dcee0e01bb1eda00fbdb77a9ab5e281.tar.gz
rust-7f89c7c32dcee0e01bb1eda00fbdb77a9ab5e281.zip
Make EvalCtxt's infcx private
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonical/mod.rs57
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs112
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs24
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs16
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 efecaf33ef9..d393ab1ba4a 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<ty::GenericArg<'tcx>>, 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<ExternalConstraints<'tcx>, 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 &region_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 e47b5ae21b5..92aff517fbb 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<impl Iterator<Item = Goal<'tcx, ty::Predicate<'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<ExternalConstraints<'tcx>, 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<T: TypeFoldable<TyCtxt<'tcx>>>(
+        &self,
+        canonicalize_mode: CanonicalizeMode,
+        variables: &mut Vec<ty::GenericArg<'tcx>>,
+        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 6a64dfdedd4..7c01d5d2bef 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 525b3105538..4c61a2cb2cc 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<Option<LeafDef>, 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");