Skip to content

Commit 156fec0

Browse files
authored
Rollup merge of rust-lang#59146 - estebank:suggest-return-lt, r=varkor
Suggest return lifetime when there's only one named lifetime Fix rust-lang#29094.
2 parents 4e992e0 + 0ea9b58 commit 156fec0

File tree

3 files changed

+76
-5
lines changed

3 files changed

+76
-5
lines changed

src/librustc/middle/resolve_lifetime.rs

+41-5
Original file line numberDiff line numberDiff line change
@@ -2299,19 +2299,26 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
22992299
let span = lifetime_refs[0].span;
23002300
let mut late_depth = 0;
23012301
let mut scope = self.scope;
2302+
let mut lifetime_names = FxHashSet::default();
23022303
let error = loop {
23032304
match *scope {
23042305
// Do not assign any resolution, it will be inferred.
23052306
Scope::Body { .. } => return,
23062307

23072308
Scope::Root => break None,
23082309

2309-
Scope::Binder { s, .. } => {
2310+
Scope::Binder { s, ref lifetimes, .. } => {
2311+
// collect named lifetimes for suggestions
2312+
for name in lifetimes.keys() {
2313+
if let hir::ParamName::Plain(name) = name {
2314+
lifetime_names.insert(*name);
2315+
}
2316+
}
23102317
late_depth += 1;
23112318
scope = s;
23122319
}
23132320

2314-
Scope::Elision { ref elide, .. } => {
2321+
Scope::Elision { ref elide, ref s, .. } => {
23152322
let lifetime = match *elide {
23162323
Elide::FreshLateAnon(ref counter) => {
23172324
for lifetime_ref in lifetime_refs {
@@ -2321,7 +2328,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
23212328
return;
23222329
}
23232330
Elide::Exact(l) => l.shifted(late_depth),
2324-
Elide::Error(ref e) => break Some(e),
2331+
Elide::Error(ref e) => {
2332+
if let Scope::Binder { ref lifetimes, .. } = s {
2333+
// collect named lifetimes for suggestions
2334+
for name in lifetimes.keys() {
2335+
if let hir::ParamName::Plain(name) = name {
2336+
lifetime_names.insert(*name);
2337+
}
2338+
}
2339+
}
2340+
break Some(e);
2341+
}
23252342
};
23262343
for lifetime_ref in lifetime_refs {
23272344
self.insert_lifetime(lifetime_ref, lifetime);
@@ -2344,7 +2361,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
23442361
}
23452362
}
23462363
if add_label {
2347-
add_missing_lifetime_specifiers_label(&mut err, span, lifetime_refs.len());
2364+
add_missing_lifetime_specifiers_label(
2365+
&mut err,
2366+
span,
2367+
lifetime_refs.len(),
2368+
&lifetime_names,
2369+
self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()),
2370+
);
23482371
}
23492372

23502373
err.emit();
@@ -2885,10 +2908,23 @@ fn add_missing_lifetime_specifiers_label(
28852908
err: &mut DiagnosticBuilder<'_>,
28862909
span: Span,
28872910
count: usize,
2911+
lifetime_names: &FxHashSet<ast::Ident>,
2912+
snippet: Option<&str>,
28882913
) {
28892914
if count > 1 {
28902915
err.span_label(span, format!("expected {} lifetime parameters", count));
2916+
} else if let (1, Some(name), Some("&")) = (
2917+
lifetime_names.len(),
2918+
lifetime_names.iter().next(),
2919+
snippet,
2920+
) {
2921+
err.span_suggestion(
2922+
span,
2923+
"consider using the named lifetime",
2924+
format!("&{} ", name),
2925+
Applicability::MaybeIncorrect,
2926+
);
28912927
} else {
28922928
err.span_label(span, "expected lifetime parameter");
2893-
};
2929+
}
28942930
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
struct Thing<'a>(&'a ());
2+
struct Foo<'a>(&usize);
3+
//~^ ERROR missing lifetime specifier
4+
5+
fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
6+
//~^ ERROR missing lifetime specifier
7+
fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() }
8+
//~^ ERROR missing lifetime specifier
9+
10+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0106]: missing lifetime specifier
2+
--> $DIR/return-without-lifetime.rs:2:16
3+
|
4+
LL | struct Foo<'a>(&usize);
5+
| ^ help: consider using the named lifetime: `&'a`
6+
7+
error[E0106]: missing lifetime specifier
8+
--> $DIR/return-without-lifetime.rs:5:34
9+
|
10+
LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
11+
| ^ help: consider using the named lifetime: `&'a`
12+
|
13+
= help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from
14+
15+
error[E0106]: missing lifetime specifier
16+
--> $DIR/return-without-lifetime.rs:7:35
17+
|
18+
LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() }
19+
| ^ help: consider using the named lifetime: `&'a`
20+
|
21+
= help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from
22+
23+
error: aborting due to 3 previous errors
24+
25+
For more information about this error, try `rustc --explain E0106`.

0 commit comments

Comments
 (0)