Skip to content

Commit 439ef6d

Browse files
committed
Fix suggestions for missing return type lifetime parameters
1 parent e5f83d2 commit 439ef6d

File tree

9 files changed

+514
-151
lines changed

9 files changed

+514
-151
lines changed

compiler/rustc_errors/src/diagnostic.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,30 @@ impl Diagnostic {
299299
self
300300
}
301301

302+
/// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
303+
pub fn multipart_suggestion_with_style(
304+
&mut self,
305+
msg: &str,
306+
suggestion: Vec<(Span, String)>,
307+
applicability: Applicability,
308+
style: SuggestionStyle,
309+
) -> &mut Self {
310+
assert!(!suggestion.is_empty());
311+
self.suggestions.push(CodeSuggestion {
312+
substitutions: vec![Substitution {
313+
parts: suggestion
314+
.into_iter()
315+
.map(|(span, snippet)| SubstitutionPart { snippet, span })
316+
.collect(),
317+
}],
318+
msg: msg.to_owned(),
319+
style,
320+
applicability,
321+
tool_metadata: Default::default(),
322+
});
323+
self
324+
}
325+
302326
/// Prints out a message with for a multipart suggestion without showing the suggested code.
303327
///
304328
/// This is intended to be used for suggestions that are obvious in what the changes need to

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 205 additions & 146 deletions
Large diffs are not rendered by default.

compiler/rustc_resolve/src/late/lifetimes.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2956,7 +2956,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
29562956
return;
29572957
}
29582958

2959-
let span = lifetime_refs[0].span;
29602959
let mut late_depth = 0;
29612960
let mut scope = self.scope;
29622961
let mut lifetime_names = FxHashSet::default();
@@ -3035,18 +3034,26 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
30353034
}
30363035
};
30373036

3038-
let mut err = self.report_missing_lifetime_specifiers(span, lifetime_refs.len());
3037+
let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
3038+
spans.sort();
3039+
let mut spans_dedup = spans.clone();
3040+
spans_dedup.dedup();
3041+
let counts: Vec<_> =
3042+
spans_dedup.iter().map(|sp| spans.iter().filter(|nsp| *nsp == sp).count()).collect();
3043+
3044+
let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len());
30393045

