diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 2ec14b2f018c3..06c5e518fc646 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -742,7 +742,7 @@ fn ty_known_to_outlive<'tcx>( region: ty::Region<'tcx>, ) -> bool { test_region_obligations(tcx, id, param_env, wf_tys, |infcx| { - infcx.register_region_obligation(infer::RegionObligation { + infcx.register_type_outlives_constraint_inner(infer::TypeOutlivesConstraint { sub_region: region, sup_type: ty, origin: infer::RelateParamBound(DUMMY_SP, ty, None), diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index e9cfc96ba508a..bda33f3f455b0 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -12,23 +12,20 @@ use std::iter; use rustc_index::{Idx, IndexVec}; use rustc_middle::arena::ArenaAllocatable; +use rustc_middle::bug; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable}; -use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument}; use crate::infer::canonical::instantiate::{CanonicalExt, instantiate_value}; use crate::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues, - QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, + QueryRegionConstraints, QueryResponse, }; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin}; use crate::traits::query::NoSolution; -use crate::traits::{ - Obligation, ObligationCause, PredicateObligation, PredicateObligations, ScrubbedTraitError, - TraitEngine, -}; +use crate::traits::{ObligationCause, PredicateObligations, ScrubbedTraitError, TraitEngine}; impl<'tcx> InferCtxt<'tcx> { /// This method is meant to be invoked as the final step of a canonical query @@ -169,15 +166,13 @@ impl<'tcx> InferCtxt<'tcx> { where R: Debug + TypeFoldable>, { - let InferOk { value: result_args, mut obligations } = + let InferOk { value: result_args, obligations } = self.query_response_instantiation(cause, param_env, original_values, query_response)?; - obligations.extend(self.query_outlives_constraints_into_obligations( - cause, - param_env, - &query_response.value.region_constraints.outlives, - &result_args, - )); + for (predicate, _category) in &query_response.value.region_constraints.outlives { + let predicate = instantiate_value(self.tcx, &result_args, *predicate); + self.register_outlives_constraint(predicate, cause); + } let user_result: R = query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); @@ -525,47 +520,6 @@ impl<'tcx> InferCtxt<'tcx> { self.unify_canonical_vars(cause, param_env, original_values, instantiated_query_response) } - /// Converts the region constraints resulting from a query into an - /// iterator of obligations. - fn query_outlives_constraints_into_obligations( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - uninstantiated_region_constraints: &[QueryOutlivesConstraint<'tcx>], - result_args: &CanonicalVarValues<'tcx>, - ) -> impl Iterator> { - uninstantiated_region_constraints.iter().map(move |&constraint| { - let predicate = instantiate_value(self.tcx, result_args, constraint); - self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env) - }) - } - - pub fn query_outlives_constraint_to_obligation( - &self, - (predicate, _): QueryOutlivesConstraint<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Obligation<'tcx, ty::Predicate<'tcx>> { - let ty::OutlivesPredicate(k1, r2) = predicate; - - let atom = match k1.unpack() { - GenericArgKind::Lifetime(r1) => ty::PredicateKind::Clause( - ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)), - ), - GenericArgKind::Type(t1) => ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( - ty::OutlivesPredicate(t1, r2), - )), - GenericArgKind::Const(..) => { - // Consts cannot outlive one another, so we don't expect to - // encounter this branch. - span_bug!(cause.span, "unexpected const outlives {:?}", predicate); - } - }; - let predicate = ty::Binder::dummy(atom); - - Obligation::new(self.tcx, cause, param_env, predicate) - } - /// Given two sets of values for the same set of canonical variables, unify them. /// The second set is produced lazily by supplying indices from the first set. fn unify_canonical_vars( diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 359b9da11ced6..f7fe32a06e63e 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -214,7 +214,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>, span: Span) { - self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy_with_span(span)); + self.register_type_outlives_constraint(ty, r, &ObligationCause::dummy_with_span(span)); } type OpaqueTypeStorageEntries = OpaqueTypeStorageEntries; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b408d76010d7b..8fb25cb9b32fa 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -150,7 +150,7 @@ pub struct InferCtxtInner<'tcx> { /// for each body-id in this map, which will process the /// obligations within. This is expected to be done 'late enough' /// that all type inference variables have been bound and so forth. - region_obligations: Vec>, + region_obligations: Vec>, /// Caches for opaque type inference. opaque_type_storage: OpaqueTypeStorage<'tcx>, @@ -173,7 +173,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - pub fn region_obligations(&self) -> &[RegionObligation<'tcx>] { + pub fn region_obligations(&self) -> &[TypeOutlivesConstraint<'tcx>] { &self.region_obligations } @@ -488,7 +488,7 @@ impl fmt::Display for FixupError { /// See the `region_obligations` field for more information. #[derive(Clone, Debug)] -pub struct RegionObligation<'tcx> { +pub struct TypeOutlivesConstraint<'tcx> { pub sub_region: ty::Region<'tcx>, pub sup_type: Ty<'tcx>, pub origin: SubregionOrigin<'tcx>, @@ -738,19 +738,6 @@ impl<'tcx> InferCtxt<'tcx> { }) } - pub fn region_outlives_predicate( - &self, - cause: &traits::ObligationCause<'tcx>, - predicate: ty::PolyRegionOutlivesPredicate<'tcx>, - ) { - self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| { - let origin = SubregionOrigin::from_obligation_cause(cause, || { - RelateRegionParamBound(cause.span, None) - }); - self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` - }) - } - /// Number of type variables created so far. pub fn num_ty_vars(&self) -> usize { self.inner.borrow_mut().type_variables().num_vars() diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 5fd98e35e5ce8..890902af02bc6 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -76,23 +76,56 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::resolve::OpportunisticRegionResolver; use crate::infer::snapshot::undo_log::UndoLog; -use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound}; +use crate::infer::{ + self, GenericKind, InferCtxt, SubregionOrigin, TypeOutlivesConstraint, VerifyBound, +}; use crate::traits::{ObligationCause, ObligationCauseCode}; impl<'tcx> InferCtxt<'tcx> { + pub fn register_outlives_constraint( + &self, + ty::OutlivesPredicate(arg, r2): ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + cause: &ObligationCause<'tcx>, + ) { + match arg.unpack() { + ty::GenericArgKind::Lifetime(r1) => { + self.register_region_outlives_constraint(ty::OutlivesPredicate(r1, r2), cause); + } + ty::GenericArgKind::Type(ty1) => { + self.register_type_outlives_constraint(ty1, r2, cause); + } + ty::GenericArgKind::Const(_) => unreachable!(), + } + } + + pub fn register_region_outlives_constraint( + &self, + ty::OutlivesPredicate(r_a, r_b): ty::RegionOutlivesPredicate<'tcx>, + cause: &ObligationCause<'tcx>, + ) { + let origin = SubregionOrigin::from_obligation_cause(cause, || { + SubregionOrigin::RelateRegionParamBound(cause.span, None) + }); + // `'a: 'b` ==> `'b <= 'a` + self.sub_regions(origin, r_b, r_a); + } + /// Registers that the given region obligation must be resolved /// from within the scope of `body_id`. These regions are enqueued /// and later processed by regionck, when full type information is /// available (see `region_obligations` field for more /// information). #[instrument(level = "debug", skip(self))] - pub fn register_region_obligation(&self, obligation: RegionObligation<'tcx>) { + pub fn register_type_outlives_constraint_inner( + &self, + obligation: TypeOutlivesConstraint<'tcx>, + ) { let mut inner = self.inner.borrow_mut(); - inner.undo_log.push(UndoLog::PushRegionObligation); + inner.undo_log.push(UndoLog::PushTypeOutlivesConstraint); inner.region_obligations.push(obligation); } - pub fn register_region_obligation_with_cause( + pub fn register_type_outlives_constraint( &self, sup_type: Ty<'tcx>, sub_region: Region<'tcx>, @@ -124,11 +157,15 @@ impl<'tcx> InferCtxt<'tcx> { ) }); - self.register_region_obligation(RegionObligation { sup_type, sub_region, origin }); + self.register_type_outlives_constraint_inner(TypeOutlivesConstraint { + sup_type, + sub_region, + origin, + }); } /// Trait queries just want to pass back type obligations "as is" - pub fn take_registered_region_obligations(&self) -> Vec> { + pub fn take_registered_region_obligations(&self) -> Vec> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } @@ -166,7 +203,7 @@ impl<'tcx> InferCtxt<'tcx> { ); } - for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { + for TypeOutlivesConstraint { sup_type, sub_region, origin } in my_region_obligations { let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region)); let ty::OutlivesPredicate(sup_type, sub_region) = deeply_normalize_ty(outlives, origin.clone()) diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index b7412d3d6a6da..6193f35f3eb60 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -26,7 +26,7 @@ pub(crate) enum UndoLog<'tcx> { RegionConstraintCollector(region_constraints::UndoLog<'tcx>), RegionUnificationTable(sv::UndoLog>>), ProjectionCache(traits::UndoLog<'tcx>), - PushRegionObligation, + PushTypeOutlivesConstraint, } macro_rules! impl_from { @@ -72,7 +72,7 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { self.region_constraint_storage.as_mut().unwrap().unification_table.reverse(undo) } UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), - UndoLog::PushRegionObligation => { + UndoLog::PushTypeOutlivesConstraint => { self.region_obligations.pop(); } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index dfabb94ebfc60..ef955410247fc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1024,7 +1024,7 @@ where } pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) { - // `b : a` ==> `a <= b` + // `'a: 'b` ==> `'b <= 'a` self.delegate.sub_regions(b, a, self.origin_span); } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index b68a784536604..eea311fe66ebb 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -76,7 +76,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< Some(HasChanged::No) } ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { - self.0.register_region_obligation_with_cause( + self.0.register_type_outlives_constraint( outlives.0, outlives.1, &ObligationCause::dummy_with_span(span), diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 02521c9453d98..3ae908ec16b8e 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -726,7 +726,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => { let binder = bound_predicate.rebind(binder); - selcx.infcx.region_outlives_predicate(&dummy_cause, binder) + selcx.infcx.enter_forall(binder, |pred| { + selcx.infcx.register_region_outlives_constraint(pred, &dummy_cause); + }); } ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => { let binder = bound_predicate.rebind(binder); @@ -735,14 +737,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { binder.map_bound_ref(|pred| pred.0).no_bound_vars(), ) { (None, Some(t_a)) => { - selcx.infcx.register_region_obligation_with_cause( + selcx.infcx.register_type_outlives_constraint( t_a, selcx.infcx.tcx.lifetimes.re_static, &dummy_cause, ); } (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { - selcx.infcx.register_region_obligation_with_cause( + selcx.infcx.register_type_outlives_constraint( t_a, r_b, &dummy_cause, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 34c3c905bd977..951dfb879aed7 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -428,7 +428,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { if infcx.considering_regions { - infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); + infcx.register_region_outlives_constraint(data, &obligation.cause); } ProcessResult::Changed(Default::default()) @@ -439,7 +439,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { r_b, ))) => { if infcx.considering_regions { - infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause); + infcx.register_type_outlives_constraint(t_a, r_b, &obligation.cause); } ProcessResult::Changed(Default::default()) } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 68983ef80fa48..59d3ac21387f5 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -9,7 +9,7 @@ use rustc_span::def_id::LocalDefId; use tracing::instrument; use crate::infer::InferCtxt; -use crate::traits::{ObligationCause, ObligationCtxt}; +use crate::traits::ObligationCause; /// Implied bounds are region relationships that we deduce /// automatically. The idea is that (e.g.) a caller must check that a @@ -79,24 +79,9 @@ fn implied_outlives_bounds<'a, 'tcx>( if !constraints.is_empty() { let QueryRegionConstraints { outlives } = constraints; - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let ocx = ObligationCtxt::new(infcx); let cause = ObligationCause::misc(span, body_id); - for &constraint in &outlives { - ocx.register_obligation(infcx.query_outlives_constraint_to_obligation( - constraint, - cause.clone(), - param_env, - )); - } - - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infcx.dcx().span_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation", - ); + for &(predicate, _) in &outlives { + infcx.register_outlives_constraint(predicate, &cause); } }; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index d9b57f0c67d14..e294f7839aac7 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,6 +1,6 @@ use std::ops::ControlFlow; -use rustc_infer::infer::RegionObligation; +use rustc_infer::infer::TypeOutlivesConstraint; use rustc_infer::infer::canonical::CanonicalQueryInput; use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; @@ -141,7 +141,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( && !ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat && ty.visit_with(&mut ContainsBevyParamSet { tcx: ocx.infcx.tcx }).is_break() { - for RegionObligation { sup_type, sub_region, .. } in + for TypeOutlivesConstraint { sup_type, sub_region, .. } in ocx.infcx.take_registered_region_obligations() { let mut components = smallvec![];