diff options
Diffstat (limited to 'compiler/rustc_infer/src/infer/outlives')
-rw-r--r-- | compiler/rustc_infer/src/infer/outlives/env.rs | 48 | ||||
-rw-r--r-- | compiler/rustc_infer/src/infer/outlives/mod.rs | 107 | ||||
-rw-r--r-- | compiler/rustc_infer/src/infer/outlives/obligations.rs | 47 | ||||
-rw-r--r-- | compiler/rustc_infer/src/infer/outlives/test_type_match.rs | 8 |
4 files changed, 133 insertions, 77 deletions
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 24e3c34dd..47e3dd762 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -1,9 +1,9 @@ use crate::infer::free_regions::FreeRegionMap; -use crate::infer::{GenericKind, InferCtxt}; +use crate::infer::GenericKind; use crate::traits::query::OutlivesBound; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::transitive_relation::TransitiveRelationBuilder; -use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region}; +use rustc_middle::ty::{self, Region}; use super::explicit_outlives_bounds; @@ -75,7 +75,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { region_bound_pairs: Default::default(), }; - builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env)); + builder.add_outlives_bounds(explicit_outlives_bounds(param_env)); builder } @@ -89,11 +89,10 @@ impl<'tcx> OutlivesEnvironment<'tcx> { /// Create a new `OutlivesEnvironment` with extra outlives bounds. pub fn with_bounds( param_env: ty::ParamEnv<'tcx>, - infcx: Option<&InferCtxt<'tcx>>, extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>, ) -> Self { let mut builder = Self::builder(param_env); - builder.add_outlives_bounds(infcx, extra_bounds); + builder.add_outlives_bounds(extra_bounds); builder.build() } @@ -120,12 +119,7 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { } /// Processes outlives bounds that are known to hold, whether from implied or other sources. - /// - /// The `infcx` parameter is optional; if the implied bounds may - /// contain inference variables, it must be supplied, in which - /// case we will register "givens" on the inference context. (See - /// `RegionConstraintData`.) - fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I) + fn add_outlives_bounds<I>(&mut self, outlives_bounds: I) where I: IntoIterator<Item = OutlivesBound<'tcx>>, { @@ -142,27 +136,17 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { self.region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); } - OutlivesBound::RegionSubRegion(r_a, r_b) => { - if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) { - infcx - .expect("no infcx provided but region vars found") - .add_given(r_a, vid_b); - } else { - // In principle, we could record (and take - // advantage of) every relationship here, but - // we are also free not to -- it simply means - // strictly less that we can successfully type - // check. Right now we only look for things - // relationships between free regions. (It may - // also be that we should revise our inference - // system to be more general and to make use - // of *every* relationship that arises here, - // but presently we do not.) - if r_a.is_free_or_static() && r_b.is_free() { - self.region_relation.add(r_a, r_b) - } - } - } + OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) { + ( + ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_), + ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_), + ) => self.region_relation.add(r_a, r_b), + (ty::ReError(_), _) | (_, ty::ReError(_)) => {} + // FIXME(#109628): We shouldn't have existential variables in implied bounds. + // Panic here once the linked issue is resolved! + (ty::ReVar(_), _) | (_, ty::ReVar(_)) => {} + _ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"), + }, } } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 83f3d5a74..9a9a1696b 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -1,4 +1,11 @@ //! Various code related to computing outlives relations. +use self::env::OutlivesEnvironment; +use super::region_constraints::RegionConstraintData; +use super::{InferCtxt, RegionResolutionError}; +use crate::infer::free_regions::RegionRelations; +use crate::infer::lexical_region_resolve::{self, LexicalRegionResolutions}; +use rustc_middle::traits::query::OutlivesBound; +use rustc_middle::ty; pub mod components; pub mod env; @@ -6,9 +13,6 @@ pub mod obligations; pub mod test_type_match; pub mod verify; -use rustc_middle::traits::query::OutlivesBound; -use rustc_middle::ty; - #[instrument(level = "debug", skip(param_env), ret)] pub fn explicit_outlives_bounds<'tcx>( param_env: ty::ParamEnv<'tcx>, @@ -22,7 +26,7 @@ pub fn explicit_outlives_bounds<'tcx>( ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::Trait(..)) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::WellFormed(..) @@ -39,3 +43,98 @@ pub fn explicit_outlives_bounds<'tcx>( ))) => Some(OutlivesBound::RegionSubRegion(r_b, r_a)), }) } + +impl<'tcx> InferCtxt<'tcx> { + pub fn skip_region_resolution(&self) { + let (var_infos, _) = { + let mut inner = self.inner.borrow_mut(); + let inner = &mut *inner; + // Note: `inner.region_obligations` may not be empty, because we + // didn't necessarily call `process_registered_region_obligations`. + // This is okay, because that doesn't introduce new vars. + inner + .region_constraint_storage + .take() + .expect("regions already resolved") + .with_log(&mut inner.undo_log) + .into_infos_and_data() + }; + + let lexical_region_resolutions = LexicalRegionResolutions { + values: rustc_index::vec::IndexVec::from_elem_n( + crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased), + var_infos.len(), + ), + }; + + let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); + assert!(old_value.is_none()); + } + + /// Process the region constraints and return any errors that + /// result. After this, no more unification operations should be + /// done -- or the compiler will panic -- but it is legal to use + /// `resolve_vars_if_possible` as well as `fully_resolve`. + #[must_use] + pub fn resolve_regions( + &self, + outlives_env: &OutlivesEnvironment<'tcx>, + ) -> Vec<RegionResolutionError<'tcx>> { + self.process_registered_region_obligations(outlives_env); + + let (var_infos, data) = { + let mut inner = self.inner.borrow_mut(); + let inner = &mut *inner; + assert!( + self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(), + "region_obligations not empty: {:#?}", + inner.region_obligations + ); + inner + .region_constraint_storage + .take() + .expect("regions already resolved") + .with_log(&mut inner.undo_log) + .into_infos_and_data() + }; + + let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map()); + + let (lexical_region_resolutions, errors) = + lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data); + + let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); + assert!(old_value.is_none()); + + errors + } + + /// Obtains (and clears) the current set of region + /// constraints. The inference context is still usable: further + /// unifications will simply add new constraints. + /// + /// This method is not meant to be used with normal lexical region + /// resolution. Rather, it is used in the NLL mode as a kind of + /// interim hack: basically we run normal type-check and generate + /// region constraints as normal, but then we take them and + /// translate them into the form that the NLL solver + /// understands. See the NLL module for mode details. + pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> { + assert!( + self.inner.borrow().region_obligations.is_empty(), + "region_obligations not empty: {:#?}", + self.inner.borrow().region_obligations + ); + + self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data() + } + + /// Gives temporary access to the region constraint data. + pub fn with_region_constraints<R>( + &self, + op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, + ) -> R { + let mut inner = self.inner.borrow_mut(); + op(inner.unwrap_region_constraints().data()) + } +} diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index bbe7d4c63..ccf11c61b 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -72,6 +72,8 @@ use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitableExt}; use smallvec::smallvec; +use super::env::OutlivesEnvironment; + impl<'tcx> InferCtxt<'tcx> { /// Registers that the given region obligation must be resolved /// from within the scope of `body_id`. These regions are enqueued @@ -112,39 +114,17 @@ impl<'tcx> InferCtxt<'tcx> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } - /// NOTE: Prefer using `TypeErrCtxt::check_region_obligations_and_report_errors` - /// instead of calling this directly. - /// /// Process the region obligations that must be proven (during /// `regionck`) for the given `body_id`, given information about - /// the region bounds in scope and so forth. This function must be - /// invoked for all relevant body-ids before region inference is - /// done (or else an assert will fire). + /// the region bounds in scope and so forth. /// /// See the `region_obligations` field of `InferCtxt` for some /// comments about how this function fits into the overall expected /// flow of the inferencer. The key point is that it is /// invoked after all type-inference variables have been bound -- - /// towards the end of regionck. This also ensures that the - /// region-bound-pairs are available (see comments above regarding - /// closures). - /// - /// # Parameters - /// - /// - `region_bound_pairs_map`: the set of region bounds implied by - /// the parameters and where-clauses. In particular, each pair - /// `('a, K)` in this list tells us that the bounds in scope - /// indicate that `K: 'a`, where `K` is either a generic - /// parameter like `T` or a projection like `T::Item`. - /// - `param_env` is the parameter environment for the enclosing function. - /// - `body_id` is the body-id whose region obligations are being - /// processed. - #[instrument(level = "debug", skip(self, region_bound_pairs))] - pub fn process_registered_region_obligations( - &self, - region_bound_pairs: &RegionBoundPairs<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) { + /// right before lexical region resolution. + #[instrument(level = "debug", skip(self, outlives_env))] + pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) { assert!( !self.in_snapshot.get(), "cannot process registered region obligations in a snapshot" @@ -153,15 +133,16 @@ impl<'tcx> InferCtxt<'tcx> { let my_region_obligations = self.take_registered_region_obligations(); for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { - debug!( - "process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}", - sup_type, sub_region, origin - ); - + debug!(?sup_type, ?sub_region, ?origin); let sup_type = self.resolve_vars_if_possible(sup_type); - let outlives = - &mut TypeOutlives::new(self, self.tcx, ®ion_bound_pairs, None, param_env); + let outlives = &mut TypeOutlives::new( + self, + self.tcx, + &outlives_env.region_bound_pairs(), + None, + outlives_env.param_env, + ); let category = origin.to_constraint_category(); outlives.type_must_outlive(origin, sup_type, sub_region, category); } diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 3c6cc2b90..01f900f05 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -137,10 +137,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { "Match" } - fn intercrate(&self) -> bool { - false - } - fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -151,10 +147,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { true } // irrelevant - fn mark_ambiguous(&mut self) { - bug!() - } - #[instrument(level = "trace", skip(self))] fn relate_with_variance<T: Relate<'tcx>>( &mut self, |