Skip to content

Commit 4bbd5d0

Browse files
committed
Account for fn() types in lifetime suggestions
1 parent 9af8a38 commit 4bbd5d0

20 files changed

+210
-153
lines changed

src/librustc_resolve/diagnostics.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use syntax::print::pprust;
1919
use syntax::util::lev_distance::find_best_match_for_name;
2020

2121
use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
22-
use crate::lifetimes::{ElisionFailureInfo, HRLTSpanType, MissingLifetimeSpot};
22+
use crate::lifetimes::{ElisionFailureInfo, ForLifetimeSpanType, MissingLifetimeSpot};
2323
use crate::path_names_to_string;
2424
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind};
2525
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
@@ -1490,23 +1490,35 @@ crate fn add_missing_lifetime_specifiers_label(
14901490
let should_break;
14911491
introduce_suggestion.push(match missing {
14921492
MissingLifetimeSpot::Generics(generics) => {
1493-
msg = "consider introducing a named lifetime parameter";
1493+
msg = "consider introducing a named lifetime parameter".to_string();
14941494
should_break = true;
14951495
match &generics.params {
14961496
[] => (generics.span, "<'a>".to_string()),
14971497
[param, ..] => (param.span.shrink_to_lo(), "'a, ".to_string()),
14981498
}
14991499
}
15001500
MissingLifetimeSpot::HRLT { span, span_type } => {
1501-
msg = "consider introducing a higher-ranked lifetime";
1501+
msg = format!(
1502+
"consider making the {} lifetime-generic with a new `'a` lifetime",
1503+
match span_type {
1504+
ForLifetimeSpanType::BoundEmpty
1505+
| ForLifetimeSpanType::BoundTail => "bound",
1506+
ForLifetimeSpanType::TypeEmpty | ForLifetimeSpanType::TypeTail =>
1507+
"type",
1508+
}
1509+
);
15021510
should_break = false;
15031511
err.note(
15041512
"for more information on higher-ranked lifetimes, visit \
15051513
https://doc.rust-lang.org/nomicon/hrtb.html",
15061514
);
15071515
let suggestion = match span_type {
1508-
HRLTSpanType::Empty => "for<'a> ",
1509-
HRLTSpanType::Tail => ", 'a",
1516+
ForLifetimeSpanType::BoundEmpty | ForLifetimeSpanType::TypeEmpty => {
1517+
"for<'a> "
1518+
}
1519+
ForLifetimeSpanType::BoundTail | ForLifetimeSpanType::TypeTail => {
1520+
", 'a"
1521+
}
15101522
};
15111523
(*span, suggestion.to_string())
15121524
}
@@ -1523,7 +1535,7 @@ crate fn add_missing_lifetime_specifiers_label(
15231535
}
15241536
}
15251537
introduce_suggestion.push((span, sugg.to_string()));
1526-
err.multipart_suggestion(msg, introduce_suggestion, Applicability::MaybeIncorrect);
1538+
err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect);
15271539
if should_break {
15281540
break;
15291541
}

src/librustc_resolve/lifetimes.rs

+42-22
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,14 @@ struct NamedRegionMap {
155155

156156
crate enum MissingLifetimeSpot<'tcx> {
157157
Generics(&'tcx hir::Generics<'tcx>),
158-
HRLT { span: Span, span_type: HRLTSpanType },
158+
HRLT { span: Span, span_type: ForLifetimeSpanType },
159159
}
160160

161-
crate enum HRLTSpanType {
162-
Empty,
163-
Tail,
161+
crate enum ForLifetimeSpanType {
162+
BoundEmpty,
163+
BoundTail,
164+
TypeEmpty,
165+
TypeTail,
164166
}
165167

166168
impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &'tcx hir::Generics<'tcx> {
@@ -509,6 +511,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
509511
let next_early_index = self.next_early_index();
510512
let was_in_fn_syntax = self.is_in_fn_syntax;
511513
self.is_in_fn_syntax = true;
514+
let lifetime_span: Option<Span> = c
515+
.generic_params
516+
.iter()
517+
.filter_map(|param| match param.kind {
518+
GenericParamKind::Lifetime { .. } => Some(param.span),
519+
_ => None,
520+
})
521+
.last();
522+
let (span, span_type) = if let Some(span) = lifetime_span {
523+
(span.shrink_to_hi(), ForLifetimeSpanType::TypeTail)
524+
} else {
525+
(ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty)
526+
};
527+
self.missing_named_lifetime_spots
528+
.push(MissingLifetimeSpot::HRLT { span, span_type });
512529
let scope = Scope::Binder {
513530
lifetimes: c
514531
.generic_params
@@ -531,6 +548,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
531548
this.check_lifetime_params(old_scope, &c.generic_params);
532549
intravisit::walk_ty(this, ty);
533550
});
551+
self.missing_named_lifetime_spots.pop();
534552
self.is_in_fn_syntax = was_in_fn_syntax;
535553
}
536554
hir::TyKind::TraitObject(bounds, ref lifetime) => {
@@ -1873,12 +1891,23 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
18731891
err.span_suggestion(
18741892
*span,
18751893
&format!(
1876-
"consider introducing a higher-ranked lifetime `{}` here",
1894+
"consider making the {} lifetime-generic with a new `{}` lifetime",
1895+
match span_type {
1896+
ForLifetimeSpanType::BoundEmpty
1897+
| ForLifetimeSpanType::BoundTail => "bound",
1898+
ForLifetimeSpanType::TypeEmpty
1899+
| ForLifetimeSpanType::TypeTail => "type",
1900+
},
18771901
lifetime_ref
18781902
),
18791903
match span_type {
1880-
HRLTSpanType::Empty => format!("for<{}> ", lifetime_ref),
1881-
HRLTSpanType::Tail => format!(", {}", lifetime_ref),
1904+
ForLifetimeSpanType::TypeEmpty
1905+
| ForLifetimeSpanType::BoundEmpty => {
1906+
format!("for<{}> ", lifetime_ref)
1907+
}
1908+
ForLifetimeSpanType::TypeTail | ForLifetimeSpanType::BoundTail => {
1909+
format!(", {}", lifetime_ref)
1910+
}
18821911
}
18831912
.to_string(),
18841913
Applicability::MaybeIncorrect,
@@ -2487,13 +2516,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
24872516
params.iter().cloned().filter(|info| info.lifetime_count > 0).collect();
24882517

24892518
let elided_len = elided_params.len();
2490-
let mut spans = vec![];
24912519

24922520
for (i, info) in elided_params.into_iter().enumerate() {
24932521
let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
24942522
info;
24952523

2496-
spans.push(span);
2524+
db.span_label(span, "");
24972525
let help_name = if let Some(ident) =
24982526
parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
24992527
{
@@ -2524,37 +2552,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
25242552
}
25252553
}
25262554

2527-
let help = |msg| {
2528-
if spans.is_empty() {
2529-
db.help(msg);
2530-
} else {
2531-
db.span_help(spans, msg);
2532-
}
2533-
};
2534-
25352555
if len == 0 {
25362556
db.help(
25372557
"this function's return type contains a borrowed value, \
25382558
but there is no value for it to be borrowed from",
25392559
);
25402560
self.suggest_lifetime(db, span, "consider giving it a 'static lifetime")
25412561
} else if elided_len == 0 {
2542-
help(
2562+
db.help(
25432563
"this function's return type contains a borrowed value with \
25442564
an elided lifetime, but the lifetime cannot be derived from \
25452565
the arguments",
25462566
);
25472567
let msg = "consider giving it an explicit bounded or 'static lifetime";
25482568
self.suggest_lifetime(db, span, msg)
25492569
} else if elided_len == 1 {
2550-
help(&format!(
2570+
db.help(&format!(
25512571
"this function's return type contains a borrowed value, \
25522572
but the signature does not say which {} it is borrowed from",
25532573
m
25542574
));
25552575
true
25562576
} else {
2557-
help(&format!(
2577+
db.help(&format!(
25582578
"this function's return type contains a borrowed value, \
25592579
but the signature does not say whether it is borrowed from {}",
25602580
m
@@ -2816,8 +2836,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
28162836
.contains(&Some(did))
28172837
{
28182838
let (span, span_type) = match &trait_ref.bound_generic_params {
2819-
[] => (trait_ref.span.shrink_to_lo(), HRLTSpanType::Empty),
2820-
[.., bound] => (bound.span.shrink_to_hi(), HRLTSpanType::Tail),
2839+
[] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
2840+
[.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
28212841
};
28222842
self.missing_named_lifetime_spots
28232843
.push(MissingLifetimeSpot::HRLT { span, span_type });

src/test/ui/async-await/issues/issue-63388-2.stderr

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
error[E0106]: missing lifetime specifier
22
--> $DIR/issue-63388-2.rs:12:10
33
|
4+
LL | foo: &dyn Foo, bar: &'a dyn Foo
5+
| -------- -----------
46
LL | ) -> &dyn Foo
57
| ^ help: consider using the named lifetime: `&'a`
68
|
7-
help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar`
8-
--> $DIR/issue-63388-2.rs:11:14
9-
|
10-
LL | foo: &dyn Foo, bar: &'a dyn Foo
11-
| ^^^^^^^^ ^^^^^^^^^^^
9+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar`
1210

1311
error: cannot infer an appropriate lifetime
1412
--> $DIR/issue-63388-2.rs:11:9

src/test/ui/generic/generic-extern-lifetime.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,24 @@ error[E0261]: use of undeclared lifetime name `'a`
99
|
1010
LL | pub fn life4<'b>(x: for<'c> fn(&'a i32));
1111
| ^^ undeclared lifetime
12+
|
13+
= note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html
14+
help: consider making the type lifetime-generic with a new `'a` lifetime
15+
|
16+
LL | pub fn life4<'b>(x: for<'c, 'a> fn(&'a i32));
17+
| ^^^^
1218

1319
error[E0261]: use of undeclared lifetime name `'a`
1420
--> $DIR/generic-extern-lifetime.rs:11:38
1521
|
1622
LL | pub fn life7<'b>() -> for<'c> fn(&'a i32);
1723
| ^^ undeclared lifetime
24+
|
25+
= note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html
26+
help: consider making the type lifetime-generic with a new `'a` lifetime
27+
|
28+
LL | pub fn life7<'b>() -> for<'c, 'a> fn(&'a i32);
29+
| ^^^^
1830

1931
error: aborting due to 3 previous errors
2032

src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr

+10-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,18 @@ LL | let y: &'test u32 = x;
99
error[E0261]: use of undeclared lifetime name `'test`
1010
--> $DIR/no_introducing_in_band_in_locals.rs:10:16
1111
|
12-
LL | fn bar() {
13-
| - help: consider introducing lifetime `'test` here: `<'test>`
1412
LL | let y: fn(&'test u32) = foo2;
1513
| ^^^^^ undeclared lifetime
14+
|
15+
= note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html
16+
help: consider introducing lifetime `'test` here
17+
|
18+
LL | fn bar<'test>() {
19+
| ^^^^^^^
20+
help: consider making the type lifetime-generic with a new `'test` lifetime
21+
|
22+
LL | let y: for<'test> fn(&'test u32) = foo2;
23+
| ^^^^^^^^^^
1624

1725
error: aborting due to 2 previous errors
1826

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

+9-12
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/issue-19707.rs:3:28
33
|
44
LL | type Foo = fn(&u8, &u8) -> &u8;
5-
| ^ expected named lifetime parameter
5+
| --- --- ^ expected named lifetime parameter
66
|
7-
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-
--> $DIR/issue-19707.rs:3:15
7+
= 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+
= note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html
9+
help: consider making the type lifetime-generic with a new `'a` lifetime
910
|
10-
LL | type Foo = fn(&u8, &u8) -> &u8;
11-
| ^^^ ^^^
11+
LL | type Foo = for<'a> fn(&'a u8, &'a u8) -> &'a u8;
12+
| ^^^^^^^ ^^^^^^ ^^^^^^ ^^^
1213
help: consider introducing a named lifetime parameter
1314
|
1415
LL | type Foo<'a> = fn(&'a u8, &'a u8) -> &'a u8;
@@ -18,15 +19,11 @@ error[E0106]: missing lifetime specifier
1819
--> $DIR/issue-19707.rs:5:27
1920
|
2021
LL | fn bar<F: Fn(&u8, &u8) -> &u8>(f: &F) {}
21-
| ^ expected named lifetime parameter
22+
| --- --- ^ expected named lifetime parameter
2223
|
23-
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
24-
--> $DIR/issue-19707.rs:5:14
25-
|
26-
LL | fn bar<F: Fn(&u8, &u8) -> &u8>(f: &F) {}
27-
| ^^^ ^^^
24+
= 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
2825
= note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html
29-
help: consider introducing a higher-ranked lifetime
26+
help: consider making the bound lifetime-generic with a new `'a` lifetime
3027
|
3128
LL | fn bar<F: for<'a> Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {}
3229
| ^^^^^^^ ^^^^^^ ^^^^^^ ^^^

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

+2-6
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@ 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 named lifetime parameter
5+
| ------------------------------------ ^ expected named lifetime parameter
66
|
7-
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-
--> $DIR/issue-26638.rs:1:21
9-
|
10-
LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7+
= 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
128
help: consider introducing a named lifetime parameter
139
|
1410
LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() }

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

+6-18
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/issue-30255.rs:9:24
33
|
44
LL | fn f(a: &S, b: i32) -> &i32 {
5-
| ^ expected named lifetime parameter
5+
| -- ^ expected named lifetime parameter
66
|
7-
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-
--> $DIR/issue-30255.rs:9:9
9-
|
10-
LL | fn f(a: &S, b: i32) -> &i32 {
11-
| ^^
7+
= 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
128
help: consider introducing a named lifetime parameter
139
|
1410
LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 {
@@ -18,13 +14,9 @@ error[E0106]: missing lifetime specifier
1814
--> $DIR/issue-30255.rs:14:34
1915
|
2016
LL | fn g(a: &S, b: bool, c: &i32) -> &i32 {
21-
| ^ expected named lifetime parameter
22-
|
23-
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`
24-
--> $DIR/issue-30255.rs:14:9
17+
| -- ---- ^ expected named lifetime parameter
2518
|
26-
LL | fn g(a: &S, b: bool, c: &i32) -> &i32 {
27-
| ^^ ^^^^
19+
= 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`
2820
help: consider introducing a named lifetime parameter
2921
|
3022
LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 {
@@ -34,13 +26,9 @@ error[E0106]: missing lifetime specifier
3426
--> $DIR/issue-30255.rs:19:44
3527
|
3628
LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 {
37-
| ^ expected named lifetime parameter
38-
|
39-
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`
40-
--> $DIR/issue-30255.rs:19:9
29+
| ----- -- ---- ^ expected named lifetime parameter
4130
|
42-
LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 {
43-
| ^^^^^ ^^ ^^^^
31+
= 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`
4432
help: consider introducing a named lifetime parameter
4533
|
4634
LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a i32 {

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

+4-12
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@ 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 named lifetime parameter
13+
| ------ ------ ^ expected named lifetime parameter
1414
|
15-
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-
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:10
17-
|
18-
LL | fn g(_x: &isize, _y: &isize) -> &isize {
19-
| ^^^^^^ ^^^^^^
15+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y`
2016
help: consider introducing a named lifetime parameter
2117
|
2218
LL | fn g<'a>(_x: &'a isize, _y: &'a isize) -> &'a isize {
@@ -26,13 +22,9 @@ error[E0106]: missing lifetime specifier
2622
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19
2723
|
2824
LL | fn h(_x: &Foo) -> &isize {
29-
| ^ expected named lifetime parameter
25+
| ---- ^ expected named lifetime parameter
3026
|
31-
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
32-
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:10
33-
|
34-
LL | fn h(_x: &Foo) -> &isize {
35-
| ^^^^
27+
= 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
3628
help: consider introducing a named lifetime parameter
3729
|
3830
LL | fn h<'a>(_x: &'a Foo) -> &'a isize {

0 commit comments

Comments
 (0)