Use ObligationCtxt in favor of TraitEngine in many places

This commit is contained in:
Michael Goulet 2024-05-01 17:22:39 -04:00
parent 79734f1db8
commit d9eb5232b6
9 changed files with 142 additions and 113 deletions

View File

@ -1,6 +1,6 @@
use crate::errors::AutoDerefReachedRecursionLimit; use crate::errors::AutoDerefReachedRecursionLimit;
use crate::traits;
use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, TraitEngine, TraitEngineExt};
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
@ -8,7 +8,7 @@ use rustc_session::Limit;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::def_id::LOCAL_CRATE; use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::traits::StructurallyNormalizeExt; use rustc_trait_selection::traits::ObligationCtxt;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum AutoderefKind { pub enum AutoderefKind {
@ -167,25 +167,19 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
&self, &self,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> { ) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> {
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.infcx); let ocx = ObligationCtxt::new(self.infcx);
let Ok(normalized_ty) = ocx.structurally_normalize(
let cause = traits::ObligationCause::misc(self.span, self.body_id); &traits::ObligationCause::misc(self.span, self.body_id),
let normalized_ty = match self self.param_env,
.infcx ty,
.at(&cause, self.param_env) ) else {
.structurally_normalize(ty, &mut *fulfill_cx) // We shouldn't have errors here, except for evaluate/fulfill mismatches,
{ // but that's not a reason for an ICE (`predicate_may_hold` is conservative
Ok(normalized_ty) => normalized_ty, // by design).
Err(errors) => { // FIXME(-Znext-solver): This *actually* shouldn't happen then.
// This shouldn't happen, except for evaluate/fulfill mismatches, return None;
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
// by design).
debug!(?errors, "encountered errors while fulfilling");
return None;
}
}; };
let errors = ocx.select_where_possible();
let errors = fulfill_cx.select_where_possible(self.infcx);
if !errors.is_empty() { if !errors.is_empty() {
// This shouldn't happen, except for evaluate/fulfill mismatches, // This shouldn't happen, except for evaluate/fulfill mismatches,
// but that's not a reason for an ICE (`predicate_may_hold` is conservative // but that's not a reason for an ICE (`predicate_may_hold` is conservative
@ -194,7 +188,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
return None; return None;
} }
Some((normalized_ty, fulfill_cx.pending_obligations())) Some((normalized_ty, ocx.pending_obligations()))
} }
/// Returns the final type we ended up with, which may be an inference /// Returns the final type we ended up with, which may be an inference

View File

@ -45,8 +45,7 @@ use rustc_hir::Expr;
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::type_variable::TypeVariableOrigin;
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::traits::TraitEngineExt as _; use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause};
use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause, TraitEngine};
use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_infer::traits::{Obligation, PredicateObligation};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::traits::BuiltinImplSource; use rustc_middle::traits::BuiltinImplSource;
@ -65,7 +64,6 @@ use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::TraitEngineExt as _;
use rustc_trait_selection::traits::{ use rustc_trait_selection::traits::{
self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt,
}; };
@ -164,11 +162,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Filter these cases out to make sure our coercion is more accurate. // Filter these cases out to make sure our coercion is more accurate.
match res { match res {
Ok(InferOk { value, obligations }) if self.next_trait_solver() => { Ok(InferOk { value, obligations }) if self.next_trait_solver() => {
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self); let ocx = ObligationCtxt::new(self);
fulfill_cx.register_predicate_obligations(self, obligations); ocx.register_obligations(obligations);
let errs = fulfill_cx.select_where_possible(self); if ocx.select_where_possible().is_empty() {
if errs.is_empty() { Ok(InferOk { value, obligations: ocx.pending_obligations() })
Ok(InferOk { value, obligations: fulfill_cx.pending_obligations() })
} else { } else {
Err(TypeError::Mismatch) Err(TypeError::Mismatch)
} }
@ -631,13 +628,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// but we need to constrain vars before processing goals mentioning // but we need to constrain vars before processing goals mentioning
// them. // them.
Some(ty::PredicateKind::AliasRelate(..)) => { Some(ty::PredicateKind::AliasRelate(..)) => {
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self); let ocx = ObligationCtxt::new(self);
fulfill_cx.register_predicate_obligation(self, obligation); ocx.register_obligation(obligation);
let errs = fulfill_cx.select_where_possible(self); if !ocx.select_where_possible().is_empty() {
if !errs.is_empty() {
return Err(TypeError::Mismatch); return Err(TypeError::Mismatch);
} }
coercion.obligations.extend(fulfill_cx.pending_obligations()); coercion.obligations.extend(ocx.pending_obligations());
continue; continue;
} }
_ => { _ => {

View File

@ -206,6 +206,18 @@ impl<'tcx> FulfillmentError<'tcx> {
) -> FulfillmentError<'tcx> { ) -> FulfillmentError<'tcx> {
FulfillmentError { obligation, code, root_obligation } FulfillmentError { obligation, code, root_obligation }
} }
pub fn is_true_error(&self) -> bool {
match self.code {
FulfillmentErrorCode::SelectionError(_)
| FulfillmentErrorCode::ProjectionError(_)
| FulfillmentErrorCode::SubtypeError(_, _)
| FulfillmentErrorCode::ConstEquateError(_, _) => true,
FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => {
false
}
}
}
} }
impl<'tcx> PolyTraitObligation<'tcx> { impl<'tcx> PolyTraitObligation<'tcx> {

View File

@ -1,8 +1,9 @@
use crate::traits::query::evaluate_obligation::InferCtxtExt as _; 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::def_id::DefId;
use rustc_hir::lang_items::LangItem; 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_macros::extension;
use rustc_middle::arena::ArenaAllocatable; use rustc_middle::arena::ArenaAllocatable;
use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse}; 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]), ty::TraitRef::new(self.tcx, trait_def_id, [ty]),
)) { )) {
Ok(Some(selection)) => { Ok(Some(selection)) => {
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self); let ocx = ObligationCtxt::new(self);
fulfill_cx.register_predicate_obligations(self, selection.nested_obligations()); ocx.register_obligations(selection.nested_obligations());
Some(fulfill_cx.select_all_or_error(self)) Some(ocx.select_all_or_error())
} }
Ok(None) | Err(_) => None, Ok(None) | Err(_) => None,
} }

