Skip to content

Commit 78d3ea5

Browse files
committed
When encountering an expected named lifetime and none are present, suggest adding one
1 parent 6ba0875 commit 78d3ea5

19 files changed

+229
-39
lines changed

src/librustc_resolve/lifetimes.rs

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2398,6 +2398,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
23982398
lifetime_refs.len(),
23992399
&lifetime_names,
24002400
self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()),
2401+
&self.missing_named_lifetime_spots,
24012402
);
24022403
}
24032404

@@ -2908,19 +2909,80 @@ fn add_missing_lifetime_specifiers_label(
29082909
count: usize,
29092910
lifetime_names: &FxHashSet<ast::Ident>,
29102911
snippet: Option<&str>,
2912+
missing_named_lifetime_spots: &[&hir::Generics<'_>],
29112913
) {
29122914
if count > 1 {
29132915
err.span_label(span, format!("expected {} lifetime parameters", count));
2914-
} else if let (1, Some(name), Some("&")) =
2915-
(lifetime_names.len(), lifetime_names.iter().next(), snippet)
2916-
{
2917-
err.span_suggestion(
2918-
span,
2919-
"consider using the named lifetime",
2920-
format!("&{} ", name),
2921-
Applicability::MaybeIncorrect,
2922-
);
29232916
} else {
2924-
err.span_label(span, "expected lifetime parameter");
2917+
let mut introduce_suggestion = vec![];
2918+
if let Some(generics) = missing_named_lifetime_spots.iter().last() {
2919+
introduce_suggestion.push(match &generics.params {
2920+
[] => (generics.span, "<'lifetime>".to_string()),
2921+
[param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()),
2922+
});
2923+
}
2924+
2925+
match (lifetime_names.len(), lifetime_names.iter().next(), snippet) {
2926+
(1, Some(name), Some("&")) => {
2927+
err.span_suggestion(
2928+
span,
2929+
"consider using the named lifetime",
2930+
format!("&{} ", name),
2931+
Applicability::MaybeIncorrect,
2932+
);
2933+
}
2934+
(1, Some(name), Some("'_")) => {
2935+
err.span_suggestion(
2936+
span,
2937+
"consider using the named lifetime",
2938+
name.to_string(),
2939+
Applicability::MaybeIncorrect,
2940+
);
2941+
}
2942+
(1, Some(name), Some(snippet)) if !snippet.ends_with(">") => {
2943+
err.span_suggestion(
2944+
span,
2945+
"consider using the named lifetime",
2946+
format!("{}<{}>", snippet, name),
2947+
Applicability::MaybeIncorrect,
2948+
);
2949+
}
2950+
(0, _, Some("&")) => {
2951+
err.span_label(span, "expected named lifetime parameter");
2952+
if !introduce_suggestion.is_empty() {
2953+
introduce_suggestion.push((span, "&'lifetime ".to_string()));
2954+
err.multipart_suggestion(
2955+
"consider introducing a named lifetime",
2956+
introduce_suggestion,
2957+
Applicability::MaybeIncorrect,
2958+
);
2959+
}
2960+
}
2961+
(0, _, Some("'_")) => {
2962+
err.span_label(span, "expected named lifetime parameter");
2963+
if !introduce_suggestion.is_empty() {
2964+
introduce_suggestion.push((span, "'lifetime".to_string()));
2965+
err.multipart_suggestion(
2966+
"consider introducing a named lifetime",
2967+
introduce_suggestion,
2968+
Applicability::MaybeIncorrect,
2969+
);
2970+
}
2971+
}
2972+
(0, _, Some(snippet)) if !snippet.ends_with(">") => {
2973+
err.span_label(span, "expected named lifetime parameter");
2974+
if !introduce_suggestion.is_empty() {
2975+
introduce_suggestion.push((span, format!("{}<'lifetime>", snippet)));
2976+
err.multipart_suggestion(
2977+
"consider introducing a named lifetime",
2978+
introduce_suggestion,
2979+
Applicability::MaybeIncorrect,
2980+
);
2981+
}
2982+
}
2983+
_ => {
2984+
err.span_label(span, "expected lifetime parameter");
2985+
}
2986+
}
29252987
}
29262988
}

src/test/ui/error-codes/E0106.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct Buzz<'a, 'b>(&'a str, &'b str);
1616
struct Quux {
1717
baz: Baz,
1818
//~^ ERROR E0106
19-
//~| expected lifetime parameter
19+
//~| expected named lifetime parameter
2020
buzz: Buzz,
2121
//~^ ERROR E0106
2222
//~| expected 2 lifetime parameters

src/test/ui/error-codes/E0106.stderr

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,49 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/E0106.rs:2:8
33
|
44
LL | x: &bool,
5-
| ^ expected lifetime parameter
5+
| ^ expected named lifetime parameter
6+
|
7+
help: consider introducing a named lifetime
8+
|
9+
LL | struct Foo<'lifetime> {
10+
LL | x: &'lifetime bool,
11+
|
612

713
error[E0106]: missing lifetime specifier
814
--> $DIR/E0106.rs:7:7
915
|
1016
LL | B(&bool),
11-
| ^ expected lifetime parameter
17+
| ^ expected named lifetime parameter
18+
|
19+
help: consider introducing a named lifetime
20+
|
21+
LL | enum Bar<'lifetime> {
22+
LL | A(u8),
23+
LL | B(&'lifetime bool),
24+
|
1225

1326
error[E0106]: missing lifetime specifier
1427
--> $DIR/E0106.rs:10:14
1528
|
1629
LL | type MyStr = &str;
17-
| ^ expected lifetime parameter
30+
| ^ expected named lifetime parameter
31+
|
32+
help: consider introducing a named lifetime
33+
|
34+
LL | type MyStr<'lifetime> = &'lifetime str;
35+
| ^^^^^^^^^^^ ^^^^^^^^^^
1836

1937
error[E0106]: missing lifetime specifier
2038
--> $DIR/E0106.rs:17:10
2139
|
2240
LL | baz: Baz,
23-
| ^^^ expected lifetime parameter
41+
| ^^^ expected named lifetime parameter
42+
|
43+
help: consider introducing a named lifetime
44+
|
45+
LL | struct Quux<'lifetime> {
46+
LL | baz: Baz<'lifetime>,
47+
|
2448

2549
error[E0106]: missing lifetime specifiers
2650
--> $DIR/E0106.rs:20:11

src/test/ui/impl-header-lifetime-elision/assoc-type.stderr

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,23 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/assoc-type.rs:11:19
33
|
44
LL | type Output = &i32;
5-
| ^ expected lifetime parameter
5+
| ^ expected named lifetime parameter
6+
|
7+
help: consider introducing a named lifetime
8+
|
9+
LL | type Output<'lifetime> = &'lifetime i32;
10+
| ^^^^^^^^^^^ ^^^^^^^^^^
611

712
error[E0106]: missing lifetime specifier
813
--> $DIR/assoc-type.rs:16:20
914
|
1015
LL | type Output = &'_ i32;
11-
| ^^ expected lifetime parameter
16+
| ^^ expected named lifetime parameter
17+
|
18+
help: consider introducing a named lifetime
19+
|
20+
LL | type Output<'lifetime> = &'lifetime i32;
21+
| ^^^^^^^^^^^ ^^^^^^^^^
1222

1323
error: aborting due to 2 previous errors
1424

src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/issue-61124-anon-lifetime-in-struct-declaration.rs:8:19
33
|
44
LL | struct Heartbreak(Betrayal);
5-
| ^^^^^^^^ expected lifetime parameter
5+
| ^^^^^^^^ expected named lifetime parameter
6+
|
7+
help: consider introducing a named lifetime
8+
|
9+
LL | struct Heartbreak<'lifetime>(Betrayal<'lifetime>);
10+
| ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
611

712
error: aborting due to previous error
813

src/test/ui/issues/issue-19707.stderr

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,25 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/issue-19707.rs:3:28
33
|
44
LL | type Foo = fn(&u8, &u8) -> &u8;
5-
| ^ expected lifetime parameter
5+
| ^ expected named lifetime parameter
66
|
77
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
8+
help: consider introducing a named lifetime
9+
|
10+
LL | type Foo<'lifetime> = fn(&u8, &u8) -> &'lifetime u8;
11+
| ^^^^^^^^^^^ ^^^^^^^^^^
812

913
error[E0106]: missing lifetime specifier
1014
--> $DIR/issue-19707.rs:5:27
1115
|
1216
LL | fn bar<F: Fn(&u8, &u8) -> &u8>(f: &F) {}
13-
| ^ expected lifetime parameter
17+
| ^ expected named lifetime parameter
1418
|
1519
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
20+
help: consider introducing a named lifetime
21+
|
22+
LL | fn bar<'lifetime, F: Fn(&u8, &u8) -> &'lifetime u8>(f: &F) {}
23+
| ^^^^^^^^^^ ^^^^^^^^^^
1624

1725
error: aborting due to 2 previous errors
1826

src/test/ui/issues/issue-26638.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/issue-26638.rs:1:62
33
|
44
LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
5-
| ^ expected lifetime parameter
5+
| ^ expected named lifetime parameter
66
|
77
= help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from
8+
help: consider introducing a named lifetime
9+
|
10+
LL | fn parse_type<'lifetime>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'lifetime str { iter.next() }
11+
| ^^^^^^^^^^^ ^^^^^^^^^^
812

913
error[E0106]: missing lifetime specifier
1014
--> $DIR/issue-26638.rs:4:40

src/test/ui/issues/issue-30255.stderr

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,37 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/issue-30255.rs:9:24
33
|
44
LL | fn f(a: &S, b: i32) -> &i32 {
5-
| ^ expected lifetime parameter
5+
| ^ expected named lifetime parameter
66
|
77
= help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from
8+
help: consider introducing a named lifetime
9+
|
10+
LL | fn f<'lifetime>(a: &S, b: i32) -> &'lifetime i32 {
11+
| ^^^^^^^^^^^ ^^^^^^^^^^
812

913
error[E0106]: missing lifetime specifier
1014
--> $DIR/issue-30255.rs:14:34
1115
|
1216
LL | fn g(a: &S, b: bool, c: &i32) -> &i32 {
13-
| ^ expected lifetime parameter
17+
| ^ expected named lifetime parameter
1418
|
1519
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c`
20+
help: consider introducing a named lifetime
21+
|
22+
LL | fn g<'lifetime>(a: &S, b: bool, c: &i32) -> &'lifetime i32 {
23+
| ^^^^^^^^^^^ ^^^^^^^^^^
1624

1725
error[E0106]: missing lifetime specifier
1826
--> $DIR/issue-30255.rs:19:44
1927
|
2028
LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 {
21-
| ^ expected lifetime parameter
29+
| ^ expected named lifetime parameter
2230
|
2331
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d`
32+
help: consider introducing a named lifetime
33+
|
34+
LL | fn h<'lifetime>(a: &bool, b: bool, c: &S, d: &i32) -> &'lifetime i32 {
35+
| ^^^^^^^^^^^ ^^^^^^^^^^
2436

2537
error: aborting due to 3 previous errors
2638

src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,25 @@ error[E0106]: missing lifetime specifier
1010
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33
1111
|
1212
LL | fn g(_x: &isize, _y: &isize) -> &isize {
13-
| ^ expected lifetime parameter
13+
| ^ expected named lifetime parameter
1414
|
1515
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y`
16+
help: consider introducing a named lifetime
17+
|
18+
LL | fn g<'lifetime>(_x: &isize, _y: &isize) -> &'lifetime isize {
19+
| ^^^^^^^^^^^ ^^^^^^^^^^
1620

1721
error[E0106]: missing lifetime specifier
1822
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19
1923
|
2024
LL | fn h(_x: &Foo) -> &isize {
21-
| ^ expected lifetime parameter
25+
| ^ expected named lifetime parameter
2226
|
2327
= help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from
28+
help: consider introducing a named lifetime
29+
|
30+
LL | fn h<'lifetime>(_x: &Foo) -> &'lifetime isize {
31+
| ^^^^^^^^^^^ ^^^^^^^^^^
2432

2533
error[E0106]: missing lifetime specifier
2634
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20

src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/ex1b-return-no-names-if-else.rs:1:29
33
|
44
LL | fn foo(x: &i32, y: &i32) -> &i32 {
5-
| ^ expected lifetime parameter
5+
| ^ expected named lifetime parameter
66
|
77
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
8+
help: consider introducing a named lifetime
9+
|
10+
LL | fn foo<'lifetime>(x: &i32, y: &i32) -> &'lifetime i32 {
11+
| ^^^^^^^^^^^ ^^^^^^^^^^
812

913
error: aborting due to previous error
1014

src/test/ui/proc-macro/item-error.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/item-error.rs:10:8
33
|
44
LL | a: &u64
5-
| ^ expected lifetime parameter
5+
| ^ expected named lifetime parameter
6+
|
7+
help: consider introducing a named lifetime
8+
|
9+
LL | struct A<'lifetime> {
10+
LL | a: &'lifetime u64
11+
|
612

713
error: aborting due to previous error
814

src/test/ui/regions/regions-in-enums-anon.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/regions-in-enums-anon.rs:4:9
33
|
44
LL | Bar(&isize)
5-
| ^ expected lifetime parameter
5+
| ^ expected named lifetime parameter
6+
|
7+
help: consider introducing a named lifetime
8+
|
9+
LL | enum Foo<'lifetime> {
10+
LL | Bar(&'lifetime isize)
11+
|
612

713
error: aborting due to previous error
814

src/test/ui/regions/regions-in-structs-anon.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/regions-in-structs-anon.rs:4:8
33
|
44
LL | x: &isize
5-
| ^ expected lifetime parameter
5+
| ^ expected named lifetime parameter
6+
|
7+
help: consider introducing a named lifetime
8+
|
9+
LL | struct Foo<'lifetime> {
10+
LL | x: &'lifetime isize
11+
|
612

713
error: aborting due to previous error
814

src/test/ui/rfc1623.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/rfc1623.rs:8:42
33
|
44
LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
5-
| ^ expected lifetime parameter
5+
| ^ expected named lifetime parameter
66
|
77
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
88

99
error[E0106]: missing lifetime specifier
1010
--> $DIR/rfc1623.rs:10:39
1111
|
1212
LL | &(non_elidable as fn(&u8, &u8) -> &u8);
13-
| ^ expected lifetime parameter
13+
| ^ expected named lifetime parameter
1414
|
1515
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
1616

0 commit comments

Comments
 (0)