30403046
if let Some(params) = error {
30413047
// If there's no lifetime available, suggest `'static`.
30423048
if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() {
30433049
lifetime_names.insert(kw::StaticLifetime);
30443050
}
30453051
}
3052+
30463053
self.add_missing_lifetime_specifiers_label(
30473054
&mut err,
3048-
span,
3049-
lifetime_refs.len(),
3055+
spans,
3056+
counts,
30503057
&lifetime_names,
30513058
lifetime_spans,
30523059
error.unwrap_or(&[]),

src/test/ui/issues/issue-84592.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* Checks whether issue #84592 has been resolved. The issue was
2+
* that in this example, there are two expected/missing lifetime
3+
* parameters with *different spans*, leading to incorrect
4+
* suggestions from rustc.
5+
*/
6+
7+
struct TwoLifetimes<'x, 'y> {
8+
x: &'x (),
9+
y: &'y (),
10+
}
11+
12+
fn two_lifetimes_needed(a: &(), b: &()) -> TwoLifetimes<'_, '_> {
13+
//~^ ERROR missing lifetime specifiers [E0106]
14+
TwoLifetimes { x: &(), y: &() }
15+
}
16+
17+
fn main() {}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0106]: missing lifetime specifiers
2+
--> $DIR/issue-84592.rs:12:57
3+
|
4+
LL | fn two_lifetimes_needed(a: &(), b: &()) -> TwoLifetimes<'_, '_> {
5+
| --- --- ^^ ^^ expected named lifetime parameter
6+
| |
7+
| expected named lifetime parameter
8+
|
9+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
10+
help: consider introducing a named lifetime parameter
11+
|
12+
LL | fn two_lifetimes_needed<'a>(a: &'a (), b: &'a ()) -> TwoLifetimes<'a, 'a> {
13+
| ^^^^ ^^^^^^ ^^^^^^ ^^ ^^
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0106`.

src/test/ui/return-elided-lifetime.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* Checks all four scenarios possible in report_elision_failure() of
2+
* rustc_resolve::late::lifetimes::LifetimeContext related to returning
3+
* borrowed values, in various configurations.
4+
*/
5+
6+
fn f1() -> &i32 { loop {} }
7+
//~^ ERROR missing lifetime specifier [E0106]
8+
fn f1_() -> (&i32, &i32) { loop {} }
9+
//~^ ERROR missing lifetime specifier [E0106]
10+
//~^^ ERROR missing lifetime specifier [E0106]
11+
12+
fn f2(a: i32, b: i32) -> &i32 { loop {} }
13+
//~^ ERROR missing lifetime specifier [E0106]
14+
fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
15+
//~^ ERROR missing lifetime specifier [E0106]
16+
//~^^ ERROR missing lifetime specifier [E0106]
17+
18+
struct S<'a, 'b> { a: &'a i32, b: &'b i32 }
19+
fn f3(s: &S) -> &i32 { loop {} }
20+
//~^ ERROR missing lifetime specifier [E0106]
21+
fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
22+
//~^ ERROR missing lifetime specifier [E0106]
23+
//~^^ ERROR missing lifetime specifier [E0106]
24+
25+
fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
26+
//~^ ERROR missing lifetime specifier [E0106]
27+
fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
28+
//~^ ERROR missing lifetime specifier [E0106]
29+
//~^^ ERROR missing lifetime specifier [E0106]
30+
31+
fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} }
32+
//~^ ERROR missing lifetime specifier [E0106]
33+
fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
34+
//~^ ERROR missing lifetime specifier [E0106]
35+
//~^^ ERROR missing lifetime specifier [E0106]
36+
37+
fn main() {}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
error[E0106]: missing lifetime specifier
2+
--> $DIR/return-elided-lifetime.rs:6:12
3+
|
4+
LL | fn f1() -> &i32 { loop {} }
5+
| ^ expected named lifetime parameter
6+
|
7+
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
8+
help: consider using the `'static` lifetime
9+
|
10+
LL | fn f1() -> &'static i32 { loop {} }
11+
| ^^^^^^^^
12+
13+
error[E0106]: missing lifetime specifier
14+
--> $DIR/return-elided-lifetime.rs:8:14
15+
|
16+
LL | fn f1_() -> (&i32, &i32) { loop {} }
17+
| ^ expected named lifetime parameter
18+
|
19+
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
20+
help: consider using the `'static` lifetime
21+
|
22+
LL | fn f1_() -> (&'static i32, &i32) { loop {} }
23+
| ^^^^^^^^
24+
25+
error[E0106]: missing lifetime specifier
26+
--> $DIR/return-elided-lifetime.rs:8:20
27+
|
28+
LL | fn f1_() -> (&i32, &i32) { loop {} }
29+
| ^ expected named lifetime parameter
30+
|
31+
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
32+
help: consider using the `'static` lifetime
33+
|
34+
LL | fn f1_() -> (&i32, &'static i32) { loop {} }
35+
| ^^^^^^^^
36+
37+
error[E0106]: missing lifetime specifier
38+
--> $DIR/return-elided-lifetime.rs:12:26
39+
|
40+
LL | fn f2(a: i32, b: i32) -> &i32 { loop {} }
41+
| ^ expected named lifetime parameter
42+
|
43+
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
44+
help: consider using the `'static` lifetime
45+
|
46+
LL | fn f2(a: i32, b: i32) -> &'static i32 { loop {} }
47+
| ^^^^^^^^
48+
49+
error[E0106]: missing lifetime specifier
50+
--> $DIR/return-elided-lifetime.rs:14:28
51+
|
52+
LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
53+
| ^ expected named lifetime parameter
54+
|
55+
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
56+
help: consider using the `'static` lifetime
57+
|
58+
LL | fn f2_(a: i32, b: i32) -> (&'static i32, &i32) { loop {} }
59+
| ^^^^^^^^
60+
61+
error[E0106]: missing lifetime specifier
62+
--> $DIR/return-elided-lifetime.rs:14:34
63+
|
64+
LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
65+
| ^ expected named lifetime parameter
66+
|
67+
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
68+
help: consider using the `'static` lifetime
69+
|
70+
LL | fn f2_(a: i32, b: i32) -> (&i32, &'static i32) { loop {} }
71+
| ^^^^^^^^
72+
73+
error[E0106]: missing lifetime specifier
74+
--> $DIR/return-elided-lifetime.rs:19:17
75+
|
76+
LL | fn f3(s: &S) -> &i32 { loop {} }
77+
| -- ^ expected named lifetime parameter
78+
|
79+
= help: this function's return type contains a borrowed value, but the signature does not say which one of `s`'s 3 lifetimes it is borrowed from
80+
help: consider introducing a named lifetime parameter
81+
|
82+
LL | fn f3<'a>(s: &'a S) -> &'a i32 { loop {} }
83+
| ^^^^ ^^^^^ ^^^
84+
85+
error[E0106]: missing lifetime specifier
86+
--> $DIR/return-elided-lifetime.rs:21:26
87+
|
88+
LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
89+
| -- -- ^ expected named lifetime parameter
90+
|
91+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes
92+
help: consider introducing a named lifetime parameter
93+
|
94+
LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&'a i32, &i32) { loop {} }
95+
| ^^^^ ^^^^^ ^^^^^ ^^^
96+
97+
error[E0106]: missing lifetime specifier
98+
--> $DIR/return-elided-lifetime.rs:21:32
99+
|
100+
LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
101+
| -- -- ^ expected named lifetime parameter
102+
|
103+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes
104+
help: consider introducing a named lifetime parameter
105+
|
106+
LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&i32, &'a i32) { loop {} }
107+
| ^^^^ ^^^^^ ^^^^^ ^^^
108+
109+
error[E0106]: missing lifetime specifier
110+
--> $DIR/return-elided-lifetime.rs:25:42
111+
|
112+
LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
113+
| ------- ------- ^ expected named lifetime parameter
114+
|
115+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
116+
note: these named lifetimes are available to use
117+
--> $DIR/return-elided-lifetime.rs:25:7
118+
|
119+
LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
120+
| ^^ ^^
121+
help: consider using one of the available lifetimes here
122+
|
123+
LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &'lifetime i32 { loop {} }
124+
| ^^^^^^^^^^
125+
126+
error[E0106]: missing lifetime specifier
127+
--> $DIR/return-elided-lifetime.rs:27:44
128+
|
129+
LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
130+
| ------- ------- ^ expected named lifetime parameter
131+
|
132+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
133+
note: these named lifetimes are available to use
134+
--> $DIR/return-elided-lifetime.rs:27:8
135+
|
136+
LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
137+
| ^^ ^^
138+
help: consider using one of the available lifetimes here
139+
|
140+
LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &i32) { loop {} }
141+
| ^^^^^^^^^^
142+
143+
error[E0106]: missing lifetime specifier
144+
--> $DIR/return-elided-lifetime.rs:27:50
145+
|
146+
LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
147+
| ------- ------- ^ expected named lifetime parameter
148+
|
149+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
150+
note: these named lifetimes are available to use
151+
--> $DIR/return-elided-lifetime.rs:27:8
152+
|
153+
LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
154+
| ^^ ^^
155+
help: consider using one of the available lifetimes here
156+
|
157+
LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &'lifetime i32) { loop {} }
158+
| ^^^^^^^^^^
159+
160+
error[E0106]: missing lifetime specifier
161+
--> $DIR/return-elided-lifetime.rs:31:35
162+
|
163+
LL | fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} }
164+
| ------- ---- ^ expected named lifetime parameter
165+
|
166+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
167+
help: consider using the `'a` lifetime
168+
|
169+
LL | fn f5<'a>(a: &'a i32, b: &i32) -> &'a i32 { loop {} }
170+
| ^^^
171+
172+
error[E0106]: missing lifetime specifier
173+
--> $DIR/return-elided-lifetime.rs:33:37
174+
|
175+
LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
176+
| ------- ---- ^ expected named lifetime parameter
177+
|
178+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
179+
help: consider using the `'a` lifetime
180+
|
181+
LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &i32) { loop {} }
182+
| ^^^
183+
184+
error[E0106]: missing lifetime specifier
185+
--> $DIR/return-elided-lifetime.rs:33:43
186+
|
187+
LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
188+
| ------- ---- ^ expected named lifetime parameter
189+
|
190+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
191+
help: consider using the `'a` lifetime
192+
|
193+
LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &'a i32) { loop {} }
194+
| ^^^
195+
196+
error: aborting due to 15 previous errors
197+
198+
For more information about this error, try `rustc --explain E0106`.

src/test/ui/suggestions/missing-lt-for-hrtb.stderr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ note: these named lifetimes are available to use
4444
|
4545
LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
4646
| ^^ ^^
47+
help: consider using one of the available lifetimes here
48+
|
49+
LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X);
50+
| ^^^^^^^^^^
4751

4852
error[E0106]: missing lifetime specifier
4953
--> $DIR/missing-lt-for-hrtb.rs:5:41

src/tools/tidy/src/ui_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::path::Path;
88
const ENTRY_LIMIT: usize = 1000;
99
// FIXME: The following limits should be reduced eventually.
1010
const ROOT_ENTRY_LIMIT: usize = 1388;
11-
const ISSUES_ENTRY_LIMIT: usize = 2551;
11+
const ISSUES_ENTRY_LIMIT: usize = 2557;
1212

1313
fn check_entries(path: &Path, bad: &mut bool) {
1414
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))

0 commit comments

Comments
 (0)