Skip to content

Commit fefce2f

Browse files
committed
Account for lifetimes of assoc types in fields
1 parent 1c5993f commit fefce2f

File tree

2 files changed

+127
-62
lines changed

2 files changed

+127
-62
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 106 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2727,38 +2727,119 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
27272727
return None;
27282728
};
27292729
/// Collect all `hir::Ty<'_>` `Span`s for trait objects with the sup lifetime.
2730-
pub struct HirTraitObjectVisitor<'tcx>(
2731-
pub Vec<&'tcx hir::PolyTraitRef<'tcx>>,
2732-
pub ty::Region<'tcx>,
2733-
pub FxHashSet<Span>,
2734-
);
2730+
pub struct HirTraitObjectVisitor<'tcx> {
2731+
pub expected_region: ty::Region<'tcx>,
2732+
pub found_region: ty::Region<'tcx>,
2733+
pub lifetime_spans: FxHashSet<Span>,
2734+
pub pred_spans: Vec<Span>,
2735+
pub tcx: TyCtxt<'tcx>,
2736+
}
27352737
impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'tcx> {
2738+
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
2739+
if match (lt.res, self.expected_region.kind()) {
2740+
(
2741+
hir::LifetimeName::ImplicitObjectLifetimeDefault
2742+
| hir::LifetimeName::Static,
2743+
ty::RegionKind::ReStatic,
2744+
) => true,
2745+
(hir::LifetimeName::Param(a), ty::RegionKind::ReEarlyParam(b)) => {
2746+
a.to_def_id() == b.def_id
2747+
}
2748+
_ => false,
2749+
} {
2750+
// We want to keep a span to the lifetime bound on the trait object.
2751+
self.lifetime_spans.insert(lt.ident.span);
2752+
}
2753+
}
27362754
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
2737-
// Find all the trait objects that have the lifetime that was found.
2738-
if let hir::TyKind::TraitObject(poly_trait_refs, lt, _) = t.kind
2739-
&& match (lt.res, self.1.kind()) {
2740-
(
2741-
hir::LifetimeName::ImplicitObjectLifetimeDefault
2742-
| hir::LifetimeName::Static,
2743-
ty::RegionKind::ReStatic,
2744-
) => true,
2745-
(hir::LifetimeName::Param(a), ty::RegionKind::ReEarlyParam(b)) => {
2746-
a.to_def_id() == b.def_id
2755+
match t.kind {
2756+
// Find all the trait objects that have the lifetime that was found.
2757+
hir::TyKind::TraitObject(poly_trait_refs, lt, _)
2758+
if match (lt.res, self.expected_region.kind()) {
2759+
(
2760+
hir::LifetimeName::ImplicitObjectLifetimeDefault
2761+
| hir::LifetimeName::Static,
2762+
ty::RegionKind::ReStatic,
2763+
) => true,
2764+
(hir::LifetimeName::Param(a), ty::RegionKind::ReEarlyParam(b)) => {
2765+
a.to_def_id() == b.def_id
2766+
}
2767+
_ => false,
2768+
} =>
2769+
{
2770+
for ptr in poly_trait_refs {
2771+
if let Some(def_id) = ptr.trait_ref.trait_def_id() {
2772+
// Find the bounds on the trait with the lifetime that couldn't be met.
2773+
let bindings: Vec<Span> = elaborate(
2774+
self.tcx,
2775+
self.tcx
2776+
.predicates_of(def_id)
2777+
.predicates
2778+
.iter()
2779+
.map(|(p, sp)| (p.as_predicate(), *sp)),
2780+
)
2781+
.filter_map(|(pred, pred_span)| {
2782+
if let ty::PredicateKind::Clause(clause) =
2783+
pred.kind().skip_binder()
2784+
&& let ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
2785+
_pred_ty,
2786+
r,
2787+
)) = clause
2788+
&& r == self.found_region
2789+
{
2790+
Some(pred_span)
2791+
} else {
2792+
None
2793+
}
2794+
})
2795+
.collect();
2796+
if !bindings.is_empty() {
2797+
self.lifetime_spans.insert(ptr.span);
2798+
self.pred_spans.extend(bindings);
2799+
}
2800+
}
27472801
}
2748-
_ => false,
27492802
}
2750-
{
2751-
for ptr in poly_trait_refs {
2752-
// We'll filter the traits later, after collection.
2753-
self.0.push(ptr);
2803+
// Detect when an associated item is given a lifetime restriction that the
2804+
// definition of that associated item couldn't meet.
2805+
hir::TyKind::Path(hir::QPath::Resolved(Some(_), path)) => {
2806+
self.pred_spans = elaborate(
2807+
self.tcx,
2808+
self.tcx
2809+
.predicates_of(path.res.def_id())
2810+
.predicates
2811+
.iter()
2812+
.map(|(p, sp)| (p.as_predicate(), *sp)),
2813+
)
2814+
.filter_map(|(pred, pred_span)| {
2815+
match pred.kind().skip_binder() {
2816+
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
2817+
ty::OutlivesPredicate(
2818+
// What should I filter this with?
2819+
_pred_ty,
2820+
r,
2821+
),
2822+
)) if r == self.found_region => Some(pred_span),
2823+
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
2824+
ty::OutlivesPredicate(_, r),
2825+
)) if r == self.found_region => Some(pred_span),
2826+
_ => None,
2827+
}
2828+
})
2829+
.collect();
27542830
}
2755-
// We want to keep a span to the lifetime bound on the trait object.
2756-
self.2.insert(lt.ident.span);
2831+
_ => {}
27572832
}
27582833
hir::intravisit::walk_ty(self, t);
27592834
}
27602835
}
2761-
let mut visitor = HirTraitObjectVisitor(vec![], sup, Default::default());
2836+
let mut visitor = HirTraitObjectVisitor {
2837+
expected_region: sup,
2838+
found_region: sub,
2839+
lifetime_spans: Default::default(),
2840+
pred_spans: vec![],
2841+
tcx: self.tcx,
2842+
};
27622843
for field in item.fields() {
27632844
if field.ty.span == *span {
27642845
// `span` points at the type of a field, we only want to look for trait objects in
@@ -2767,40 +2848,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
27672848
}
27682849
}
27692850