View File

@ -14,7 +14,6 @@ use rustc_ast_ir::visit::VisitorResult;
use rustc_infer::infer::resolve::EagerResolver; use rustc_infer::infer::resolve::EagerResolver;
use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::type_variable::TypeVariableOrigin;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
use rustc_infer::traits::{TraitEngine, TraitEngineExt};
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::infer::unify_key::ConstVariableOrigin; use rustc_middle::infer::unify_key::ConstVariableOrigin;
use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::query::NoSolution;
@ -26,9 +25,9 @@ use rustc_middle::ty::TypeFoldable;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
use crate::solve::eval_ctxt::canonical; use crate::solve::eval_ctxt::canonical;
use crate::solve::FulfillmentCtxt;
use crate::solve::{EvalCtxt, GoalEvaluationKind, GoalSource}; use crate::solve::{EvalCtxt, GoalEvaluationKind, GoalSource};
use crate::solve::{GenerateProofTree, InferCtxtEvalExt}; use crate::solve::{GenerateProofTree, InferCtxtEvalExt};
use crate::traits::ObligationCtxt;
pub struct InspectConfig { pub struct InspectConfig {
pub max_depth: usize, pub max_depth: usize,
@ -74,14 +73,13 @@ impl<'tcx> NormalizesToTermHack<'tcx> {
.eq(DefineOpaqueTypes::Yes, self.term, self.unconstrained_term) .eq(DefineOpaqueTypes::Yes, self.term, self.unconstrained_term)
.map_err(|_| NoSolution) .map_err(|_| NoSolution)
.and_then(|InferOk { value: (), obligations }| { .and_then(|InferOk { value: (), obligations }| {
let mut fulfill_cx = FulfillmentCtxt::new(infcx); let ocx = ObligationCtxt::new(infcx);
fulfill_cx.register_predicate_obligations(infcx, obligations); ocx.register_obligations(obligations);
if fulfill_cx.select_where_possible(infcx).is_empty() { let errors = ocx.select_all_or_error();
if fulfill_cx.pending_obligations().is_empty() { if errors.is_empty() {
Ok(Certainty::Yes) Ok(Certainty::Yes)
} else { } else if errors.iter().all(|e| !e.is_true_error()) {
Ok(Certainty::AMBIGUOUS) Ok(Certainty::AMBIGUOUS)
}
} else { } else {
Err(NoSolution) Err(NoSolution)
} }

View File

@ -6,12 +6,9 @@
use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::InferOk; use crate::infer::InferOk;
use crate::regions::InferCtxtRegionExt;
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
use crate::solve::{deeply_normalize_for_diagnostics, inspect, FulfillmentCtxt}; use crate::solve::{deeply_normalize_for_diagnostics, inspect};
use crate::traits::engine::TraitEngineExt as _;
use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::structural_normalize::StructurallyNormalizeExt;
use crate::traits::NormalizeExt; use crate::traits::NormalizeExt;
use crate::traits::SkipLeakCheck; use crate::traits::SkipLeakCheck;
use crate::traits::{ use crate::traits::{
@ -22,7 +19,7 @@ use rustc_errors::{Diag, EmissionGuarantee};
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; 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::query::NoSolution;
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::traits::specialization_graph::OverlapMode;
@ -35,6 +32,7 @@ use std::fmt::Debug;
use std::ops::ControlFlow; use std::ops::ControlFlow;
use super::error_reporting::suggest_new_overflow_limit; 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. /// Whether we do the orphan check relative to this crate or to some remote crate.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -361,23 +359,27 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
let infcx = selcx.infcx; let infcx = selcx.infcx;
if infcx.next_trait_solver() { if infcx.next_trait_solver() {
let mut fulfill_cx = FulfillmentCtxt::new(infcx); let ocx = ObligationCtxt::new(infcx);
fulfill_cx.register_predicate_obligations(infcx, obligations.iter().cloned()); 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. // We only care about the obligations that are *definitely* true errors.
// Ambiguities do not prove the disjointness of two impls. // 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() { if errors.is_empty() {
let overflow_errors = fulfill_cx.collect_remaining_errors(infcx); IntersectionHasImpossibleObligations::No {
let overflowing_predicates = overflow_errors overflowing_predicates: ambiguities
.into_iter() .into_iter()
.filter(|e| match e.code { .filter(|error| {
FulfillmentErrorCode::Ambiguity { overflow: Some(true) } => true, matches!(
_ => false, error.code,
}) FulfillmentErrorCode::Ambiguity { overflow: Some(true) }
.map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate)) )
.collect(); })
IntersectionHasImpossibleObligations::No { overflowing_predicates } .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
.collect(),
}
} else { } else {
IntersectionHasImpossibleObligations::Yes IntersectionHasImpossibleObligations::Yes
} }
@ -589,13 +591,14 @@ fn try_prove_negated_where_clause<'tcx>(
// Without this, we over-eagerly register coherence ambiguity candidates when // Without this, we over-eagerly register coherence ambiguity candidates when
// impl candidates do exist. // impl candidates do exist.
let ref infcx = root_infcx.fork_with_intercrate(false); let ref infcx = root_infcx.fork_with_intercrate(false);
let mut fulfill_cx = FulfillmentCtxt::new(infcx); let ocx = ObligationCtxt::new(infcx);
ocx.register_obligation(Obligation::new(
fulfill_cx.register_predicate_obligation( infcx.tcx,
infcx, ObligationCause::dummy(),
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, negative_predicate), param_env,
); negative_predicate,
if !fulfill_cx.select_all_or_error(infcx).is_empty() { ));
if !ocx.select_all_or_error().is_empty() {
return false; 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 // if that wasn't implemented just for LocalDefId, and we'd need to do
// the normalization ourselves since this is totally fallible... // the normalization ourselves since this is totally fallible...
let outlives_env = OutlivesEnvironment::new(param_env); let outlives_env = OutlivesEnvironment::new(param_env);
let errors = ocx.resolve_regions(&outlives_env);
let errors = infcx.resolve_regions(&outlives_env);
if !errors.is_empty() { if !errors.is_empty() {
return false; return false;
} }
@ -1129,22 +1131,17 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
result: Ok(_), result: Ok(_),
} = cand.kind() } = cand.kind()
{ {
let lazily_normalize_ty = |ty: Ty<'tcx>| { let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx);
if matches!(ty.kind(), ty::Alias(..)) { if matches!(ty.kind(), ty::Alias(..)) {
// FIXME(-Znext-solver=coherence): we currently don't let ocx = ObligationCtxt::new(infcx);
// normalize opaque types here, resulting in diverging behavior ty = ocx
// for TAITs. .structurally_normalize(&ObligationCause::dummy(), param_env, ty)
match infcx .map_err(|_| ())?;
.at(&ObligationCause::dummy(), param_env) if !ocx.select_where_possible().is_empty() {
.structurally_normalize(ty, &mut *fulfill_cx) return Err(());
{
Ok(ty) => Ok(ty),
Err(_errs) => Err(()),
} }
} else {
Ok(ty)
} }
Ok(ty)
}; };
infcx.probe(|_| { infcx.probe(|_| {

View File

@ -7,6 +7,7 @@ use crate::regions::InferCtxtRegionExt;
use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::NormalizeExt; use crate::traits::NormalizeExt;
use crate::traits::StructurallyNormalizeExt;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
@ -15,6 +16,7 @@ use rustc_infer::infer::canonical::{
Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse, Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
}; };
use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::RegionResolutionError;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
use rustc_infer::traits::{ use rustc_infer::traits::{
FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, 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()) 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>>( pub fn eq<T: ToTrace<'tcx>>(
&self, &self,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
@ -182,6 +195,11 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
self.engine.borrow_mut().select_all_or_error(self.infcx) 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. /// Resolves regions and reports errors.
/// ///
/// Takes ownership of the context as doing trait solving afterwards /// 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( pub fn assumed_wf_types_and_report_errors(
&self, &self,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,

View File

@ -1,9 +1,10 @@
use rustc_infer::traits::{TraitEngine, TraitEngineExt};
use rustc_macros::extension; use rustc_macros::extension;
use crate::infer::canonical::OriginalQueryValues; use crate::infer::canonical::OriginalQueryValues;
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext}; use crate::traits::{
EvaluationResult, ObligationCtxt, OverflowError, PredicateObligation, SelectionContext,
};
#[extension(pub trait InferCtxtExt<'tcx>)] #[extension(pub trait InferCtxtExt<'tcx>)]
impl<'tcx> InferCtxt<'tcx> { impl<'tcx> InferCtxt<'tcx> {
@ -67,21 +68,22 @@ impl<'tcx> InferCtxt<'tcx> {
if self.next_trait_solver() { if self.next_trait_solver() {
self.probe(|snapshot| { self.probe(|snapshot| {
let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(self); let ocx = ObligationCtxt::new(self);
fulfill_cx.register_predicate_obligation(self, obligation.clone()); ocx.register_obligation(obligation.clone());
// True errors let mut result = EvaluationResult::EvaluatedToOk;
// FIXME(-Znext-solver): Overflows are reported as ambig here, is that OK? for error in ocx.select_all_or_error() {
if !fulfill_cx.select_where_possible(self).is_empty() { if error.is_true_error() {
Ok(EvaluationResult::EvaluatedToErr) return Ok(EvaluationResult::EvaluatedToErr);
} else if !fulfill_cx.select_all_or_error(self).is_empty() { } else {
Ok(EvaluationResult::EvaluatedToAmbig) result = result.max(EvaluationResult::EvaluatedToAmbig);
} else if self.opaque_types_added_in_snapshot(snapshot) { }
Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes)
} else if self.region_constraints_added_in_snapshot(snapshot) {
Ok(EvaluationResult::EvaluatedToOkModuloRegions)
} else {
Ok(EvaluationResult::EvaluatedToOk)
} }
if self.opaque_types_added_in_snapshot(snapshot) {
result = result.max(EvaluationResult::EvaluatedToOkModuloOpaqueTypes);
} else if self.region_constraints_added_in_snapshot(snapshot) {
result = result.max(EvaluationResult::EvaluatedToOkModuloRegions);
}
Ok(result)
}) })
} else { } else {
assert!(!self.intercrate); assert!(!self.intercrate);

View File

@ -4,14 +4,13 @@
// general routines. // general routines.
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _}; use rustc_infer::traits::FulfillmentErrorCode;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::traits::CodegenObligationError; use rustc_middle::traits::CodegenObligationError;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::{ use rustc_trait_selection::traits::{
ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, Unimplemented,
Unimplemented,
}; };
use tracing::debug; use tracing::debug;
@ -51,15 +50,15 @@ pub fn codegen_select_candidate<'tcx>(
// Currently, we use a fulfillment context to completely resolve // Currently, we use a fulfillment context to completely resolve
// all nested obligations. This is because they can inform the // all nested obligations. This is because they can inform the
// inference of the impl's type parameters. // inference of the impl's type parameters.
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(&infcx); let ocx = ObligationCtxt::new(&infcx);
let impl_source = selection.map(|predicate| { let impl_source = selection.map(|obligation| {
fulfill_cx.register_predicate_obligation(&infcx, predicate); ocx.register_obligation(obligation);
}); });
// In principle, we only need to do this so long as `impl_source` // In principle, we only need to do this so long as `impl_source`
// contains unbound type parameters. It could be a slight // contains unbound type parameters. It could be a slight
// optimization to stop iterating early. // optimization to stop iterating early.
let errors = fulfill_cx.select_all_or_error(&infcx); let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
// `rustc_monomorphize::collector` assumes there are no type errors. // `rustc_monomorphize::collector` assumes there are no type errors.
// Cycle errors are the only post-monomorphization errors possible; emit them now so // Cycle errors are the only post-monomorphization errors possible; emit them now so