Skip to content

Commit 3e320bc

Browse files
resolve region bounds from components of type projection
1 parent 8c0b1fc commit 3e320bc

File tree

9 files changed

+73
-18
lines changed

9 files changed

+73
-18
lines changed

compiler/rustc_borrowck/src/type_check/constraint_conversion.rs

+8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_span::Span;
1212
use rustc_trait_selection::solve::deeply_normalize;
1313
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
1414
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
15+
use smallvec::SmallVec;
1516

1617
use crate::{
1718
constraints::OutlivesConstraint,
@@ -147,8 +148,14 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
147148
region_bound_pairs,
148149
implicit_region_bound,
149150
known_type_outlives_obligations,
151+
param_env,
150152
..
151153
} = *self;
154+
let projection_predicates: SmallVec<[_; 4]> = param_env
155+
.caller_bounds()
156+
.iter()
157+
.filter_map(|clause| clause.as_projection_clause())
158+
.collect();
152159

153160
let mut outlives_predicates = vec![(predicate, constraint_category)];
154161
for iteration in 0.. {
@@ -191,6 +198,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
191198
region_bound_pairs,
192199
Some(implicit_region_bound),
193200
known_type_outlives_obligations,
201+
&projection_predicates,
194202
)
195203
.type_must_outlive(
196204
origin,

compiler/rustc_borrowck/src/type_check/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
11291129
data: &QueryRegionConstraints<'tcx>,
11301130
) {
11311131
debug!("constraints generated: {:#?}", data);
1132+
debug!(?self.param_env);
11321133

11331134
constraint_conversion::ConstraintConversion::new(
11341135
self.infcx,

compiler/rustc_borrowck/src/universal_regions.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ struct UniversalRegionsBuilder<'cx, 'tcx> {
418418
const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion;
419419

420420
impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
421+
#[instrument(level = "debug", skip(self))]
421422
fn build(self) -> UniversalRegions<'tcx> {
422423
debug!("build(mir_def={:?})", self.mir_def);
423424

@@ -851,8 +852,8 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
851852
/// in later and instantiate the late-bound regions, and then we
852853
/// insert the `ReLateParam` version of those into the map as
853854
/// well. These are used for error reporting.
855+
#[instrument(level = "debug", skip(self))]
854856
fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) {
855-
debug!("insert_late_bound_region({:?}, {:?})", r, vid);
856857
self.indices.insert(r, vid);
857858
}
858859

compiler/rustc_infer/src/infer/outlives/components.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,10 @@ pub(super) fn compute_alias_components_recursive<'tcx>(
211211
let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
212212
unreachable!("can only call `compute_alias_components_recursive` on an alias type")
213213
};
214-
let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] };
214+
let opt_variances =
215+
if matches!(kind, ty::Opaque) { tcx.variances_of(alias_ty.def_id) } else { &[] };
215216
for (index, child) in alias_ty.args.iter().enumerate() {
216-
if opt_variances.get(index) == Some(&ty::Bivariant) {
217+
if matches!(opt_variances.get(index), Some(ty::Bivariant)) {
217218
continue;
218219
}
219220
if !visited.insert(child) {

compiler/rustc_infer/src/infer/outlives/env.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use super::explicit_outlives_bounds;
2626
/// refactoring here, since the setup with NLL is quite different.
2727
/// For example, NLL has no need of `RegionRelations`, and is solely
2828
/// interested in the `OutlivesEnvironment`. -nmatsakis
29-
#[derive(Clone)]
29+
#[derive(Clone, Debug)]
3030
pub struct OutlivesEnvironment<'tcx> {
3131
pub param_env: ty::ParamEnv<'tcx>,
3232
free_region_map: FreeRegionMap<'tcx>,

compiler/rustc_infer/src/infer/outlives/obligations.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,13 @@ impl<'tcx> InferCtxt<'tcx> {
8989
inner.region_obligations.push(obligation);
9090
}
9191

92+
#[instrument(level = "debug", skip(self))]
9293
pub fn register_region_obligation_with_cause(
9394
&self,
9495
sup_type: Ty<'tcx>,
9596
sub_region: Region<'tcx>,
9697
cause: &ObligationCause<'tcx>,
9798
) {
98-
debug!(?sup_type, ?sub_region, ?cause);
9999
let origin = SubregionOrigin::from_obligation_cause(cause, || {
100100
infer::RelateParamBound(
101101
cause.span,
@@ -125,7 +125,7 @@ impl<'tcx> InferCtxt<'tcx> {
125125
/// flow of the inferencer. The key point is that it is
126126
/// invoked after all type-inference variables have been bound --
127127
/// right before lexical region resolution.
128-
#[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))]
128+
#[instrument(level = "debug", skip(self, deeply_normalize_ty))]
129129
pub fn process_registered_region_obligations(
130130
&self,
131131
outlives_env: &OutlivesEnvironment<'tcx>,
@@ -185,6 +185,7 @@ impl<'tcx> InferCtxt<'tcx> {
185185
outlives_env.region_bound_pairs(),
186186
None,
187187
&normalized_caller_bounds,
188+
&[],
188189
);
189190
let category = origin.to_constraint_category();
190191
outlives.type_must_outlive(origin, sup_type, sub_region, category);
@@ -240,6 +241,7 @@ where
240241
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
241242
implicit_region_bound: Option<ty::Region<'tcx>>,
242243
caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>],
244+
projection_predicates: &'cx [ty::PolyTypeProjectionPredicate<'tcx>],
243245
) -> Self {
244246
Self {
245247
delegate,
@@ -249,6 +251,7 @@ where
249251
region_bound_pairs,
250252
implicit_region_bound,
251253
caller_bounds,
254+
projection_predicates,
252255
),
253256
}
254257
}
@@ -319,7 +322,10 @@ where
319322
region: ty::Region<'tcx>,
320323
param_ty: ty::ParamTy,
321324
) {
322-
let verify_bound = self.verify_bound.param_or_placeholder_bound(param_ty.to_ty(self.tcx));
325+
let verify_bound = self
326+
.verify_bound
327+
.param_or_placeholder_bound(param_ty.to_ty(self.tcx), &mut Default::default());
328+
debug!("param_ty_must_outlive: pushing {:?}", verify_bound);
323329
self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound);
324330
}
325331

@@ -330,9 +336,11 @@ where
330336
region: ty::Region<'tcx>,
331337
placeholder_ty: ty::PlaceholderType,
332338
) {
333-
let verify_bound = self
334-
.verify_bound
335-
.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty));
339+
let verify_bound = self.verify_bound.param_or_placeholder_bound(
340+
Ty::new_placeholder(self.tcx, placeholder_ty),
341+
&mut Default::default(),
342+
);
343+
debug!("placeholder_ty_must_outlive: pushing {:?}", verify_bound);
336344
self.delegate.push_verify(
337345
origin,
338346
GenericKind::Placeholder(placeholder_ty),

compiler/rustc_infer/src/infer/outlives/verify.rs

+40-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub struct VerifyBoundCx<'cx, 'tcx> {
2424
/// setting `'?0` to `'empty`.
2525
implicit_region_bound: Option<ty::Region<'tcx>>,
2626
caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>],
27+
projection_predicates: &'cx [ty::PolyTypeProjectionPredicate<'tcx>],
2728
}
2829

