summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer/outlives/obligations.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer/src/infer/outlives/obligations.rs')
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs170
1 files changed, 123 insertions, 47 deletions
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index ad052f58c..6ca884799 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -68,12 +68,14 @@ use crate::infer::{
};
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::undo_log::UndoLogs;
+use rustc_hir::def_id::DefId;
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 rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
use smallvec::smallvec;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// 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
@@ -92,12 +94,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 +165,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);
}
}
@@ -178,7 +183,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
outlives_env.param_env,
);
- self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
+ self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env)
}
}
@@ -205,6 +210,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 +253,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,21 +273,25 @@ 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);
}
+ Component::Opaque(def_id, substs) => {
+ self.opaque_must_outlive(*def_id, substs, origin, region)
+ }
Component::Projection(projection_ty) => {
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
@@ -308,17 +318,69 @@ where
);
let generic = GenericKind::Param(param_ty);
- let verify_bound = self.verify_bound.generic_bound(generic);
+ let verify_bound = self.verify_bound.param_bound(param_ty);
self.delegate.push_verify(origin, generic, region, verify_bound);
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
+ fn opaque_must_outlive(
+ &mut self,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ ) {
+ self.generic_must_outlive(
+ origin,
+ region,
+ GenericKind::Opaque(def_id, substs),
+ def_id,
+ substs,
+ true,
+ |ty| match *ty.kind() {
+ ty::Opaque(def_id, substs) => (def_id, substs),
+ _ => bug!("expected only projection types from env, not {:?}", ty),
+ },
+ );
+ }
+
+ #[instrument(level = "debug", skip(self))]
fn projection_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
) {
+ self.generic_must_outlive(
+ origin,
+ region,
+ GenericKind::Projection(projection_ty),
+ projection_ty.item_def_id,
+ projection_ty.substs,
+ false,
+ |ty| match ty.kind() {
+ ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs),
+ _ => bug!("expected only projection types from env, not {:?}", ty),
+ },
+ );
+ }
+
+ #[instrument(level = "debug", skip(self, filter))]
+ fn generic_must_outlive(
+ &mut self,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ generic: GenericKind<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ is_opaque: bool,
+ filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>),
+ ) {
+ // An optimization for a common case with opaque types.
+ if substs.is_empty() {
+ return;
+ }
+
// This case is thorny for inference. The fundamental problem is
// that there are many cases where we have choice, and inference
// doesn't like choice (the current region inference in
@@ -337,16 +399,15 @@ where
// These are guaranteed to apply, no matter the inference
// results.
let trait_bounds: Vec<_> =
- self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect();
+ self.verify_bound.declared_region_bounds(def_id, substs).collect();
debug!(?trait_bounds);
// Compute the bounds we can derive from the environment. This
// is an "approximate" match -- in some cases, these bounds
// may not apply.
- let mut approx_env_bounds =
- self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty);
- debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds);
+ let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic);
+ debug!(?approx_env_bounds);
// Remove outlives bounds that we get from the environment but
// which are also deducible from the trait. This arises (cc
@@ -360,14 +421,8 @@ where
// If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
// will be invoked with `['b => ^1]` and so we will get `^1` returned.
let bound = bound_outlives.skip_binder();
- match *bound.0.kind() {
- ty::Projection(projection_ty) => self
- .verify_bound
- .projection_declared_bounds_from_trait(projection_ty)
- .all(|r| r != bound.1),
-
- _ => panic!("expected only projection types from env, not {:?}", bound.0),
- }
+ let (def_id, substs) = filter(bound.0);
+ self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1)
});
// If declared bounds list is empty, the only applicable rule is
@@ -384,23 +439,11 @@ where
// the problem is to add `T: 'r`, which isn't true. So, if there are no
// inference variables, we use a verify constraint instead of adding
// edges, which winds up enforcing the same condition.
- let needs_infer = projection_ty.needs_infer();
- if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
- debug!("projection_must_outlive: no declared bounds");
-
- for k in projection_ty.substs {
- match k.unpack() {
- GenericArgKind::Lifetime(lt) => {
- self.delegate.push_sub_region_constraint(origin.clone(), region, lt);
- }
- GenericArgKind::Type(ty) => {
- self.type_must_outlive(origin.clone(), ty, region);
- }
- GenericArgKind::Const(_) => {
- // Const parameters don't impose constraints.
- }
- }
- }
+ let needs_infer = substs.needs_infer();
+ if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) {
+ debug!("no declared bounds");
+
+ self.substs_must_outlive(substs, origin, region);
return;
}
@@ -430,9 +473,10 @@ where
.all(|b| b == Some(trait_bounds[0]))
{
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);
+ debug!(?unique_bound);
+ debug!("unique declared bound appears in trait ref");
+ let category = origin.to_constraint_category();
+ self.delegate.push_sub_region_constraint(origin, region, unique_bound, category);
return;
}
@@ -441,19 +485,51 @@ where
// projection outlive; in some cases, this may add insufficient
// edges into the inference graph, leading to inference failures
// even though a satisfactory solution exists.
- let generic = GenericKind::Projection(projection_ty);
- let verify_bound = self.verify_bound.generic_bound(generic);
+ let verify_bound = self.verify_bound.projection_opaque_bounds(
+ generic,
+ def_id,
+ substs,
+ &mut Default::default(),
+ );
debug!("projection_must_outlive: pushing {:?}", verify_bound);
self.delegate.push_verify(origin, generic, region, verify_bound);
}
+
+ fn substs_must_outlive(
+ &mut self,
+ substs: SubstsRef<'tcx>,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ ) {
+ let constraint = origin.to_constraint_category();
+ for k in substs {
+ match k.unpack() {
+ GenericArgKind::Lifetime(lt) => {
+ self.delegate.push_sub_region_constraint(
+ origin.clone(),
+ region,
+ lt,
+ constraint,
+ );
+ }
+ GenericArgKind::Type(ty) => {
+ self.type_must_outlive(origin.clone(), ty, region, constraint);
+ }
+ GenericArgKind::Const(_) => {
+ // Const parameters don't impose constraints.
+ }
+ }
+ }
+ }
}
-impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
+impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'tcx> {
fn push_sub_region_constraint(
&mut self,
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
+ _constraint_category: ConstraintCategory<'tcx>,
) {
self.sub_regions(origin, a, b)
}