Skip to content

Commit 7449c6e

Browse files
Rollup merge of #87983 - estebank:smaller-lt-spans, r=oli-obk
Use more accurate spans when proposing adding lifetime to item
2 parents e89c7d0 + 9349046 commit 7449c6e

17 files changed

+106
-40
lines changed

compiler/rustc_resolve/src/late/diagnostics.rs

+76-10
Original file line numberDiff line numberDiff line change
@@ -2073,20 +2073,85 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
20732073
continue;
20742074
}
20752075
});
2076+
2077+
struct Lifetime(Span, String);
2078+
impl Lifetime {
2079+
fn is_unnamed(&self) -> bool {
2080+
self.1.starts_with('&') && !self.1.starts_with("&'")
2081+
}
2082+
fn is_underscore(&self) -> bool {
2083+
self.1.starts_with("&'_ ")
2084+
}
2085+
fn is_named(&self) -> bool {
2086+
self.1.starts_with("&'")
2087+
}
2088+
fn suggestion(&self, sugg: String) -> Option<(Span, String)> {
2089+
Some(
2090+
match (
2091+
self.is_unnamed(),
2092+
self.is_underscore(),
2093+
self.is_named(),
2094+
sugg.starts_with("&"),
2095+
) {
2096+
(true, _, _, false) => (self.span_unnamed_borrow(), sugg),
2097+
(true, _, _, true) => {
2098+
(self.span_unnamed_borrow(), sugg[1..].to_string())
2099+
}
2100+
(_, true, _, false) => {
2101+
(self.span_underscore_borrow(), sugg.trim().to_string())
2102+
}
2103+
(_, true, _, true) => {
2104+
(self.span_underscore_borrow(), sugg[1..].trim().to_string())
2105+
}
2106+
(_, _, true, false) => {
2107+
(self.span_named_borrow(), sugg.trim().to_string())
2108+
}
2109+
(_, _, true, true) => {
2110+
(self.span_named_borrow(), sugg[1..].trim().to_string())
2111+
}
2112+
_ => return None,
2113+
},
2114+
)
2115+
}
2116+
fn span_unnamed_borrow(&self) -> Span {
2117+
let lo = self.0.lo() + BytePos(1);
2118+
self.0.with_lo(lo).with_hi(lo)
2119+
}
2120+
fn span_named_borrow(&self) -> Span {
2121+
let lo = self.0.lo() + BytePos(1);
2122+
self.0.with_lo(lo)
2123+
}
2124+
fn span_underscore_borrow(&self) -> Span {
2125+
let lo = self.0.lo() + BytePos(1);
2126+
let hi = lo + BytePos(2);
2127+
self.0.with_lo(lo).with_hi(hi)
2128+
}
2129+
}
2130+
20762131
for param in params {
20772132
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
2078-
if snippet.starts_with('&') && !snippet.starts_with("&'") {
2079-
introduce_suggestion
2080-
.push((param.span, format!("&'a {}", &snippet[1..])));
2081-
} else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
2082-
introduce_suggestion.push((param.span, format!("&'a {}", &stripped)));
2133+
if let Some((span, sugg)) =
2134+
Lifetime(param.span, snippet).suggestion("'a ".to_string())
2135+
{
2136+
introduce_suggestion.push((span, sugg));
20832137
}
20842138
}
20852139
}
2086-
for ((span, _), sugg) in spans_with_counts.iter().copied().zip(suggs.iter()) {
2087-
if let Some(sugg) = sugg {
2088-
introduce_suggestion.push((span, sugg.to_string()));
2089-
}
2140+
for (span, sugg) in spans_with_counts.iter().copied().zip(suggs.iter()).filter_map(
2141+
|((span, _), sugg)| match &sugg {
2142+
Some(sugg) => Some((span, sugg.to_string())),
2143+
_ => None,
2144+
},
2145+
) {
2146+
let (span, sugg) = self
2147+
.tcx
2148+
.sess
2149+
.source_map()
2150+
.span_to_snippet(span)
2151+
.ok()
2152+
.and_then(|snippet| Lifetime(span, snippet).suggestion(sugg.clone()))
2153+
.unwrap_or((span, sugg));
2154+
introduce_suggestion.push((span, sugg.to_string()));
20902155
}
20912156
err.multipart_suggestion_with_style(
20922157
&msg,
@@ -2159,7 +2224,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
21592224
for ((span, _), snippet) in spans_with_counts.iter().copied().zip(snippets.iter()) {
21602225
match snippet.as_deref() {
21612226
Some("") => spans_suggs.push((span, "'lifetime, ".to_string())),
2162-
Some("&") => spans_suggs.push((span, "&'lifetime ".to_string())),
2227+
Some("&") => spans_suggs
2228+
.push((span.with_lo(span.lo() + BytePos(1)), "'lifetime ".to_string())),
21632229
_ => {}
21642230
}
21652231
}

src/test/ui/error-codes/E0106.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ LL | type MyStr = &str;
5959
help: consider introducing a named lifetime parameter
6060
|
6161
LL | type MyStr<'a> = &'a str;
62-
| ++++ ~~~
62+
| ++++ ++
6363

6464
error: aborting due to 5 previous errors
6565

src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ LL | type F<T1> = &[u8];
1515
help: consider introducing a named lifetime parameter
1616
|
1717
LL | type F<'a, T1> = &'a [u8];
18-
| +++ ~~~
18+
| +++ ++
1919

2020
error: aborting due to 2 previous errors
2121

src/test/ui/impl-header-lifetime-elision/assoc-type.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | type Output = &i32;
77
help: consider introducing a named lifetime parameter
88
|
99
LL | type Output<'a> = &'a i32;
10-
| ++++ ~~~
10+
| ++++ ++
1111

1212
error[E0106]: missing lifetime specifier
1313
--> $DIR/assoc-type.rs:16:20

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ LL | type Foo = fn(&u8, &u8) -> &u8;
99
help: consider making the type lifetime-generic with a new `'a` lifetime
1010
|
1111
LL | type Foo = for<'a> fn(&'a u8, &'a u8) -> &'a u8;
12-
| +++++++ ~~~~~~ ~~~~~~ ~~~
12+
| +++++++ ++ ++ ++
1313
help: consider introducing a named lifetime parameter
1414
|
1515
LL | type Foo<'a> = fn(&'a u8, &'a u8) -> &'a u8;
16-
| ++++ ~~~~~~ ~~~~~~ ~~~
16+
| ++++ ++ ++ ++
1717

1818
error[E0106]: missing lifetime specifier
1919
--> $DIR/issue-19707.rs:5:27
@@ -26,11 +26,11 @@ LL | fn bar<F: Fn(&u8, &u8) -> &u8>(f: &F) {}
2626
help: consider making the bound lifetime-generic with a new `'a` lifetime
2727
|
2828
LL | fn bar<F: for<'a> Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {}
29-
| +++++++ ~~~~~~ ~~~~~~ ~~~
29+
| +++++++ ++ ++ ++
3030
help: consider introducing a named lifetime parameter
3131
|
3232
LL | fn bar<'a, F: Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {}
33-
| +++ ~~~~~~ ~~~~~~ ~~~
33+
| +++ ++ ++ ++
3434

3535
error: aborting due to 2 previous errors
3636

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.ne
88
help: consider introducing a named lifetime parameter
99
|
1010
LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() }
11-
| ++++ ~~~
11+
| ++++ ++
1212

1313
error[E0106]: missing lifetime specifier
1414
--> $DIR/issue-26638.rs:4:40

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | fn f(a: &S, b: i32) -> &i32 {
88
help: consider introducing a named lifetime parameter
99
|
1010
LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 {
11-
| ++++ ~~~~~ ~~~
11+
| ++++ ++ ++
1212

1313
error[E0106]: missing lifetime specifier
1414
--> $DIR/issue-30255.rs:14:34
@@ -20,7 +20,7 @@ LL | fn g(a: &S, b: bool, c: &i32) -> &i32 {
2020
help: consider introducing a named lifetime parameter
2121
|
2222
LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 {
23-
| ++++ ~~~~~ ~~~~~~~ ~~~
23+
| ++++ ++ ++ ++
2424

2525
error[E0106]: missing lifetime specifier
2626
--> $DIR/issue-30255.rs:19:44
@@ -32,7 +32,7 @@ LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 {
3232
help: consider introducing a named lifetime parameter
3333
|
3434
LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a i32 {
35-
| ++++ ~~~~~~~~ ~~~~~ ~~~~~~~ ~~~
35+
| ++++ ++ ++ ++ ++
3636

3737
error: aborting due to 3 previous errors
3838

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ LL | fn g(_x: &isize, _y: &isize) -> &isize {
2020
help: consider introducing a named lifetime parameter
2121
|
2222
LL | fn g<'a>(_x: &'a isize, _y: &'a isize) -> &'a isize {
23-
| ++++ ~~~~~~~~~ ~~~~~~~~~ ~~~
23+
| ++++ ++ ++ ++
2424

2525
error[E0106]: missing lifetime specifier
2626
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19
@@ -32,7 +32,7 @@ LL | fn h(_x: &Foo) -> &isize {
3232
help: consider introducing a named lifetime parameter
3333
|
3434
LL | fn h<'a>(_x: &'a Foo) -> &'a isize {
35-
| ++++ ~~~~~~~ ~~~
35+
| ++++ ++ ++
3636

3737
error[E0106]: missing lifetime specifier
3838
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20

src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | fn foo(x: &i32, y: &i32) -> &i32 {
88
help: consider introducing a named lifetime parameter
99
|
1010
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
11-
| ++++ ~~~~~~~ ~~~~~~~ ~~~
11+
| ++++ ++ ++ ++
1212

1313
error: aborting due to previous error
1414

src/test/ui/rfc1623-2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
99
help: consider making the type lifetime-generic with a new `'a` lifetime
1010
|
1111
LL | static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 =
12-
| +++++++ ~~~~~~ ~~~~~~ ~~~
12+
| +++++++ ++ ++ ++
1313

1414
error[E0106]: missing lifetime specifier
1515
--> $DIR/rfc1623-2.rs:10:39
@@ -22,7 +22,7 @@ LL | &(non_elidable as fn(&u8, &u8) -> &u8);
2222
help: consider making the type lifetime-generic with a new `'a` lifetime
2323
|
2424
LL | &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
25-
| +++++++ ~~~~~~ ~~~~~~ ~~~
25+
| +++++++ ++ ++ ++
2626

2727
error: aborting due to 2 previous errors
2828

src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ LL | struct S2<F: Fn(&i32, &i32) -> &i32>(F);
2525
help: consider making the bound lifetime-generic with a new `'a` lifetime
2626
|
2727
LL | struct S2<F: for<'a> Fn(&'a i32, &'a i32) -> &'a i32>(F);
28-
| +++++++ ~~~~~~~ ~~~~~~~ ~~~
28+
| +++++++ ++ ++ ++
2929
help: consider introducing a named lifetime parameter
3030
|
3131
LL | struct S2<'a, F: Fn(&'a i32, &'a i32) -> &'a i32>(F);
32-
| +++ ~~~~~~~ ~~~~~~~ ~~~
32+
| +++ ++ ++ ++
3333

3434
error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types
3535
--> $DIR/fn-missing-lifetime-in-item.rs:3:40

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ LL | fn two_lifetimes_needed(a: &(), b: &()) -> TwoLifetimes<'_, '_> {
1010
help: consider introducing a named lifetime parameter
1111
|
1212
LL | fn two_lifetimes_needed<'a>(a: &'a (), b: &'a ()) -> TwoLifetimes<'a, 'a> {
13-
| ++++ ~~~~~~ ~~~~~~ ~~ ~~
13+
| ++++ ++ ++ ~~ ~~
1414

1515
error: aborting due to previous error
1616

src/test/ui/suggestions/issue-86667.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | async fn a(s1: &str, s2: &str) -> &str {
88
help: consider introducing a named lifetime parameter
99
|
1010
LL | async fn a<'a>(s1: &'a str, s2: &'a str) -> &'a str {
11-
| ++++ ~~~~~~~ ~~~~~~~ ~~~
11+
| ++++ ++ ++ ++
1212

1313
error[E0106]: missing lifetime specifier
1414
--> $DIR/issue-86667.rs:11:29
@@ -20,7 +20,7 @@ LL | fn b(s1: &str, s2: &str) -> &str {
2020
help: consider introducing a named lifetime parameter
2121
|
2222
LL | fn b<'a>(s1: &'a str, s2: &'a str) -> &'a str {
23-
| ++++ ~~~~~~~ ~~~~~~~ ~~~
23+
| ++++ ++ ++ ++
2424

2525
error: aborting due to 2 previous errors
2626

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
4747
help: consider using one of the available lifetimes here
4848
|
4949
LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X);
50-
| ~~~~~~~~~~
50+
| +++++++++
5151

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

src/test/ui/suggestions/return-elided-lifetime.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ LL | fn f3(s: &S) -> &i32 { loop {} }
8080
help: consider introducing a named lifetime parameter
8181
|
8282
LL | fn f3<'a>(s: &'a S) -> &'a i32 { loop {} }
83-
| ++++ ~~~~~ ~~~
83+
| ++++ ++ ++
8484

8585
error[E0106]: missing lifetime specifier
8686
--> $DIR/return-elided-lifetime.rs:21:26
@@ -92,7 +92,7 @@ LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
9292
help: consider introducing a named lifetime parameter
9393
|
9494
LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&'a i32, &i32) { loop {} }
95-
| ++++ ~~~~~ ~~~~~ ~~~
95+
| ++++ ++ ++ ++
9696

9797
error[E0106]: missing lifetime specifier
9898
--> $DIR/return-elided-lifetime.rs:21:32
@@ -104,7 +104,7 @@ LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
104104
help: consider introducing a named lifetime parameter
105105
|
106106
LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&i32, &'a i32) { loop {} }
107-
| ++++ ~~~~~ ~~~~~ ~~~
107+
| ++++ ++ ++ ++
108108

109109
error[E0106]: missing lifetime specifier
110110
--> $DIR/return-elided-lifetime.rs:25:42
@@ -121,7 +121,7 @@ LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
121121
help: consider using one of the available lifetimes here
122122
|
123123
LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &'lifetime i32 { loop {} }
124-
| ~~~~~~~~~~
124+
| +++++++++
125125

126126
error[E0106]: missing lifetime specifier
127127
--> $DIR/return-elided-lifetime.rs:27:44
@@ -138,7 +138,7 @@ LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
138138
help: consider using one of the available lifetimes here
139139
|
140140
LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &i32) { loop {} }
141-
| ~~~~~~~~~~
141+
| +++++++++
142142

143143
error[E0106]: missing lifetime specifier
144144
--> $DIR/return-elided-lifetime.rs:27:50
@@ -155,7 +155,7 @@ LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
155155
help: consider using one of the available lifetimes here
156156
|
157157
LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &'lifetime i32) { loop {} }
158-
| ~~~~~~~~~~
158+
| +++++++++
159159

160160
error[E0106]: missing lifetime specifier
161161
--> $DIR/return-elided-lifetime.rs:31:35

src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } }
88
help: consider introducing a named lifetime parameter
99
|
1010
LL | fn foo<'a>(x: &'a u32, y: &'a u32) -> &'a u32 { loop { } }
11-
| ++++ ~~~~~~~ ~~~~~~~ ~~
11+
| ++++ ++ ++ ~~
1212

1313
error: aborting due to previous error
1414

src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y }
4343
help: consider introducing a named lifetime parameter
4444
|
4545
LL | fn foo2<'a>(_: &'a u8, y: &'a u8) -> &'a u8 { y }
46-
| ++++ ~~~~~~ ~~~~~~ ~~
46+
| ++++ ~~ ~~ ~~
4747

4848
error: aborting due to 5 previous errors
4949

0 commit comments

Comments
 (0)