Skip to content

Commit 270fa94

Browse files
committed
Make a proper suggestion.
1 parent bf7e7a5 commit 270fa94

14 files changed

+414
-90
lines changed

compiler/rustc_hir_analysis/src/astconv/generics.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,40 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
611611
})
612612
.collect();
613613

614-
tcx.sess.struct_span_err(spans, msg).span_note(span_late, note).help(help).emit();
614+
let mut err = tcx.sess.struct_span_err(spans, msg);
615+
err.span_note(span_late, note);
616+
617+
let mut suggestions = vec![];
618+
if let Some(span_ext) = args.span_ext() {
619+
if args.num_lifetime_params() == args.args.len()
620+
&& span_ext.ctxt() == seg.ident.span.ctxt()
621+
{
622+
// We only specify lifetime args, so suggest to remove everything.
623+
suggestions.push((seg.ident.span.shrink_to_hi().to(span_ext), String::new()));
624+
} else {
625+
for [arg, next_arg] in args.args.array_windows() {
626+
if let hir::GenericArg::Lifetime(lifetime) = arg
627+
&& let Some(arg_span) = lifetime.ident.span.find_ancestor_inside(span_ext)
628+
&& let Some(next_span_lo) = next_arg.span().shrink_to_lo().find_ancestor_inside(span_ext)
629+
{
630+
suggestions.push((arg_span.with_hi(next_span_lo.lo()), String::new()));
631+
}
632+
}
633+
634+
if let Some(arg) = args.args.last()
635+
&& let hir::GenericArg::Lifetime(lifetime) = arg
636+
&& let Some(arg_span) = lifetime.ident.span.find_ancestor_inside(span_ext)
637+
{
638+
suggestions.push((arg_span, String::new()));
639+
}
640+
}
641+
}
642+
if !suggestions.is_empty() {
643+
err.multipart_suggestion_verbose(help, suggestions, Applicability::MachineApplicable);
644+
} else {
645+
err.help(help);
646+
}
647+
err.emit();
615648