2770-
// The display of these spans will not change regardless or sorting.
27712851
#[allow(rustc::potential_query_instability)]
2772-
let mut primary_spans: Vec<Span> = visitor.2.into_iter().collect();
2773-
let mut relevant_bindings: Vec<Span> = vec![];
2774-
for ptr in visitor.0 {
2775-
if let Some(def_id) = ptr.trait_ref.trait_def_id() {
2776-
// Find the bounds on the trait with the lifetime that couldn't be met.
2777-
let bindings: Vec<Span> = elaborate(
2778-
self.tcx,
2779-
self.tcx
2780-
.predicates_of(def_id)
2781-
.predicates
2782-
.iter()
2783-
.map(|(p, sp)| (p.as_predicate(), *sp)),
2784-
)
2785-
.filter_map(|(pred, pred_span)| {
2786-
if let ty::PredicateKind::Clause(clause) = pred.kind().skip_binder()
2787-
&& let ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_pred_ty, r)) =
2788-
clause
2789-
&& r == sub
2790-
{
2791-
Some(pred_span)
2792-
} else {
2793-
None
2794-
}
2795-
})
2796-
.collect();
2797-
if !bindings.is_empty() {
2798-
primary_spans.push(ptr.span);
2799-
relevant_bindings.extend(bindings);
2800-
}
2801-
}
2802-
}
2803-
Some((primary_spans.into(), relevant_bindings.into()))
2852+
let primary_spans: Vec<Span> = visitor.lifetime_spans.into_iter().collect();
2853+
Some((primary_spans.into(), visitor.pred_spans.into()))
28042854
}
28052855

28062856
/// Determine whether an error associated with the given span and definition

tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,43 +32,58 @@ LL | type Y<'a> = &'a () where 'a: 'static;
3232
| +++++++++++++++++
3333

3434
error[E0478]: lifetime bound not satisfied
35-
--> $DIR/unsatisfied-item-lifetime-bound.rs:14:8
35+
--> $DIR/unsatisfied-item-lifetime-bound.rs:14:20
3636
|
3737
LL | f: <T as X>::Y<'a>,
38-
| ^^^^^^^^^^^^^^^
38+
| ^^
3939
|
4040
note: lifetime parameter instantiated with the lifetime `'a` as defined here
4141
--> $DIR/unsatisfied-item-lifetime-bound.rs:13:10
4242
|
4343
LL | struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
4444
| ^^
4545
= note: but lifetime parameter must outlive the static lifetime
46+
note: `'static` requirement introduced here
47+
--> $DIR/unsatisfied-item-lifetime-bound.rs:4:16
48+
|
49+
LL | type Y<'a: 'static>;
50+
| ^^^^^^^
4651

4752
error[E0478]: lifetime bound not satisfied
48-
--> $DIR/unsatisfied-item-lifetime-bound.rs:19:8
53+
--> $DIR/unsatisfied-item-lifetime-bound.rs:19:20
4954
|
5055
LL | f: <T as X>::Y<'a>,
51-
| ^^^^^^^^^^^^^^^
56+
| ^^
5257
|
5358
note: lifetime parameter instantiated with the lifetime `'a` as defined here
5459
--> $DIR/unsatisfied-item-lifetime-bound.rs:18:10
5560
|
5661
LL | struct C<'a, T: X> {
5762
| ^^
5863
= note: but lifetime parameter must outlive the static lifetime
64+
note: `'static` requirement introduced here
65+
--> $DIR/unsatisfied-item-lifetime-bound.rs:4:16
66+
|
67+
LL | type Y<'a: 'static>;
68+
| ^^^^^^^
5969

6070
error[E0478]: lifetime bound not satisfied
61-
--> $DIR/unsatisfied-item-lifetime-bound.rs:24:8
71+
--> $DIR/unsatisfied-item-lifetime-bound.rs:24:21
6272
|
6373
LL | f: <() as X>::Y<'a>,
64-
| ^^^^^^^^^^^^^^^^
74+
| ^^
6575
|
6676
note: lifetime parameter instantiated with the lifetime `'a` as defined here
6777
--> $DIR/unsatisfied-item-lifetime-bound.rs:23:10
6878
|
6979
LL | struct D<'a> {
7080
| ^^
7181
= note: but lifetime parameter must outlive the static lifetime
82+
note: `'static` requirement introduced here
83+
--> $DIR/unsatisfied-item-lifetime-bound.rs:4:16
84+
|
85+
LL | type Y<'a: 'static>;
86+
| ^^^^^^^
7287

7388
error: aborting due to 4 previous errors; 1 warning emitted
7489

0 commit comments

Comments
 (0)