diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index f8e2f0cafff..345e5184e84 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -2398,6 +2398,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { lifetime_refs.len(), &lifetime_names, self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()), + &self.missing_named_lifetime_spots, ); } @@ -2908,19 +2909,80 @@ fn add_missing_lifetime_specifiers_label( count: usize, lifetime_names: &FxHashSet, snippet: Option<&str>, + missing_named_lifetime_spots: &[&hir::Generics<'_>], ) { if count > 1 { err.span_label(span, format!("expected {} lifetime parameters", count)); - } else if let (1, Some(name), Some("&")) = - (lifetime_names.len(), lifetime_names.iter().next(), snippet) - { - err.span_suggestion( - span, - "consider using the named lifetime", - format!("&{} ", name), - Applicability::MaybeIncorrect, - ); } else { - err.span_label(span, "expected lifetime parameter"); + let mut introduce_suggestion = vec![]; + if let Some(generics) = missing_named_lifetime_spots.iter().last() { + introduce_suggestion.push(match &generics.params { + [] => (generics.span, "<'lifetime>".to_string()), + [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()), + }); + } + + match (lifetime_names.len(), lifetime_names.iter().next(), snippet) { + (1, Some(name), Some("&")) => { + err.span_suggestion( + span, + "consider using the named lifetime", + format!("&{} ", name), + Applicability::MaybeIncorrect, + ); + } + (1, Some(name), Some("'_")) => { + err.span_suggestion( + span, + "consider using the named lifetime", + name.to_string(), + Applicability::MaybeIncorrect, + ); + } + (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { + err.span_suggestion( + span, + "consider using the named lifetime", + format!("{}<{}>", snippet, name), + Applicability::MaybeIncorrect, + ); + } + (0, _, Some("&")) => { + err.span_label(span, "expected named lifetime parameter"); + if !introduce_suggestion.is_empty() { + introduce_suggestion.push((span, "&'lifetime ".to_string())); + err.multipart_suggestion( + "consider introducing a named lifetime", + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + } + } + (0, _, Some("'_")) => { + err.span_label(span, "expected named lifetime parameter"); + if !introduce_suggestion.is_empty() { + introduce_suggestion.push((span, "'lifetime".to_string())); + err.multipart_suggestion( + "consider introducing a named lifetime", + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + } + } + (0, _, Some(snippet)) if !snippet.ends_with(">") => { + err.span_label(span, "expected named lifetime parameter"); + if !introduce_suggestion.is_empty() { + introduce_suggestion.push((span, format!("{}<'lifetime>", snippet))); + err.multipart_suggestion( + "consider introducing a named lifetime", + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + } + } + _ => { + err.span_label(span, "expected lifetime parameter"); + } + } } } diff --git a/src/test/ui/error-codes/E0106.rs b/src/test/ui/error-codes/E0106.rs index d6537d12363..cc3438727a8 100644 --- a/src/test/ui/error-codes/E0106.rs +++ b/src/test/ui/error-codes/E0106.rs @@ -16,7 +16,7 @@ struct Buzz<'a, 'b>(&'a str, &'b str); struct Quux { baz: Baz, //~^ ERROR E0106 - //~| expected lifetime parameter + //~| expected named lifetime parameter buzz: Buzz, //~^ ERROR E0106 //~| expected 2 lifetime parameters diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index cea9581e701..bb7efa90c80 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -2,25 +2,49 @@ error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:2:8 | LL | x: &bool, - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Foo<'lifetime> { +LL | x: &'lifetime bool, + | error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:7:7 | LL | B(&bool), - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | enum Bar<'lifetime> { +LL | A(u8), +LL | B(&'lifetime bool), + | error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:10:14 | LL | type MyStr = &str; - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | type MyStr<'lifetime> = &'lifetime str; + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:17:10 | LL | baz: Baz, - | ^^^ expected lifetime parameter + | ^^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Quux<'lifetime> { +LL | baz: Baz<'lifetime>, + | error[E0106]: missing lifetime specifiers --> $DIR/E0106.rs:20:11 diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr index 492ca872187..0835970df40 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -2,13 +2,23 @@ error[E0106]: missing lifetime specifier --> $DIR/assoc-type.rs:11:19 | LL | type Output = &i32; - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | type Output<'lifetime> = &'lifetime i32; + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/assoc-type.rs:16:20 | LL | type Output = &'_ i32; - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | type Output<'lifetime> = &'lifetime i32; + | ^^^^^^^^^^^ ^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr index 9579abb76b3..32507e21d27 100644 --- a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr +++ b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr @@ -2,7 +2,12 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-61124-anon-lifetime-in-struct-declaration.rs:8:19 | LL | struct Heartbreak(Betrayal); - | ^^^^^^^^ expected lifetime parameter + | ^^^^^^^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Heartbreak<'lifetime>(Betrayal<'lifetime>); + | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index c85ce0eb3a7..51a8aabb483 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -2,17 +2,25 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:3:28 | LL | type Foo = fn(&u8, &u8) -> &u8; - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = 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 +help: consider introducing a named lifetime + | +LL | type Foo<'lifetime> = fn(&u8, &u8) -> &'lifetime u8; + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:5:27 | LL | fn bar &u8>(f: &F) {} - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = 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 +help: consider introducing a named lifetime + | +LL | fn bar<'lifetime, F: Fn(&u8, &u8) -> &'lifetime u8>(f: &F) {} + | ^^^^^^^^^^ ^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr index 6d7c1b0c43f..8396c932c5b 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:1:62 | LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = 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 +help: consider introducing a named lifetime + | +LL | fn parse_type<'lifetime>(iter: Box+'static>) -> &'lifetime str { iter.next() } + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:4:40 diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index c53129b7f29..64f89496caa 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -2,25 +2,37 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:9:24 | LL | fn f(a: &S, b: i32) -> &i32 { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = 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 +help: consider introducing a named lifetime + | +LL | fn f<'lifetime>(a: &S, b: i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:14:34 | LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = 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` +help: consider introducing a named lifetime + | +LL | fn g<'lifetime>(a: &S, b: bool, c: &i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:19:44 | LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = 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` +help: consider introducing a named lifetime + | +LL | fn h<'lifetime>(a: &bool, b: bool, c: &S, d: &i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index 3f7c3934a0b..075ea3c691f 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -10,17 +10,25 @@ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33 | LL | fn g(_x: &isize, _y: &isize) -> &isize { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y` +help: consider introducing a named lifetime + | +LL | fn g<'lifetime>(_x: &isize, _y: &isize) -> &'lifetime isize { + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19 | LL | fn h(_x: &Foo) -> &isize { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = 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 +help: consider introducing a named lifetime + | +LL | fn h<'lifetime>(_x: &Foo) -> &'lifetime isize { + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20 diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr index a4e0d71a3fa..f95b4cb16be 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/ex1b-return-no-names-if-else.rs:1:29 | LL | fn foo(x: &i32, y: &i32) -> &i32 { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` +help: consider introducing a named lifetime + | +LL | fn foo<'lifetime>(x: &i32, y: &i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/proc-macro/item-error.stderr b/src/test/ui/proc-macro/item-error.stderr index e801c26c43b..19bbadbcd41 100644 --- a/src/test/ui/proc-macro/item-error.stderr +++ b/src/test/ui/proc-macro/item-error.stderr @@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/item-error.rs:10:8 | LL | a: &u64 - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct A<'lifetime> { +LL | a: &'lifetime u64 + | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-enums-anon.stderr b/src/test/ui/regions/regions-in-enums-anon.stderr index ae06e7653db..6e653452f55 100644 --- a/src/test/ui/regions/regions-in-enums-anon.stderr +++ b/src/test/ui/regions/regions-in-enums-anon.stderr @@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/regions-in-enums-anon.rs:4:9 | LL | Bar(&isize) - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | enum Foo<'lifetime> { +LL | Bar(&'lifetime isize) + | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-structs-anon.stderr b/src/test/ui/regions/regions-in-structs-anon.stderr index a1d4ebb597b..b40990e3edb 100644 --- a/src/test/ui/regions/regions-in-structs-anon.stderr +++ b/src/test/ui/regions/regions-in-structs-anon.stderr @@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/regions-in-structs-anon.rs:4:8 | LL | x: &isize - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Foo<'lifetime> { +LL | x: &'lifetime isize + | error: aborting due to previous error diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 171c00ba7b8..5b665e18141 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -2,7 +2,7 @@ error[E0106]: missing lifetime specifier --> $DIR/rfc1623.rs:8:42 | LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = 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 @@ -10,7 +10,7 @@ error[E0106]: missing lifetime specifier --> $DIR/rfc1623.rs:10:39 | LL | &(non_elidable as fn(&u8, &u8) -> &u8); - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = 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 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index 9fb9a07166f..3b101bf304a 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -2,9 +2,18 @@ error[E0106]: missing lifetime specifier --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:39 | LL | let _: dyn Foo(&isize, &usize) -> &usize; - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = 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 +help: consider introducing a named lifetime + | +LL | fn main<'lifetime>() { +LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, +LL | dyn Foo(&isize) -> &isize >(); +LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=(&'a isize, &'a isize)>, +LL | dyn Foo(&isize) -> (&isize, &isize) >(); +LL | + ... error: aborting due to previous error diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index b20c23ade2b..c06891d2308 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/dyn-trait-underscore-in-struct.rs:9:24 | LL | x: Box, - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Foo<'lifetime> { +LL | x: Box, + | error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound --> $DIR/dyn-trait-underscore-in-struct.rs:9:12 diff --git a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr index ed61bdfddda..bdfb8ce4d83 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/in-fn-return-illegal.rs:5:30 | LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` +help: consider introducing a named lifetime + | +LL | fn foo<'lifetime>(x: &u32, y: &u32) -> &'lifetime u32 { loop { } } + | ^^^^^^^^^^^ ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/underscore-lifetime/in-struct.stderr b/src/test/ui/underscore-lifetime/in-struct.stderr index 6bbdc71195a..46dc3f899a1 100644 --- a/src/test/ui/underscore-lifetime/in-struct.stderr +++ b/src/test/ui/underscore-lifetime/in-struct.stderr @@ -2,13 +2,25 @@ error[E0106]: missing lifetime specifier --> $DIR/in-struct.rs:6:9 | LL | x: &'_ u32, - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Foo<'lifetime> { +LL | x: &'lifetime u32, + | error[E0106]: missing lifetime specifier --> $DIR/in-struct.rs:10:14 | LL | Variant(&'_ u32), - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | enum Bar<'lifetime> { +LL | Variant(&'lifetime u32), + | error: aborting due to 2 previous errors diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index ef9e7e39df0..6c2159bc661 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -14,7 +14,7 @@ error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:2:17 | LL | struct Baz<'a>(&'_ &'a u8); - | ^^ expected lifetime parameter + | ^^ help: consider using the named lifetime: `'a` error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:10:33 @@ -28,9 +28,13 @@ error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:16:35 | LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` +help: consider introducing a named lifetime + | +LL | fn foo2<'lifetime>(_: &'_ u8, y: &'_ u8) -> &'lifetime u8 { y } + | ^^^^^^^^^^^ ^^^^^^^^^ error: aborting due to 5 previous errors