616649
ExplicitLateBound::Yes
617650
} else {

compiler/rustc_hir_analysis/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ This API is completely unstable and subject to change.
5757

5858
#![allow(rustc::potential_query_instability)]
5959
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
60+
#![feature(array_windows)]
6061
#![feature(box_patterns)]
6162
#![feature(control_flow_enum)]
6263
#![feature(drain_filter)]

tests/ui/const-generics/const-arg-in-const-arg.full.stderr

+40-8
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ note: the late bound lifetime parameter is introduced here
99
|
1010
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
1111
| ^^
12-
= help: remove the explicit lifetime argument
12+
help: remove the explicit lifetime argument
13+
|
14+
LL - let _: [u8; faz::<'a>(&())];
15+
LL + let _: [u8; faz(&())];
16+
|
1317

1418
error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
1519
--> $DIR/const-arg-in-const-arg.rs:21:23
@@ -22,7 +26,11 @@ note: the late bound lifetime parameter is introduced here
2226
|
2327
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
2428
| ^^
25-
= help: remove the explicit lifetime argument
29+
help: remove the explicit lifetime argument
30+
|
31+
LL - let _: [u8; faz::<'b>(&())];
32+
LL + let _: [u8; faz(&())];
33+
|
2634

2735
error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
2836
--> $DIR/const-arg-in-const-arg.rs:41:24
@@ -35,7 +43,11 @@ note: the late bound lifetime parameter is introduced here
3543
|
3644
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
3745
| ^^
38-
= help: remove the explicit lifetime argument
46+
help: remove the explicit lifetime argument
47+
|
48+
LL - let _: Foo<{ faz::<'a>(&()) }>;
49+
LL + let _: Foo<{ faz(&()) }>;
50+
|
3951

4052
error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
4153
--> $DIR/const-arg-in-const-arg.rs:44:24
@@ -48,7 +60,11 @@ note: the late bound lifetime parameter is introduced here
4860
|
4961
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
5062
| ^^
51-
= help: remove the explicit lifetime argument
63+
help: remove the explicit lifetime argument
64+
|
65+
LL - let _: Foo<{ faz::<'b>(&()) }>;
66+
LL + let _: Foo<{ faz(&()) }>;
67+
|
5268

5369
error: unconstrained generic constant
5470
--> $DIR/const-arg-in-const-arg.rs:13:12
@@ -109,7 +125,11 @@ note: the late bound lifetime parameter is introduced here
109125
|
110126
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
111127
| ^^
112-
= help: remove the explicit lifetime argument
128+
help: remove the explicit lifetime argument
129+
|
130+
LL - let _ = [0; faz::<'a>(&())];
131+
LL + let _ = [0; faz(&())];
132+
|
113133

114134
error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
115135
--> $DIR/const-arg-in-const-arg.rs:33:23
@@ -122,7 +142,11 @@ note: the late bound lifetime parameter is introduced here
122142
|
123143
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
124144
| ^^
125-
= help: remove the explicit lifetime argument
145+
help: remove the explicit lifetime argument
146+
|
147+
LL - let _ = [0; faz::<'b>(&())];
148+
LL + let _ = [0; faz(&())];
149+
|
126150

127151
error: unconstrained generic constant
128152
--> $DIR/const-arg-in-const-arg.rs:47:19
@@ -151,7 +175,11 @@ note: the late bound lifetime parameter is introduced here
151175
|
152176
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
153177
| ^^
154-
= help: remove the explicit lifetime argument
178+
help: remove the explicit lifetime argument
179+
|
180+
LL - let _ = Foo::<{ faz::<'a>(&()) }>;
181+
LL + let _ = Foo::<{ faz(&()) }>;
182+
|
155183

156184
error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
157185
--> $DIR/const-arg-in-const-arg.rs:55:27
@@ -164,7 +192,11 @@ note: the late bound lifetime parameter is introduced here
164192
|
165193
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
166194
| ^^
167-
= help: remove the explicit lifetime argument
195+
help: remove the explicit lifetime argument
196+
|
197+
LL - let _ = Foo::<{ faz::<'b>(&()) }>;
198+
LL + let _ = Foo::<{ faz(&()) }>;
199+
|
168200

169201
error: aborting due to 16 previous errors
170202

tests/ui/const-generics/const-arg-in-const-arg.min.stderr

+40-8
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,11 @@ note: the late bound lifetime parameter is introduced here
227227
|
228228
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
229229
| ^^
230-
= help: remove the explicit lifetime argument
230+
help: remove the explicit lifetime argument
231+
|
232+
LL - let _: [u8; faz::<'a>(&())];
233+
LL + let _: [u8; faz(&())];
234+
|
231235

232236
error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
233237
--> $DIR/const-arg-in-const-arg.rs:21:23
@@ -240,7 +244,11 @@ note: the late bound lifetime parameter is introduced here
240244
|
241245
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
242246
| ^^
243-
= help: remove the explicit lifetime argument
247+
help: remove the explicit lifetime argument
248+
|
249+
LL - let _: [u8; faz::<'b>(&())];
250+
LL + let _: [u8; faz(&())];
251+
|
244252

245253
error[E0747]: unresolved item provided when a constant was expected
246254
--> $DIR/const-arg-in-const-arg.rs:38:24
@@ -264,7 +272,11 @@ note: the late bound lifetime parameter is introduced here
264272
|
265273
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
266274
| ^^
267-
= help: remove the explicit lifetime argument
275+
help: remove the explicit lifetime argument
276+
|
277+
LL - let _: Foo<{ faz::<'a>(&()) }>;
278+
LL + let _: Foo<{ faz(&()) }>;
279+
|
268280

269281
error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
270282
--> $DIR/const-arg-in-const-arg.rs:44:24
@@ -277,7 +289,11 @@ note: the late bound lifetime parameter is introduced here
277289
|
278290
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
279291
| ^^
280-
= help: remove the explicit lifetime argument
292+
help: remove the explicit lifetime argument
293+
|
294+
LL - let _: Foo<{ faz::<'b>(&()) }>;
295+
LL + let _: Foo<{ faz(&()) }>;
296+
|
281297

282298
error: constant expression depends on a generic parameter
283299
--> $DIR/const-arg-in-const-arg.rs:25:17
@@ -309,7 +325,11 @@ note: the late bound lifetime parameter is introduced here
309325
|
310326
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
311327
| ^^
312-
= help: remove the explicit lifetime argument
328+
help: remove the explicit lifetime argument
329+
|
330+
LL - let _ = [0; faz::<'a>(&())];
331+
LL + let _ = [0; faz(&())];
332+
|
313333

314334
error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
315335
--> $DIR/const-arg-in-const-arg.rs:33:23
@@ -322,7 +342,11 @@ note: the late bound lifetime parameter is introduced here
322342
|
323343
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
324344
| ^^
325-
= help: remove the explicit lifetime argument
345+
help: remove the explicit lifetime argument
346+
|
347+
LL - let _ = [0; faz::<'b>(&())];
348+
LL + let _ = [0; faz(&())];
349+
|
326350

327351
error[E0747]: unresolved item provided when a constant was expected
328352
--> $DIR/const-arg-in-const-arg.rs:49:27
@@ -346,7 +370,11 @@ note: the late bound lifetime parameter is introduced here
346370
|
347371
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
348372
| ^^
349-
= help: remove the explicit lifetime argument
373+
help: remove the explicit lifetime argument
374+
|
375+
LL - let _ = Foo::<{ faz::<'a>(&()) }>;
376+
LL + let _ = Foo::<{ faz(&()) }>;
377+
|
350378

351379
error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
352380
--> $DIR/const-arg-in-const-arg.rs:55:27
@@ -359,7 +387,11 @@ note: the late bound lifetime parameter is introduced here
359387
|
360388
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
361389
| ^^
362-
= help: remove the explicit lifetime argument
390+
help: remove the explicit lifetime argument
391+
|
392+
LL - let _ = Foo::<{ faz::<'b>(&()) }>;
393+
LL + let _ = Foo::<{ faz(&()) }>;
394+
|
363395

364396
error: aborting due to 36 previous errors
365397

tests/ui/const-generics/issues/issue-83466.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ note: the late bound lifetime parameter is introduced here
99
|
1010
LL | fn func<'a, U>(self) -> U {
1111
| ^^
12-
= help: remove the explicit lifetime argument
12+
help: remove the explicit lifetime argument
13+
|
14+
LL - S.func::<'a, 10_u32>()
15+
LL + S.func::<10_u32>()
16+
|
1317

1418
error[E0747]: constant provided when a type was expected
1519
--> $DIR/issue-83466.rs:11:18

tests/ui/issues/issue-60622.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ note: the late bound lifetime parameter is introduced here
99
|
1010
LL | fn a(&self) {}
1111
| ^
12-
= help: remove the explicit lifetime argument
12+
help: remove the explicit lifetime argument
13+
|
14+
LL - b.a::<'_, T>();
15+
LL + b.a::<T>();
16+
|
1317

1418
error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
1519
--> $DIR/issue-60622.rs:10:7

tests/ui/issues/issue-72278.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ note: the late bound lifetime parameter is introduced here
99
|
1010
LL | fn func<'a, U>(&'a self) -> U {
1111
| ^^
12-
= help: remove the explicit lifetime argument
12+
help: remove the explicit lifetime argument
13+
|
14+
LL - S.func::<'a, U>()
15+
LL + S.func::<U>()
16+
|
1317

1418
error: aborting due to previous error
1519

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
4+
struct S;
5+
6+
impl S {
7+
fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
8+
fn late_implicit(self, _: &u8, _: &u8) {}
9+
fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
10+
fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
11+
fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
12+
fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} }
13+
fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} }
14+
fn life_and_type<'a, T>(self) -> &'a T { loop {} }
15+
}
16+
17+
fn method_call() {
18+
S.early(); // OK
19+
S.early::<'static, 'static>();
20+
//~^ ERROR method takes 2 lifetime arguments but 1 lifetime argument
21+
S.early::<'static, 'static, >();
22+
//~^ ERROR method takes 2 lifetime arguments but 3 lifetime arguments were supplied
23+
let _: &u8 = S.life_and_type::<'static>();
24+
S.life_and_type::<u8>();
25+
S.life_and_type::<'static, u8>();
26+
}
27+
28+
fn ufcs() {
29+
S::late(S, &0, &0); // OK
30+
S::late(S, &0, &0);
31+
//~^ ERROR cannot specify lifetime arguments explicitly
32+
S::late(S, &0, &0);
33+
//~^ ERROR cannot specify lifetime arguments explicitly
34+
S::late(S, &0, &0);
35+
//~^ ERROR cannot specify lifetime arguments explicitly
36+
S::late_early(S, &0); // OK
37+
S::late_early(S, &0);
38+
//~^ ERROR cannot specify lifetime arguments explicitly
39+
S::late_early(S, &0);
40+
//~^ ERROR cannot specify lifetime arguments explicitly
41+
42+
S::late_implicit(S, &0, &0); // OK
43+
S::late_implicit(S, &0, &0);
44+
//~^ ERROR cannot specify lifetime arguments explicitly
45+
S::late_implicit(S, &0, &0);
46+
//~^ ERROR cannot specify lifetime arguments explicitly
47+
S::late_implicit(S, &0, &0);
48+
//~^ ERROR cannot specify lifetime arguments explicitly
49+
S::late_implicit_early(S, &0); // OK
50+
S::late_implicit_early(S, &0);
51+
//~^ ERROR cannot specify lifetime arguments explicitly
52+
S::late_implicit_early(S, &0);
53+
//~^ ERROR cannot specify lifetime arguments explicitly
54+
S::late_implicit_self_early(&S); // OK
55+
S::late_implicit_self_early(&S);
56+
//~^ ERROR cannot specify lifetime arguments explicitly
57+
S::late_implicit_self_early(&S);
58+
//~^ ERROR cannot specify lifetime arguments explicitly
59+
S::late_unused_early(S); // OK
60+
S::late_unused_early(S);
61+
//~^ ERROR cannot specify lifetime arguments explicitly
62+
S::late_unused_early(S);
63+
//~^ ERROR cannot specify lifetime arguments explicitly
64+
65+
S::early(S); // OK
66+
S::early::<'static, 'static>(S);
67+
//~^ ERROR method takes 2 lifetime arguments but 1 lifetime argument
68+
S::early::<'static, 'static, >(S);
69+
//~^ ERROR method takes 2 lifetime arguments but 3 lifetime arguments were supplied
70+
let _: &u8 = S::life_and_type::<'static>(S);
71+
S::life_and_type::<u8>(S);
72+
S::life_and_type::<'static, u8>(S);
73+
}
74+
75+
fn main() {}

tests/ui/methods/method-call-lifetime-args-fail.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
14
struct S;
25

36
impl S {

0 commit comments

Comments
 (0)