Rollup merge of #59146 - estebank:suggest-return-lt, r=varkor
Suggest return lifetime when there's only one named lifetime Fix #29094.
This commit is contained in:
commit
bbe5f3d08b
3 changed files with 76 additions and 5 deletions
|
@ -2299,6 +2299,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
let span = lifetime_refs[0].span;
|
let span = lifetime_refs[0].span;
|
||||||
let mut late_depth = 0;
|
let mut late_depth = 0;
|
||||||
let mut scope = self.scope;
|
let mut scope = self.scope;
|
||||||
|
let mut lifetime_names = FxHashSet::default();
|
||||||
let error = loop {
|
let error = loop {
|
||||||
match *scope {
|
match *scope {
|
||||||
// Do not assign any resolution, it will be inferred.
|
// Do not assign any resolution, it will be inferred.
|
||||||
|
@ -2306,12 +2307,18 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
|
|
||||||
Scope::Root => break None,
|
Scope::Root => break None,
|
||||||
|
|
||||||
Scope::Binder { s, .. } => {
|
Scope::Binder { s, ref lifetimes, .. } => {
|
||||||
|
// collect named lifetimes for suggestions
|
||||||
|
for name in lifetimes.keys() {
|
||||||
|
if let hir::ParamName::Plain(name) = name {
|
||||||
|
lifetime_names.insert(*name);
|
||||||
|
}
|
||||||
|
}
|
||||||
late_depth += 1;
|
late_depth += 1;
|
||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope::Elision { ref elide, .. } => {
|
Scope::Elision { ref elide, ref s, .. } => {
|
||||||
let lifetime = match *elide {
|
let lifetime = match *elide {
|
||||||
Elide::FreshLateAnon(ref counter) => {
|
Elide::FreshLateAnon(ref counter) => {
|
||||||
for lifetime_ref in lifetime_refs {
|
for lifetime_ref in lifetime_refs {
|
||||||
|
@ -2321,7 +2328,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Elide::Exact(l) => l.shifted(late_depth),
|
Elide::Exact(l) => l.shifted(late_depth),
|
||||||
Elide::Error(ref e) => break Some(e),
|
Elide::Error(ref e) => {
|
||||||
|
if let Scope::Binder { ref lifetimes, .. } = s {
|
||||||
|
// collect named lifetimes for suggestions
|
||||||
|
for name in lifetimes.keys() {
|
||||||
|
if let hir::ParamName::Plain(name) = name {
|
||||||
|
lifetime_names.insert(*name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break Some(e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
for lifetime_ref in lifetime_refs {
|
for lifetime_ref in lifetime_refs {
|
||||||
self.insert_lifetime(lifetime_ref, lifetime);
|
self.insert_lifetime(lifetime_ref, lifetime);
|
||||||
|
@ -2344,7 +2361,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if add_label {
|
if add_label {
|
||||||
add_missing_lifetime_specifiers_label(&mut err, span, lifetime_refs.len());
|
add_missing_lifetime_specifiers_label(
|
||||||
|
&mut err,
|
||||||
|
span,
|
||||||
|
lifetime_refs.len(),
|
||||||
|
&lifetime_names,
|
||||||
|
self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
err.emit();
|
err.emit();
|
||||||
|
@ -2885,10 +2908,23 @@ fn add_missing_lifetime_specifiers_label(
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
count: usize,
|
count: usize,
|
||||||
|
lifetime_names: &FxHashSet<ast::Ident>,
|
||||||
|
snippet: Option<&str>,
|
||||||
) {
|
) {
|
||||||
if count > 1 {
|
if count > 1 {
|
||||||
err.span_label(span, format!("expected {} lifetime parameters", count));
|
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 {
|
} else {
|
||||||
err.span_label(span, "expected lifetime parameter");
|
err.span_label(span, "expected lifetime parameter");
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/test/ui/suggestions/return-without-lifetime.rs
Normal file
10
src/test/ui/suggestions/return-without-lifetime.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
struct Thing<'a>(&'a ());
|
||||||
|
struct Foo<'a>(&usize);
|
||||||
|
//~^ ERROR missing lifetime specifier
|
||||||
|
|
||||||
|
fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
|
||||||
|
//~^ ERROR missing lifetime specifier
|
||||||
|
fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() }
|
||||||
|
//~^ ERROR missing lifetime specifier
|
||||||
|
|
||||||
|
fn main() {}
|
25
src/test/ui/suggestions/return-without-lifetime.stderr
Normal file
25
src/test/ui/suggestions/return-without-lifetime.stderr
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/return-without-lifetime.rs:2:16
|
||||||
|
|
|
||||||
|
LL | struct Foo<'a>(&usize);
|
||||||
|
| ^ help: consider using the named lifetime: `&'a`
|
||||||
|
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/return-without-lifetime.rs:5:34
|
||||||
|
|
|
||||||
|
LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
|
||||||
|
| ^ help: consider using the named lifetime: `&'a`
|
||||||
|
|
|
||||||
|
= 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
|
||||||
|
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/return-without-lifetime.rs:7:35
|
||||||
|
|
|
||||||
|
LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() }
|
||||||
|
| ^ help: consider using the named lifetime: `&'a`
|
||||||
|
|
|
||||||
|
= 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
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0106`.
|
Loading…
Add table
Add a link
Reference in a new issue