Skip to content

Commit bde9677

Browse files
committed
Suggest named lifetime in ADT with hrtb
1 parent 24be307 commit bde9677

File tree

3 files changed

+87
-10
lines changed

3 files changed

+87
-10
lines changed

src/librustc_typeck/collect.rs

+45-7
Original file line numberDiff line numberDiff line change
@@ -364,14 +364,52 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
364364
);
365365

366366
match self.node() {
367-
hir::Node::Field(_)
368-
| hir::Node::Variant(_)
369-
| hir::Node::Ctor(_)
370-
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(..), .. })
371-
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(..), .. })
372-
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(..), .. }) => {
373-
// The suggestion is only valid if this is not an ADT.
367+
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
368+
let item =
369+
self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id()));
370+
match &item.kind {
371+
hir::ItemKind::Enum(_, generics)
372+
| hir::ItemKind::Struct(_, generics)
373+
| hir::ItemKind::Union(_, generics) => {
374+
// FIXME: look for an appropriate lt name if `'a` is already used
375+
let (lt_sp, sugg) = match &generics.params[..] {
376+
[] => (generics.span, "<'a>".to_string()),
377+
[bound, ..] => (bound.span.shrink_to_lo(), "'a, ".to_string()),
378+
};
379+
let suggestions = vec![
380+
(lt_sp, sugg),
381+
(
382+
span,
383+
format!(
384+
"{}::{}",
385+
// Replace the existing lifetimes with a new named lifetime.
386+
self.tcx
387+
.replace_late_bound_regions(&poly_trait_ref, |_| {
388+
self.tcx.mk_region(ty::ReEarlyBound(
389+
ty::EarlyBoundRegion {
390+
def_id: item_def_id,
391+
index: 0,
392+
name: Symbol::intern("'a"),
393+
},
394+
))
395+
})
396+
.0,
397+
item_segment.ident
398+
),
399+
),
400+
];
401+
err.multipart_suggestion(
402+
"use a fully qualified path with explicit lifetimes",
403+
suggestions,
404+
Applicability::MaybeIncorrect,
405+
);
406+
}
407+
_ => {}
408+
}
374409
}
410+
hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(..), .. })
411+
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(..), .. })
412+
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(..), .. }) => {}
375413
hir::Node::Item(_)
376414
| hir::Node::ForeignItem(_)
377415
| hir::Node::TraitItem(_)

src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,25 @@ pub trait Foo<T> {
77
fn get(&self, t: T) -> Self::A;
88
}
99

10-
struct SomeStruct<I : for<'x> Foo<&'x isize>> {
10+
struct SomeStruct<I: for<'x> Foo<&'x isize>> {
1111
field: I::A
1212
//~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
1313
}
1414

15+
enum SomeEnum<I: for<'x> Foo<&'x isize>> {
16+
TupleVariant(I::A),
17+
//~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
18+
StructVariant { field: I::A },
19+
//~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
20+
}
21+
1522
// FIXME(eddyb) This one doesn't even compile because of the unsupported syntax.
1623

1724
// struct AnotherStruct<I : for<'x> Foo<&'x isize>> {
1825
// field: <I as for<'y> Foo<&'y isize>>::A
1926
// }
2027

21-
struct YetAnotherStruct<'a, I : for<'x> Foo<&'x isize>> {
28+
struct YetAnotherStruct<'a, I: for<'x> Foo<&'x isize>> {
2229
field: <I as Foo<&'a isize>>::A
2330
}
2431

src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr

+33-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,38 @@ error[E0212]: cannot extract an associated type from a higher-ranked trait bound
33
|
44
LL | field: I::A
55
| ^^^^
6+
|
7+
help: use a fully qualified path with explicit lifetimes
8+
|
9+
LL | struct SomeStruct<'a, I: for<'x> Foo<&'x isize>> {
10+
LL | field: <I as Foo<&'a isize>>::A
11+
|
12+
13+
error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context
14+
--> $DIR/associated-types-project-from-hrtb-in-struct.rs:16:18
15+
|
16+
LL | TupleVariant(I::A),
17+
| ^^^^
18+
|
19+
help: use a fully qualified path with explicit lifetimes
20+
|
21+
LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> {
22+
LL | TupleVariant(<I as Foo<&'a isize>>::A),
23+
|
24+
25+
error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context
26+
--> $DIR/associated-types-project-from-hrtb-in-struct.rs:18:28
27+
|
28+
LL | StructVariant { field: I::A },
29+
| ^^^^
30+
|
31+
help: use a fully qualified path with explicit lifetimes
32+
|
33+
LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> {
34+
LL | TupleVariant(I::A),
35+
LL |
36+
LL | StructVariant { field: <I as Foo<&'a isize>>::A },
37+
|
638

7-
error: aborting due to previous error
39+
error: aborting due to 3 previous errors
840

0 commit comments

Comments
 (0)