Skip to content

Commit 9506a24

Browse files
committed
Account for lifetimes of assoc types in fields
1 parent 2978c7e commit 9506a24

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

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

2759-
// The display of these spans will not change regardless or sorting.
27602840
#[allow(rustc::potential_query_instability)]
2761-
let mut primary_spans: Vec<Span> = visitor.2.into_iter().collect();
2762-
let mut relevant_bindings: Vec<Span> = vec![];
2763-
for ptr in visitor.0 {
2764-
if let Some(def_id) = ptr.trait_ref.trait_def_id() {
2765-
// Find the bounds on the trait with the lifetime that couldn't be met.
2766-
let bindings: Vec<Span> = elaborate(
2767-
self.tcx,
2768-
self.tcx
2769-
.predicates_of(def_id)
2770-
.predicates
2771-
.iter()
2772-
.map(|(p, sp)| (p.as_predicate(), *sp)),
2773-
)
2774-
.filter_map(|(pred, pred_span)| {
2775-
if let ty::PredicateKind::Clause(clause) = pred.kind().skip_binder()
2776-
&& let ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_pred_ty, r)) =
2777-
clause
2778-
&& r == sub
2779-
{
2780-
Some(pred_span)
2781-
} else {
2782-
None
2783-
}
2784-
})
2785-
.collect();
2786-
if !bindings.is_empty() {
2787-
primary_spans.push(ptr.span);
2788-
relevant_bindings.extend(bindings);
2789-
}
2790-
}
2791-
}
2792-
Some((primary_spans.into(), relevant_bindings.into()))
2841+
let primary_spans: Vec<Span> = visitor.lifetime_spans.into_iter().collect();
2842+
Some((primary_spans.into(), visitor.pred_spans.into()))
27932843
}
27942844

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

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

+21-6
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)