Skip to content

Commit 2f4d780

Browse files
committed
Improve lifetime elision hint error
This also changes the tests introduced by the previous commits because of another rustc issue (#90258)
1 parent e7b8e73 commit 2f4d780

10 files changed

+123
-85
lines changed

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::infer::SubregionOrigin;
99

1010
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
1111
use rustc_hir as hir;
12-
use rustc_hir::Ty;
12+
use rustc_hir::{GenericParamKind, Ty};
1313
use rustc_middle::ty::Region;
1414

1515
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -163,13 +163,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
163163
}
164164
};
165165

166-
let mut e = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
166+
let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
167167

168-
e.span_label(span_1, main_label);
169-
e.span_label(span_2, String::new());
170-
e.span_label(span, span_label);
168+
err.span_label(span_1, main_label);
169+
err.span_label(span_2, String::new());
170+
err.span_label(span, span_label);
171171

172-
self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut e);
172+
self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
173173

174174
if let Some(t) = future_return_type {
175175
let snip = self
@@ -185,12 +185,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
185185
})
186186
.unwrap_or_else(|| "{unnamed_type}".to_string());
187187

188-
e.span_label(
188+
err.span_label(
189189
t.span,
190190
&format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip),
191191
);
192192
}
193-
e.emit();
193+
err.emit();
194194
Some(ErrorReported)
195195
}
196196

@@ -199,7 +199,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
199199
sub: Region<'tcx>,
200200
ty_sup: &Ty<'_>,
201201
ty_sub: &Ty<'_>,
202-
e: &mut DiagnosticBuilder<'_>,
202+
err: &mut DiagnosticBuilder<'_>,
203203
) {
204204
if let (
205205
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
@@ -214,29 +214,51 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
214214
..
215215
}) = self.tcx().hir().get(hir_id)
216216
{
217-
let add_lifetime_param = match &generics.params {
218-
[] => (generics.span, "<'a>".to_string()),
219-
[first, ..] => (first.span.shrink_to_lo(), "'a, ".to_string()),
220-
};
221-
222-
e.multipart_suggestion(
223-
"explicitly declare a lifetime and assign it to both",
224-
vec![
225-
add_lifetime_param,
226-
if let hir::LifetimeName::Underscore = lifetime_sub.name {
227-
(lifetime_sub.span, "'a".to_string())
228-
} else {
229-
(lifetime_sub.span.shrink_to_hi(), "'a ".to_string())
230-
},
231-
if let hir::LifetimeName::Underscore = lifetime_sup.name {
232-
(lifetime_sup.span, "'a".to_string())
233-
} else {
234-
(lifetime_sup.span.shrink_to_hi(), "'a ".to_string())
235-
},
236-
],
217+
let (suggestion_param_name, introduce_new) = generics
218+
.params
219+
.iter()
220+
.find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
221+
.and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok())
222+
.map(|name| (name, false))
223+
.unwrap_or_else(|| ("'a".to_string(), true));
224+
225+
let mut suggestions = vec![
226+
if let hir::LifetimeName::Underscore = lifetime_sub.name {
227+
(lifetime_sub.span, suggestion_param_name.clone())
228+
} else {
229+
(
230+
lifetime_sub.span.shrink_to_hi(),
231+
suggestion_param_name.clone() + " ",
232+
)
233+
},
234+
if let hir::LifetimeName::Underscore = lifetime_sup.name {
235+
(lifetime_sup.span, suggestion_param_name.clone())
236+
} else {
237+
(
238+
lifetime_sup.span.shrink_to_hi(),
239+
suggestion_param_name.clone() + " ",
240+
)
241+
},
242+
];
243+
244+
if introduce_new {
245+
let new_param_suggestion = match &generics.params {
246+
[] => (generics.span, format!("<{}>", suggestion_param_name)),
247+
[first, ..] => (
248+
first.span.shrink_to_lo(),
249+
format!("{}, ", suggestion_param_name),
250+
),
251+
};
252+
253+
suggestions.push(new_param_suggestion);
254+
}
255+
256+
err.multipart_suggestion(
257+
"consider introducing a named lifetime parameter",
258+
suggestions,
237259
Applicability::MaybeIncorrect,
238260
);
239-
e.note(
261+
err.note(
240262
"each elided lifetime in input position becomes a distinct lifetime",
241263
);
242264
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// run-rustfix
2+
3+
fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
4+
5+
fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
6+
7+
fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
8+
9+
fn ok<'a>(slice_a: &'a mut [u8], slice_b: &'a mut [u8]) {
10+
core::mem::swap(&mut slice_a, &mut slice_b);
11+
}
12+
13+
fn main() {
14+
let a = [1u8, 2, 3];
15+
let b = [4u8, 5, 6];
16+
foo(&mut a, &mut b);
17+
}

src/test/ui/lifetimes/issue-90170-elision-mismatch.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
fn foo(slice_a: &mut [u8], slice_b: &mut [u8]) {
2-
core::mem::swap(&mut slice_a, &mut slice_b); //~ ERROR lifetime mismatch
3-
//~^ ERROR lifetime mismatch
4-
}
1+
// run-rustfix
52

6-
fn foo2<U, W, O>(slice_a: &mut [u8], slice_b: &mut [u8], _: U, _: W, _: O) {
7-
core::mem::swap(&mut slice_a, &mut slice_b); //~ ERROR lifetime mismatch
8-
//~^ ERROR lifetime mismatch
9-
}
3+
fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
4+
5+
fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
6+
7+
fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
108

119
fn ok<'a>(slice_a: &'a mut [u8], slice_b: &'a mut [u8]) {
1210
core::mem::swap(&mut slice_a, &mut slice_b);
Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,64 @@
11
error[E0623]: lifetime mismatch
2-
--> $DIR/issue-90170-elision-mismatch.rs:2:35
2+
--> $DIR/issue-90170-elision-mismatch.rs:3:43
33
|
4-
LL | fn foo(slice_a: &mut [u8], slice_b: &mut [u8]) {
5-
| --------- --------- these two types are declared with different lifetimes...
6-
LL | core::mem::swap(&mut slice_a, &mut slice_b);
7-
| ^^^^^^^^^^^^ ...but data from `slice_b` flows into `slice_a` here
4+
LL | fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); }
5+
| --- --- ^ ...but data from `y` flows into `x` here
6+
| |
7+
| these two types are declared with different lifetimes...
88
|
99
= note: each elided lifetime in input position becomes a distinct lifetime
10-
help: explicitly declare a lifetime and assign it to both
10+
help: consider introducing a named lifetime parameter
1111
|
12-
LL | fn foo<'a>(slice_a: &'a mut [u8], slice_b: &'a mut [u8]) {
13-
| ++++ ++ ++
12+
LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
13+
| ++++ ++ ++
1414

