about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-05-01 17:22:39 -0400
committerMichael Goulet <michael@errs.io>2024-05-02 22:03:01 -0400
commitd9eb5232b6fea1d902650727f71b4c1bbf69079a (patch)
tree7edb973179d60878b6327434b90d065fd3b29df3 /compiler/rustc_trait_selection
parent79734f1db8dbe322192dea32c0f6b80ab14c4c1d (diff)
downloadrust-d9eb5232b6fea1d902650727f71b4c1bbf69079a.tar.gz
rust-d9eb5232b6fea1d902650727f71b4c1bbf69079a.zip
Use ObligationCtxt in favor of TraitEngine in many places
Diffstat (limited to 'compiler/rustc_trait_selection')
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs79
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs32
5 files changed, 99 insertions, 71 deletions
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index b2400cec42f..3dc55509dad 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -1,8 +1,9 @@
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::{self, ObligationCtxt, SelectionContext, TraitEngineExt as _};
+use crate::traits::{self, ObligationCtxt, SelectionContext};
+
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
-use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt as _};
+use rustc_infer::traits::Obligation;
 use rustc_macros::extension;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
@@ -93,9 +94,9 @@ impl<'tcx> InferCtxt<'tcx> {
                 ty::TraitRef::new(self.tcx, trait_def_id, [ty]),
             )) {
                 Ok(Some(selection)) => {
-                    let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self);
-                    fulfill_cx.register_predicate_obligations(self, selection.nested_obligations());
-                    Some(fulfill_cx.select_all_or_error(self))
+                    let ocx = ObligationCtxt::new(self);
+                    ocx.register_obligations(selection.nested_obligations());
+                    Some(ocx.select_all_or_error())
                 }
                 Ok(None) | Err(_) => None,
             }
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index 7c6dd4d3feb..97de25295b8 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -14,7 +14,6 @@ use rustc_ast_ir::visit::VisitorResult;
 use rustc_infer::infer::resolve::EagerResolver;
 use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
-use rustc_infer::traits::{TraitEngine, TraitEngineExt};
 use rustc_macros::extension;
 use rustc_middle::infer::unify_key::ConstVariableOrigin;
 use rustc_middle::traits::query::NoSolution;
@@ -26,9 +25,9 @@ use rustc_middle::ty::TypeFoldable;
 use rustc_span::{Span, DUMMY_SP};
 
 use crate::solve::eval_ctxt::canonical;
-use crate::solve::FulfillmentCtxt;
 use crate::solve::{EvalCtxt, GoalEvaluationKind, GoalSource};
 use crate::solve::{GenerateProofTree, InferCtxtEvalExt};