2930
impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
@@ -32,12 +33,23 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
3233
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
3334
implicit_region_bound: Option<ty::Region<'tcx>>,
3435
caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>],
36+
projection_predicates: &'cx [ty::PolyTypeProjectionPredicate<'tcx>],
3537
) -> Self {
36-
Self { tcx, region_bound_pairs, implicit_region_bound, caller_bounds }
38+
Self {
39+
tcx,
40+
region_bound_pairs,
41+
implicit_region_bound,
42+
caller_bounds,
43+
projection_predicates,
44+
}
3745
}
3846

3947
#[instrument(level = "debug", skip(self))]
40-
pub fn param_or_placeholder_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
48+
pub fn param_or_placeholder_bound(
49+
&self,
50+
ty: Ty<'tcx>,
51+
visited: &mut SsoHashSet<GenericArg<'tcx>>,
52+
) -> VerifyBound<'tcx> {
4153
// Start with anything like `T: 'a` we can scrape from the
4254
// environment. If the environment contains something like
4355
// `for<'a> T: 'a`, then we know that `T` outlives everything.
@@ -56,6 +68,28 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
5668
}
5769
}
5870

71+
// A parameter or placeholder bound can also be aliased to an associated type
72+
// so we need to inspect in the "reverse"
73+
for &predicate in self.projection_predicates {
74+
let ty::ProjectionPredicate { term, projection_ty } =
75+
self.tcx.erase_regions(predicate).skip_binder();
76+
if let Some(term) = term.ty()
77+
&& ty == term
78+
{
79+
debug!(?term, ?projection_ty, "found a matching predicate");
80+
let alias_ty_as_ty = projection_ty.to_ty(self.tcx);
81+
let mut components = smallvec![];
82+
compute_alias_components_recursive(
83+
self.tcx,
84+
alias_ty_as_ty,
85+
&mut components,
86+
visited,
87+
);
88+
debug!(?components);
89+
param_bounds.push(self.bound_from_components(&components, visited));
90+
}
91+
}
92+
5993
// Add in the default bound of fn body that applies to all in
6094
// scope type parameters:
6195
if let Some(r) = self.implicit_region_bound {
@@ -163,10 +197,11 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
163197
) -> VerifyBound<'tcx> {
164198
match *component {
165199
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
166-
Component::Param(param_ty) => self.param_or_placeholder_bound(param_ty.to_ty(self.tcx)),
167-
Component::Placeholder(placeholder_ty) => {
168-
self.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty))
200+
Component::Param(param_ty) => {
201+
self.param_or_placeholder_bound(param_ty.to_ty(self.tcx), visited)
169202
}
203+
Component::Placeholder(placeholder_ty) => self
204+
.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty), visited),
170205
Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited),
171206
Component::EscapingAlias(ref components) => {
172207
self.bound_from_components(components, visited)

compiler/rustc_middle/src/ty/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ pub use self::predicate::{
9494
ExistentialTraitRef, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
9595
PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
9696
PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate,
97-
PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate,
98-
RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitPredicate,
99-
TraitRef, TypeOutlivesPredicate,
97+
PolyTraitRef, PolyTypeOutlivesPredicate, PolyTypeProjectionPredicate, Predicate, PredicateKind,
98+
ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, ToPredicate,
99+
TraitPredicate, TraitRef, TypeOutlivesPredicate,
100100
};
101101
pub use self::region::{
102102
BoundRegion, BoundRegionKind, BoundRegionKind::*, EarlyParamRegion, LateParamRegion, Region,

compiler/rustc_middle/src/ty/predicate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty:
706706
pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
707707
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
708708
pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
709+
pub type PolyTypeProjectionPredicate<'tcx> = ty::Binder<'tcx, ProjectionPredicate<'tcx>>;
709710

710711
/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
711712
/// whether the `a` type is the type that we should label as "expected" when

0 commit comments

Comments
 (0)