1515
error[E0623]: lifetime mismatch
16-
--> $DIR/issue-90170-elision-mismatch.rs:2:35
16+
--> $DIR/issue-90170-elision-mismatch.rs:5:47
1717
|
18-
LL | fn foo(slice_a: &mut [u8], slice_b: &mut [u8]) {
19-
| --------- ---------
20-
| |
21-
| these two types are declared with different lifetimes...
22-
LL | core::mem::swap(&mut slice_a, &mut slice_b);
23-
| ^^^^^^^^^^^^ ...but data from `slice_a` flows into `slice_b` here
18+
LL | fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); }
19+
| ------ --- ^ ...but data from `y` flows into `x` here
20+
| |
21+
| these two types are declared with different lifetimes...
2422
|
2523
= note: each elided lifetime in input position becomes a distinct lifetime
26-
help: explicitly declare a lifetime and assign it to both
24+
help: consider introducing a named lifetime parameter
2725
|
28-
LL | fn foo<'a>(slice_a: &'a mut [u8], slice_b: &'a mut [u8]) {
29-
| ++++ ++ ++
26+
LL | fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
27+
| ++++ ~~ ++
3028

3129
error[E0623]: lifetime mismatch
32-
--> $DIR/issue-90170-elision-mismatch.rs:7:35
30+
--> $DIR/issue-90170-elision-mismatch.rs:7:66
3331
|
34-
LL | fn foo2<U, W, O>(slice_a: &mut [u8], slice_b: &mut [u8], _: U, _: W, _: O) {
35-
| --------- --------- these two types are declared with different lifetimes...
36-
LL | core::mem::swap(&mut slice_a, &mut slice_b);
37-
| ^^^^^^^^^^^^ ...but data from `slice_b` flows into `slice_a` here
32+
LL | fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); }
33+
| --- --- ^ ...but data from `y` flows into `x` here
34+
| |
35+
| these two types are declared with different lifetimes...
3836
|
3937
= note: each elided lifetime in input position becomes a distinct lifetime
40-
help: explicitly declare a lifetime and assign it to both
38+
help: consider introducing a named lifetime parameter
4139
|
42-
LL | fn foo2<'a, U, W, O>(slice_a: &'a mut [u8], slice_b: &'a mut [u8], _: U, _: W, _: O) {
43-
| +++ ++ ++
40+
LL | fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
41+
| ++ ++
4442

