summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer/outlives
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer/src/infer/outlives')
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs48
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs107
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs47
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs8
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, &region_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,