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.rs62
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs36
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs15
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs6
5 files changed, 91 insertions, 30 deletions
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index b2decd64f..9922b156e 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -2,6 +2,7 @@ use crate::infer::free_regions::FreeRegionMap;
use crate::infer::{GenericKind, InferCtxt};
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 super::explicit_outlives_bounds;
@@ -51,23 +52,49 @@ pub struct OutlivesEnvironment<'tcx> {
region_bound_pairs: RegionBoundPairs<'tcx>,
}
+/// Builder of OutlivesEnvironment.
+#[derive(Debug)]
+struct OutlivesEnvironmentBuilder<'tcx> {
+ param_env: ty::ParamEnv<'tcx>,
+ region_relation: TransitiveRelationBuilder<Region<'tcx>>,
+ region_bound_pairs: RegionBoundPairs<'tcx>,
+}
+
/// "Region-bound pairs" tracks outlives relations that are known to
/// be true, either because of explicit where-clauses like `T: 'a` or
/// because of implied bounds.
pub type RegionBoundPairs<'tcx> =
FxIndexSet<ty::OutlivesPredicate<GenericKind<'tcx>, Region<'tcx>>>;
-impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
- pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
- let mut env = OutlivesEnvironment {
+impl<'tcx> OutlivesEnvironment<'tcx> {
+ /// Create a builder using `ParamEnv` and add explicit outlives bounds into it.
+ fn builder(param_env: ty::ParamEnv<'tcx>) -> OutlivesEnvironmentBuilder<'tcx> {
+ let mut builder = OutlivesEnvironmentBuilder {
param_env,
- free_region_map: Default::default(),
+ region_relation: Default::default(),
region_bound_pairs: Default::default(),
};
- env.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
+ builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
- env
+ builder
+ }
+
+ #[inline]
+ /// Create a new `OutlivesEnvironment` without extra outlives bounds.
+ pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
+ Self::builder(param_env).build()
+ }
+
+ /// Create a new `OutlivesEnvironment` with extra outlives bounds.
+ pub fn with_bounds<'a>(
+ param_env: ty::ParamEnv<'tcx>,
+ infcx: Option<&InferCtxt<'a, 'tcx>>,
+ extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
+ ) -> Self {
+ let mut builder = Self::builder(param_env);
+ builder.add_outlives_bounds(infcx, extra_bounds);
+ builder.build()
}
/// Borrows current value of the `free_region_map`.
@@ -79,6 +106,18 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
&self.region_bound_pairs
}
+}
+
+impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
+ #[inline]
+ #[instrument(level = "debug")]
+ fn build(self) -> OutlivesEnvironment<'tcx> {
+ OutlivesEnvironment {
+ param_env: self.param_env,
+ free_region_map: FreeRegionMap { relation: self.region_relation.freeze() },
+ region_bound_pairs: self.region_bound_pairs,
+ }
+ }
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
///
@@ -86,11 +125,8 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
/// contain inference variables, it must be supplied, in which
/// case we will register "givens" on the inference context. (See
/// `RegionConstraintData`.)
- pub fn add_outlives_bounds<I>(
- &mut self,
- infcx: Option<&InferCtxt<'a, 'tcx>>,
- outlives_bounds: I,
- ) where
+ fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I)
+ where
I: IntoIterator<Item = OutlivesBound<'tcx>>,
{
// Record relationships such as `T:'x` that don't go into the
@@ -122,7 +158,9 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
// system to be more general and to make use
// of *every* relationship that arises here,
// but presently we do not.)
- self.free_region_map.relate_regions(r_a, r_b);
+ if r_a.is_free_or_static() && r_b.is_free() {
+ self.region_relation.add(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 2a085288f..2d19d1823 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -9,7 +9,7 @@ pub mod verify;
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty;
-#[instrument(level = "debug", skip(param_env))]
+#[instrument(level = "debug", skip(param_env), ret)]
pub fn explicit_outlives_bounds<'tcx>(
param_env: ty::ParamEnv<'tcx>,
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index ad052f58c..5bd1774f6 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -69,6 +69,7 @@ use crate::infer::{
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::undo_log::UndoLogs;
use rustc_hir::def_id::LocalDefId;
+use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
use smallvec::smallvec;
@@ -92,12 +93,14 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
sub_region: Region<'tcx>,
cause: &ObligationCause<'tcx>,
) {
+ debug!(?sup_type, ?sub_region, ?cause);
let origin = SubregionOrigin::from_obligation_cause(cause, || {
infer::RelateParamBound(
cause.span,
sup_type,
match cause.code().peel_derives() {
- ObligationCauseCode::BindingObligation(_, span) => Some(*span),
+ ObligationCauseCode::BindingObligation(_, span)
+ | ObligationCauseCode::ExprBindingObligation(_, span, ..) => Some(*span),
_ => None,
},
)
@@ -161,7 +164,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
let outlives =
&mut TypeOutlives::new(self, self.tcx, &region_bound_pairs, None, param_env);
- outlives.type_must_outlive(origin, sup_type, sub_region);
+ let category = origin.to_constraint_category();
+ outlives.type_must_outlive(origin, sup_type, sub_region, category);
}
}
@@ -205,6 +209,7 @@ pub trait TypeOutlivesDelegate<'tcx> {
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
+ constraint_category: ConstraintCategory<'tcx>,
);
fn push_verify(
@@ -247,19 +252,19 @@ where
/// - `origin`, the reason we need this constraint
/// - `ty`, the type `T`
/// - `region`, the region `'a`
+ #[instrument(level = "debug", skip(self))]
pub fn type_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
ty: Ty<'tcx>,
region: ty::Region<'tcx>,
+ category: ConstraintCategory<'tcx>,
) {
- debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})", ty, region, origin);
-
assert!(!ty.has_escaping_bound_vars());
let mut components = smallvec![];
push_outlives_components(self.tcx, ty, &mut components);
- self.components_must_outlive(origin, &components, region);
+ self.components_must_outlive(origin, &components, region, category);
}
fn components_must_outlive(
@@ -267,12 +272,13 @@ where
origin: infer::SubregionOrigin<'tcx>,
components: &[Component<'tcx>],
region: ty::Region<'tcx>,
+ category: ConstraintCategory<'tcx>,
) {
for component in components.iter() {
let origin = origin.clone();
match component {
Component::Region(region1) => {
- self.delegate.push_sub_region_constraint(origin, region, *region1);
+ self.delegate.push_sub_region_constraint(origin, region, *region1, category);
}
Component::Param(param_ty) => {
self.param_ty_must_outlive(origin, region, *param_ty);
@@ -281,7 +287,7 @@ where
self.projection_must_outlive(origin, region, *projection_ty);
}
Component::EscapingProjection(subcomponents) => {
- self.components_must_outlive(origin, &subcomponents, region);
+ self.components_must_outlive(origin, &subcomponents, region, category);
}
Component::UnresolvedInferenceVariable(v) => {
// ignore this, we presume it will yield an error
@@ -312,7 +318,7 @@ where
self.delegate.push_verify(origin, generic, region, verify_bound);
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn projection_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
@@ -388,13 +394,19 @@ where
if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
debug!("projection_must_outlive: no declared bounds");
+ let constraint = origin.to_constraint_category();
for k in projection_ty.substs {
match k.unpack() {
GenericArgKind::Lifetime(lt) => {
- self.delegate.push_sub_region_constraint(origin.clone(), region, lt);
+ self.delegate.push_sub_region_constraint(
+ origin.clone(),
+ region,
+ lt,
+ constraint,
+ );
}
GenericArgKind::Type(ty) => {
- self.type_must_outlive(origin.clone(), ty, region);
+ self.type_must_outlive(origin.clone(), ty, region, constraint);
}
GenericArgKind::Const(_) => {
// Const parameters don't impose constraints.
@@ -432,7 +444,8 @@ where
let unique_bound = trait_bounds[0];
debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
debug!("projection_must_outlive: unique declared bound appears in trait ref");
- self.delegate.push_sub_region_constraint(origin, region, unique_bound);
+ let category = origin.to_constraint_category();
+ self.delegate.push_sub_region_constraint(origin, region, unique_bound, category);
return;
}
@@ -454,6 +467,7 @@ impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
+ _constraint_category: ConstraintCategory<'tcx>,
) {
self.sub_regions(origin, a, b)
}
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 772e297b7..a5c21f0fb 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -34,7 +34,7 @@ use crate::infer::region_constraints::VerifyIfEq;
/// like are used. This is a particular challenge since this function is invoked
/// very late in inference and hence cannot make use of the normal inference
/// machinery.
-#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+#[instrument(level = "debug", skip(tcx, param_env))]
pub fn extract_verify_if_eq<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -71,7 +71,7 @@ pub fn extract_verify_if_eq<'tcx>(
}
/// True if a (potentially higher-ranked) outlives
-#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+#[instrument(level = "debug", skip(tcx, param_env))]
pub(super) fn can_match_erased_ty<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -110,7 +110,7 @@ impl<'tcx> Match<'tcx> {
/// Binds the pattern variable `br` to `value`; returns an `Err` if the pattern
/// is already bound to a different value.
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn bind(
&mut self,
br: ty::BoundRegion,
@@ -174,7 +174,14 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, pattern: Ty<'tcx>, value: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- if pattern == value { Ok(pattern) } else { relate::super_relate_tys(self, pattern, value) }
+ if let ty::Error(_) = pattern.kind() {
+ // Unlike normal `TypeRelation` rules, `ty::Error` does not equal any type.
+ self.no_match()
+ } else if pattern == value {
+ Ok(pattern)
+ } else {
+ relate::super_relate_tys(self, pattern, value)
+ }
}
#[instrument(skip(self), level = "debug")]
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index c7d7ef40d..752334950 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -50,13 +50,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
}
}
+ #[instrument(level = "debug", skip(self))]
fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
- debug!("param_bound(param_ty={:?})", param_ty);
-
// Start with anything like `T: 'a` we can scrape from the
// environment. If the environment contains something like
// `for<'a> T: 'a`, then we know that `T` outlives everything.
let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty);
+ debug!(?declared_bounds_from_env);
let mut param_bounds = vec![];
for declared_bound in declared_bounds_from_env {
let bound_region = declared_bound.map_bound(|outlives| outlives.1);
@@ -65,6 +65,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
param_bounds.push(VerifyBound::OutlivedBy(region));
} else {
// This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here.
+ debug!("found that {param_ty:?} outlives any lifetime, returning empty vector");
return VerifyBound::AllBounds(vec![]);
}
}
@@ -72,6 +73,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
// Add in the default bound of fn body that applies to all in
// scope type parameters:
if let Some(r) = self.implicit_region_bound {
+ debug!("adding implicit region bound of {r:?}");
param_bounds.push(VerifyBound::OutlivedBy(r));
}