Skip to content

Commit

Permalink
Suggest appropriate syntax on missing lifetime specifier in return type
Browse files Browse the repository at this point in the history
Suggest using `'static` when a lifetime is missing in the return type
with a structured suggestion instead of a note.
  • Loading branch information
estebank committed Oct 22, 2018
1 parent a66dc8a commit e1e52eb
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 34 deletions.
2 changes: 1 addition & 1 deletion src/librustc/hir/lowering.rs
Expand Up @@ -1152,7 +1152,7 @@ impl<'a> LoweringContext<'a> {
TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Rptr(ref region, ref mt) => {
let span = t.span.shrink_to_lo();
let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
let lifetime = match *region {
Some(ref lt) => self.lower_lifetime(lt),
None => self.elided_ref_lifetime(span),
Expand Down
55 changes: 48 additions & 7 deletions src/librustc/middle/resolve_lifetime.rs
Expand Up @@ -2238,7 +2238,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {

if let Some(params) = error {
if lifetime_refs.len() == 1 {
self.report_elision_failure(&mut err, params);
self.report_elision_failure(&mut err, params, span);
}
}

Expand All @@ -2249,6 +2249,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
&mut self,
db: &mut DiagnosticBuilder<'_>,
params: &[ElisionFailureInfo],
span: Span,
) {
let mut m = String::new();
let len = params.len();
Expand Down Expand Up @@ -2304,19 +2305,59 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
"this function's return type contains a borrowed value, but \
there is no value for it to be borrowed from"
);
help!(db, "consider giving it a 'static lifetime");
let msg = "consider giving it a 'static lifetime";
match self.tcx.sess.source_map().span_to_snippet(span) {
Ok(ref snippet) if snippet == "&" => db.span_suggestion_with_applicability(
span,
msg,
"&'static ".to_owned(),
Applicability::MachineApplicable,
),
Ok(ref snippet)
if snippet == "'_" => db.span_suggestion_with_applicability(
span,
msg,
"'static".to_owned(),
Applicability::MachineApplicable,
),
Ok(ref snippet) => db.span_suggestion_with_applicability(
span,
msg,
format!("{} + 'static", snippet),
Applicability::MaybeIncorrect,
),
Err(_) => db.help(msg),
};
} else if elided_len == 0 {
help!(
db,
"this function's return type contains a borrowed value with \
an elided lifetime, but the lifetime cannot be derived from \
the arguments"
);
help!(
db,
"consider giving it an explicit bounded or 'static \
lifetime"
);
let msg = "consider giving it an explicit bounded or 'static lifetime";
match self.tcx.sess.source_map().span_to_snippet(span) {
Ok(ref snippet) if snippet == "&" => db.span_suggestion_with_applicability(
span,
msg,
"&'static ".to_owned(),
Applicability::MachineApplicable,
),
Ok(ref snippet)
if snippet == "'_" => db.span_suggestion_with_applicability(
span,
msg,
"'static".to_owned(),
Applicability::MachineApplicable,
),
Ok(ref snippet) => db.span_suggestion_with_applicability(
span,
msg,
format!("{} + 'static", snippet),
Applicability::MaybeIncorrect,
),
Err(_) => db.help(msg),
};
} else if elided_len == 1 {
help!(
db,
Expand Down
Expand Up @@ -2,10 +2,12 @@ error[E0106]: missing lifetime specifier
--> $DIR/bound-lifetime-in-binding-only.rs:62:23
|
LL | fn elision<T: Fn() -> &i32>() {
| ^ expected lifetime parameter
| ^
| |
| expected lifetime parameter
| help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime

error: aborting due to previous error

Expand Down
Expand Up @@ -2,10 +2,12 @@ error[E0106]: missing lifetime specifier
--> $DIR/bound-lifetime-in-return-only.rs:44:23
|
LL | fn elision(_: fn() -> &i32) {
| ^ expected lifetime parameter
| ^
| |
| expected lifetime parameter
| help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime

error: aborting due to previous error

Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/foreign-fn-return-lifetime.fixed
@@ -0,0 +1,18 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// run-rustfix

extern "C" {
pub fn g(_: &u8) -> &u8; // OK
pub fn f() -> &'static u8; //~ ERROR missing lifetime specifier
}

fn main() {}
6 changes: 4 additions & 2 deletions src/test/ui/foreign-fn-return-lifetime.rs
Expand Up @@ -8,9 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// run-rustfix

extern "C" {
fn g(_: &u8) -> &u8; // OK
fn f() -> &u8; //~ ERROR missing lifetime specifier
pub fn g(_: &u8) -> &u8; // OK
pub fn f() -> &u8; //~ ERROR missing lifetime specifier
}

fn main() {}
10 changes: 6 additions & 4 deletions src/test/ui/foreign-fn-return-lifetime.stderr
@@ -1,11 +1,13 @@
error[E0106]: missing lifetime specifier
--> $DIR/foreign-fn-return-lifetime.rs:13:15
--> $DIR/foreign-fn-return-lifetime.rs:15:19
|
LL | fn f() -> &u8; //~ ERROR missing lifetime specifier
| ^ expected lifetime parameter
LL | pub fn f() -> &u8; //~ ERROR missing lifetime specifier
| ^
| |
| expected lifetime parameter
| help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime

error: aborting due to previous error

Expand Down
6 changes: 4 additions & 2 deletions src/test/ui/issues/issue-13497.stderr
Expand Up @@ -2,10 +2,12 @@ error[E0106]: missing lifetime specifier
--> $DIR/issue-13497.rs:12:5
|
LL | &str //~ ERROR missing lifetime specifier
| ^ expected lifetime parameter
| ^
| |
| expected lifetime parameter
| help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime

error: aborting due to previous error

Expand Down
12 changes: 8 additions & 4 deletions src/test/ui/issues/issue-26638.stderr
Expand Up @@ -10,19 +10,23 @@ error[E0106]: missing lifetime specifier
--> $DIR/issue-26638.rs:14:40
|
LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
| ^ expected lifetime parameter
| ^
| |
| expected lifetime parameter
| help: consider giving it an explicit bounded or 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
= help: consider giving it an explicit bounded or 'static lifetime

error[E0106]: missing lifetime specifier
--> $DIR/issue-26638.rs:17:22
|
LL | fn parse_type_3() -> &str { unimplemented!() }
| ^ expected lifetime parameter
| ^
| |
| expected lifetime parameter
| help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime

error: aborting due to 3 previous errors

Expand Down
Expand Up @@ -2,10 +2,12 @@ error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:12:11
|
LL | fn f() -> &isize { //~ ERROR missing lifetime specifier
| ^ expected lifetime parameter
| ^
| |
| expected lifetime parameter
| help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime

error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:33
Expand All @@ -27,28 +29,34 @@ error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:31:20
|
LL | fn i(_x: isize) -> &isize { //~ ERROR missing lifetime specifier
| ^ expected lifetime parameter
| ^
| |
| expected lifetime parameter
| help: consider giving it an explicit bounded or 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
= help: consider giving it an explicit bounded or 'static lifetime

error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:44:24
|
LL | fn j(_x: StaticStr) -> &isize { //~ ERROR missing lifetime specifier
| ^ expected lifetime parameter
| ^
| |
| expected lifetime parameter
| help: consider giving it an explicit bounded or 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
= help: consider giving it an explicit bounded or 'static lifetime

error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:50:49
|
LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize {
| ^ expected lifetime parameter
| ^
| |
| expected lifetime parameter
| help: consider giving it an explicit bounded or 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
= help: consider giving it an explicit bounded or 'static lifetime

error: aborting due to 6 previous errors

Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs
@@ -0,0 +1,10 @@
trait Future {
type Item;
type Error;
}

use std::error::Error;

fn foo() -> impl Future<Item=(), Error=Box<Error>> {
Ok(())
}
19 changes: 19 additions & 0 deletions src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
@@ -0,0 +1,19 @@
error[E0601]: `main` function not found in crate `lifetime_elision_return_type_trait`
|
= note: consider adding a `main` function to `$DIR/lifetime-elision-return-type-trait.rs`

error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-trait.rs:8:44
|
LL | fn foo() -> impl Future<Item=(), Error=Box<Error>> {
| ^^^^^
| |
| expected lifetime parameter
| help: consider giving it a 'static lifetime: `Error + 'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from

error: aborting due to 2 previous errors

Some errors occurred: E0106, E0601.
For more information about an error, try `rustc --explain E0106`.
Expand Up @@ -26,10 +26,12 @@ error[E0106]: missing lifetime specifier
--> $DIR/underscore-lifetime-binders.rs:24:29
|
LL | fn meh() -> Box<for<'_> Meh<'_>> //~ ERROR cannot be used here
| ^^ expected lifetime parameter
| ^^
| |
| expected lifetime parameter
| help: consider giving it a 'static lifetime: `'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime

error[E0106]: missing lifetime specifier
--> $DIR/underscore-lifetime-binders.rs:30:35
Expand Down

0 comments on commit e1e52eb

Please sign in to comment.