+use crate::traits::ObligationCtxt;
 
 pub struct InspectConfig {
     pub max_depth: usize,
@@ -74,14 +73,13 @@ impl<'tcx> NormalizesToTermHack<'tcx> {
             .eq(DefineOpaqueTypes::Yes, self.term, self.unconstrained_term)
             .map_err(|_| NoSolution)
             .and_then(|InferOk { value: (), obligations }| {
-                let mut fulfill_cx = FulfillmentCtxt::new(infcx);
-                fulfill_cx.register_predicate_obligations(infcx, obligations);
-                if fulfill_cx.select_where_possible(infcx).is_empty() {
-                    if fulfill_cx.pending_obligations().is_empty() {
-                        Ok(Certainty::Yes)
-                    } else {
-                        Ok(Certainty::AMBIGUOUS)
-                    }
+                let ocx = ObligationCtxt::new(infcx);
+                ocx.register_obligations(obligations);
+                let errors = ocx.select_all_or_error();
+                if errors.is_empty() {
+                    Ok(Certainty::Yes)
+                } else if errors.iter().all(|e| !e.is_true_error()) {
+                    Ok(Certainty::AMBIGUOUS)
                 } else {
                     Err(NoSolution)
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 86e7c42376a..59725ce9de0 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -6,12 +6,9 @@
 
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::InferOk;
-use crate::regions::InferCtxtRegionExt;
 use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
-use crate::solve::{deeply_normalize_for_diagnostics, inspect, FulfillmentCtxt};
-use crate::traits::engine::TraitEngineExt as _;
+use crate::solve::{deeply_normalize_for_diagnostics, inspect};
 use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::structural_normalize::StructurallyNormalizeExt;
 use crate::traits::NormalizeExt;
 use crate::traits::SkipLeakCheck;
 use crate::traits::{
@@ -22,7 +19,7 @@ use rustc_errors::{Diag, EmissionGuarantee};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::{util, FulfillmentErrorCode, TraitEngine, TraitEngineExt};
+use rustc_infer::traits::{util, FulfillmentErrorCode};
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
 use rustc_middle::traits::specialization_graph::OverlapMode;
@@ -35,6 +32,7 @@ use std::fmt::Debug;
 use std::ops::ControlFlow;
 
 use super::error_reporting::suggest_new_overflow_limit;
+use super::ObligationCtxt;
 
 /// Whether we do the orphan check relative to this crate or to some remote crate.
 #[derive(Copy, Clone, Debug)]
@@ -361,23 +359,27 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
     let infcx = selcx.infcx;
 
     if infcx.next_trait_solver() {
-        let mut fulfill_cx = FulfillmentCtxt::new(infcx);
-        fulfill_cx.register_predicate_obligations(infcx, obligations.iter().cloned());
-
+        let ocx = ObligationCtxt::new(infcx);
+        ocx.register_obligations(obligations.iter().cloned());
+        let errors_and_ambiguities = ocx.select_all_or_error();
         // We only care about the obligations that are *definitely* true errors.
         // Ambiguities do not prove the disjointness of two impls.
-        let errors = fulfill_cx.select_where_possible(infcx);
+        let (errors, ambiguities): (Vec<_>, Vec<_>) =
+            errors_and_ambiguities.into_iter().partition(|error| error.is_true_error());
+
         if errors.is_empty() {
-            let overflow_errors = fulfill_cx.collect_remaining_errors(infcx);
-            let overflowing_predicates = overflow_errors
-                .into_iter()
-                .filter(|e| match e.code {
-                    FulfillmentErrorCode::Ambiguity { overflow: Some(true) } => true,
-                    _ => false,
-                })
-                .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
-                .collect();
-            IntersectionHasImpossibleObligations::No { overflowing_predicates }
+            IntersectionHasImpossibleObligations::No {
+                overflowing_predicates: ambiguities
+                    .into_iter()
+                    .filter(|error| {
+                        matches!(
+                            error.code,
+                            FulfillmentErrorCode::Ambiguity { overflow: Some(true) }
+                        )
+                    })
+                    .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
+                    .collect(),
+            }
         } else {
             IntersectionHasImpossibleObligations::Yes
         }
@@ -589,13 +591,14 @@ fn try_prove_negated_where_clause<'tcx>(
     // Without this, we over-eagerly register coherence ambiguity candidates when
     // impl candidates do exist.
     let ref infcx = root_infcx.fork_with_intercrate(false);
-    let mut fulfill_cx = FulfillmentCtxt::new(infcx);
-
-    fulfill_cx.register_predicate_obligation(
-        infcx,
-        Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, negative_predicate),
-    );
-    if !fulfill_cx.select_all_or_error(infcx).is_empty() {
+    let ocx = ObligationCtxt::new(infcx);
+    ocx.register_obligation(Obligation::new(
+        infcx.tcx,
+        ObligationCause::dummy(),
+        param_env,
+        negative_predicate,
+    ));
+    if !ocx.select_all_or_error().is_empty() {
         return false;
     }
 
@@ -603,8 +606,7 @@ fn try_prove_negated_where_clause<'tcx>(
     // if that wasn't implemented just for LocalDefId, and we'd need to do
     // the normalization ourselves since this is totally fallible...
     let outlives_env = OutlivesEnvironment::new(param_env);
-
-    let errors = infcx.resolve_regions(&outlives_env);
+    let errors = ocx.resolve_regions(&outlives_env);
     if !errors.is_empty() {
         return false;
     }
@@ -1129,22 +1131,17 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
                 result: Ok(_),
             } = cand.kind()
             {
-                let lazily_normalize_ty = |ty: Ty<'tcx>| {
-                    let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx);
+                let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
                     if matches!(ty.kind(), ty::Alias(..)) {
-                        // FIXME(-Znext-solver=coherence): we currently don't
-                        // normalize opaque types here, resulting in diverging behavior
-                        // for TAITs.
-                        match infcx
-                            .at(&ObligationCause::dummy(), param_env)
-                            .structurally_normalize(ty, &mut *fulfill_cx)
-                        {
-                            Ok(ty) => Ok(ty),
-                            Err(_errs) => Err(()),
+                        let ocx = ObligationCtxt::new(infcx);
+                        ty = ocx
+                            .structurally_normalize(&ObligationCause::dummy(), param_env, ty)
+                            .map_err(|_| ())?;
+                        if !ocx.select_where_possible().is_empty() {
+                            return Err(());
                         }
-                    } else {
-                        Ok(ty)
                     }
+                    Ok(ty)
                 };
 
                 infcx.probe(|_| {
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 432d51ff8f9..9eaaef1eb22 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -7,6 +7,7 @@ use crate::regions::InferCtxtRegionExt;
 use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
 use crate::traits::error_reporting::TypeErrCtxtExt;
 use crate::traits::NormalizeExt;
+use crate::traits::StructurallyNormalizeExt;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -15,6 +16,7 @@ use rustc_infer::infer::canonical::{
     Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
 };
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::RegionResolutionError;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_infer::traits::{
     FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
@@ -117,6 +119,17 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
         self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut())
     }
 
+    pub fn structurally_normalize(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        value: Ty<'tcx>,
+    ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
+        self.infcx
+            .at(cause, param_env)
+            .structurally_normalize(value, &mut **self.engine.borrow_mut())
+    }
+
     pub fn eq<T: ToTrace<'tcx>>(
         &self,
         cause: &ObligationCause<'tcx>,
@@ -182,6 +195,11 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
         self.engine.borrow_mut().select_all_or_error(self.infcx)
     }
 
+    #[must_use]
+    pub fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
+        self.engine.borrow().pending_obligations()
+    }
+
     /// Resolves regions and reports errors.
     ///
     /// Takes ownership of the context as doing trait solving afterwards
@@ -199,6 +217,18 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
         }
     }
 
+    /// Resolves regions and reports errors.
+    ///
+    /// Takes ownership of the context as doing trait solving afterwards
+    /// will result in region constraints getting ignored.
+    #[must_use]
+    pub fn resolve_regions(
+        self,
+        outlives_env: &OutlivesEnvironment<'tcx>,
+    ) -> Vec<RegionResolutionError<'tcx>> {
+        self.infcx.resolve_regions(outlives_env)
+    }
+
     pub fn assumed_wf_types_and_report_errors(
         &self,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 5f2a8944135..87d240cf8ac 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -1,9 +1,10 @@
-use rustc_infer::traits::{TraitEngine, TraitEngineExt};
 use rustc_macros::extension;
 
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::InferCtxt;
-use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
+use crate::traits::{
+    EvaluationResult, ObligationCtxt, OverflowError, PredicateObligation, SelectionContext,
+};
 
 #[extension(pub trait InferCtxtExt<'tcx>)]
 impl<'tcx> InferCtxt<'tcx> {
@@ -67,21 +68,22 @@ impl<'tcx> InferCtxt<'tcx> {
 
         if self.next_trait_solver() {
             self.probe(|snapshot| {
-                let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(self);
-                fulfill_cx.register_predicate_obligation(self, obligation.clone());
-                // True errors
-                // FIXME(-Znext-solver): Overflows are reported as ambig here, is that OK?
-                if !fulfill_cx.select_where_possible(self).is_empty() {
-                    Ok(EvaluationResult::EvaluatedToErr)
-                } else if !fulfill_cx.select_all_or_error(self).is_empty() {
-                    Ok(EvaluationResult::EvaluatedToAmbig)
-                } else if self.opaque_types_added_in_snapshot(snapshot) {
-                    Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes)
+                let ocx = ObligationCtxt::new(self);
+                ocx.register_obligation(obligation.clone());
+                let mut result = EvaluationResult::EvaluatedToOk;
+                for error in ocx.select_all_or_error() {
+                    if error.is_true_error() {
+                        return Ok(EvaluationResult::EvaluatedToErr);
+                    } else {
+                        result = result.max(EvaluationResult::EvaluatedToAmbig);
+                    }
+                }
+                if self.opaque_types_added_in_snapshot(snapshot) {
+                    result = result.max(EvaluationResult::EvaluatedToOkModuloOpaqueTypes);
                 } else if self.region_constraints_added_in_snapshot(snapshot) {
-                    Ok(EvaluationResult::EvaluatedToOkModuloRegions)
-                } else {
-                    Ok(EvaluationResult::EvaluatedToOk)
+                    result = result.max(EvaluationResult::EvaluatedToOkModuloRegions);
                 }
+                Ok(result)
             })
         } else {
             assert!(!self.intercrate);