45-
error[E0623]: lifetime mismatch
46-
--> $DIR/issue-90170-elision-mismatch.rs:7:35
43+
error[E0308]: mismatched types
44+
--> $DIR/issue-90170-elision-mismatch.rs:16:9
4745
|
48-
LL | fn foo2<U, W, O>(slice_a: &mut [u8], slice_b: &mut [u8], _: U, _: W, _: O) {
49-
| --------- ---------
50-
| |
51-
| these two types are declared with different lifetimes...
52-
LL | core::mem::swap(&mut slice_a, &mut slice_b);
53-
| ^^^^^^^^^^^^ ...but data from `slice_a` flows into `slice_b` here
46+
LL | foo(&mut a, &mut b);
47+
| ^^^^^^ expected struct `Vec`, found array `[u8; 3]`
5448
|
55-
= note: each elided lifetime in input position becomes a distinct lifetime
56-
help: explicitly declare a lifetime and assign it to both
49+
= note: expected mutable reference `&mut Vec<&u8>`
50+
found mutable reference `&mut [u8; 3]`
51+
52+
error[E0308]: mismatched types
53+
--> $DIR/issue-90170-elision-mismatch.rs:16:17
54+
|
55+
LL | foo(&mut a, &mut b);
56+
| ^^^^^^ expected `u8`, found array `[u8; 3]`
5757
|
58-
LL | fn foo2<'a, U, W, O>(slice_a: &'a mut [u8], slice_b: &'a mut [u8], _: U, _: W, _: O) {
59-
| +++ ++ ++
58+
= note: expected reference `&u8`
59+
found mutable reference `&mut [u8; 3]`
6060

61-
error: aborting due to 4 previous errors
61+
error: aborting due to 5 previous errors
6262

63-
For more information about this error, try `rustc --explain E0623`.
63+
Some errors have detailed explanations: E0308, E0623.
64+
For more information about an error, try `rustc --explain E0308`.

src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | *v = x;
77
| ^ ...but data from `x` flows here
88
|
99
= note: each elided lifetime in input position becomes a distinct lifetime
10-
help: explicitly declare a lifetime and assign it to both
10+
help: consider introducing a named lifetime parameter
1111
|
1212
LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) {
1313
| ++++ ++ ++

src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | z.push((x,y));
77
| ^ ...but data flows into `z` here
88
|
99
= note: each elided lifetime in input position becomes a distinct lifetime
10-
help: explicitly declare a lifetime and assign it to both
10+
help: consider introducing a named lifetime parameter
1111
|
1212
LL | fn foo<'a>(z: &mut Vec<(&'a u8,&u8)>, (x, y): (&'a u8, &u8)) {
1313
| ++++ ++ ++
@@ -21,7 +21,7 @@ LL | z.push((x,y));
2121
| ^ ...but data flows into `z` here
2222
|
2323
= note: each elided lifetime in input position becomes a distinct lifetime
24-
help: explicitly declare a lifetime and assign it to both
24+
help: consider introducing a named lifetime parameter
2525
|
2626
LL | fn foo<'a>(z: &mut Vec<(&u8,&'a u8)>, (x, y): (&u8, &'a u8)) {
2727
| ++++ ++ ++

src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | y.push(z);
77
| ^ ...but data from `z` flows into `y` here
88
|
99
= note: each elided lifetime in input position becomes a distinct lifetime
10-
help: explicitly declare a lifetime and assign it to both
10+
help: consider introducing a named lifetime parameter
1111
|
1212
LL | fn foo<'a>(x:fn(&u8, &u8), y: Vec<&'a u8>, z: &'a u8) {
1313
| ++++ ++ ++

src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | y.push(z);
77
| ^ ...but data from `z` flows into `y` here
88
|
99
= note: each elided lifetime in input position becomes a distinct lifetime
10-
help: explicitly declare a lifetime and assign it to both
10+
help: consider introducing a named lifetime parameter
1111
|
1212
LL | fn foo<'a>(x:Box<dyn Fn(&'a u8, &'a u8)> , y: Vec<&u8>, z: &u8) {
1313
| ++++ ++ ++

src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | x.push(y);
77
| ^ ...but data from `y` flows into `x` here
88
|
99
= note: each elided lifetime in input position becomes a distinct lifetime
10-
help: explicitly declare a lifetime and assign it to both
10+
help: consider introducing a named lifetime parameter
1111
|
1212
LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) {
1313
| ++++ ++ ++

src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); }
77
| these two types are declared with different lifetimes...
88
|
99
= note: each elided lifetime in input position becomes a distinct lifetime
10-
help: explicitly declare a lifetime and assign it to both
10+
help: consider introducing a named lifetime parameter
1111
|
1212
LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
1313
| ++++ ~~ ~~

0 commit comments

Comments
 (0)