Skip to content

Commit 0edf4da

Browse files
committed
Fix span of redundant generic arguments
1 parent 69b352e commit 0edf4da

File tree

5 files changed

+281
-124
lines changed

5 files changed

+281
-124
lines changed

compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs

+44-31
Original file line numberDiff line numberDiff line change
@@ -626,30 +626,35 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
626626
let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
627627

628628
let remove_lifetime_args = |err: &mut DiagnosticBuilder<'_>| {
629-
let idx_first_redundant_lt_args = self.num_expected_lifetime_args();
630-
let span_lo_redundant_lt_args =
631-
self.gen_args.args[idx_first_redundant_lt_args].span().shrink_to_lo();
632-
let span_hi_redundant_lt_args = self.gen_args.args
633-
[idx_first_redundant_lt_args + num_redundant_lt_args - 1]
634-
.span()
635-
.shrink_to_hi();
636-
let eat_comma =
637-
idx_first_redundant_lt_args + num_redundant_lt_args - 1 != self.gen_args.args.len();
638-
639-
let span_redundant_lt_args = if eat_comma {
640-
let span_hi = self.gen_args.args
641-
[idx_first_redundant_lt_args + num_redundant_lt_args - 1]
642-
.span()
643-
.shrink_to_hi();
644-
span_lo_redundant_lt_args.to(span_hi)
645-
} else {
646-
span_lo_redundant_lt_args.to(span_hi_redundant_lt_args)
647-
};
629+
let mut lt_arg_spans = Vec::new();
630+
let mut found_redundant = false;
631+
for arg in self.gen_args.args {
632+
if let hir::GenericArg::Lifetime(_) = arg {
633+
lt_arg_spans.push(arg.span());
634+
if lt_arg_spans.len() > self.num_expected_lifetime_args() {
635+
found_redundant = true;
636+
}
637+
} else if found_redundant {
638+
// Argument which is redundant and separated like this `'c`
639+
// is not included to avoid including `Bar` in span.
640+
// ```
641+
// type Foo<'a, T> = &'a T;
642+
// let _: Foo<'a, 'b, Bar, 'c>;
643+
// ```
644+
break;
645+
}
646+
}
647+
648+
let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
649+
let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
650+
651+
let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
648652
debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
649653

654+
let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
650655
let msg_lifetimes = format!(
651656
"remove {} {} argument{}",
652-
if num_redundant_args == 1 { "this" } else { "these" },
657+
if num_redundant_lt_args == 1 { "this" } else { "these" },
653658
"lifetime",
654659
pluralize!(num_redundant_lt_args),
655660
);
@@ -663,26 +668,34 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
663668
};
664669

665670
let remove_type_or_const_args = |err: &mut DiagnosticBuilder<'_>| {
666-
let idx_first_redundant_type_or_const_args = self.get_lifetime_args_offset()
667-
+ num_redundant_lt_args
668-
+ self.num_expected_type_or_const_args();
671+
let mut gen_arg_spans = Vec::new();
672+
let mut found_redundant = false;
673+
for arg in self.gen_args.args {
674+
match arg {
675+
hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => {
676+
gen_arg_spans.push(arg.span());
677+
if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
678+
found_redundant = true;
679+
}
680+
}
681+
_ if found_redundant => break,
682+
_ => {}
683+
}
684+
}
669685

670686
let span_lo_redundant_type_or_const_args =
671-
self.gen_args.args[idx_first_redundant_type_or_const_args].span().shrink_to_lo();
672-
673-
let span_hi_redundant_type_or_const_args = self.gen_args.args
674-
[idx_first_redundant_type_or_const_args + num_redundant_type_or_const_args - 1]
675-
.span()
676-
.shrink_to_hi();
687+
gen_arg_spans[self.num_expected_type_or_const_args()];
688+
let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
677689

678690
let span_redundant_type_or_const_args =
679691
span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);
680-
681692
debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
682693

694+
let num_redundant_gen_args =
695+
gen_arg_spans.len() - self.num_expected_type_or_const_args();
683696
let msg_types_or_consts = format!(
684697
"remove {} {} argument{}",
685-
if num_redundant_args == 1 { "this" } else { "these" },
698+
if num_redundant_gen_args == 1 { "this" } else { "these" },
686699
"generic",
687700
pluralize!(num_redundant_type_or_const_args),
688701
);

src/test/ui/error-codes/E0107.rs

+26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
struct Foo<'a>(&'a str);
22
struct Buzz<'a, 'b>(&'a str, &'b str);
3+
struct Qux<'a, T>(&'a T);
4+
struct Quux<T>(T);
35

46
enum Bar {
57
A,
@@ -19,6 +21,30 @@ struct Baz<'a, 'b, 'c> {
1921
foo2: Foo<'a, 'b, 'c>,
2022
//~^ ERROR this struct takes 1 lifetime argument
2123
//~| HELP remove these lifetime arguments
24+
25+
qux1: Qux<'a, 'b, i32>,
26+
//~^ ERROR this struct takes 1 lifetime argument
27+
//~| HELP remove this lifetime argument
28+
29+
qux2: Qux<'a, i32, 'b>,
30+
//~^ ERROR this struct takes 1 lifetime argument
31+
//~| HELP remove this lifetime argument
32+
33+
qux3: Qux<'a, 'b, 'c, i32>,
34+
//~^ ERROR this struct takes 1 lifetime argument
35+
//~| HELP remove these lifetime arguments
36+
37+
qux4: Qux<'a, i32, 'b, 'c>,
38+
//~^ ERROR this struct takes 1 lifetime argument
39+
//~| HELP remove these lifetime arguments
40+
41+
qux5: Qux<'a, 'b, i32, 'c>,
42+
//~^ ERROR this struct takes 1 lifetime argument
43+
//~| HELP remove this lifetime argument
44+
45+
quux: Quux<'a, i32, 'b>,
46+
//~^ ERROR this struct takes 0 lifetime arguments
47+
//~| HELP remove this lifetime argument
2248
}
2349

2450
fn main() {}

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

+89-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0107]: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
2-
--> $DIR/E0107.rs:11:11
2+
--> $DIR/E0107.rs:13:11
33
|
44
LL | buzz: Buzz<'a>,
55
| ^^^^ -- supplied 1 lifetime argument
@@ -17,21 +17,21 @@ LL | buzz: Buzz<'a, 'a>,
1717
| ^^^^
1818

1919
error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
20-
--> $DIR/E0107.rs:15:10
20+
--> $DIR/E0107.rs:17:10
2121
|
2222
LL | bar: Bar<'a>,
2323
| ^^^---- help: remove these generics
2424
| |
2525
| expected 0 lifetime arguments
2626
|
2727
note: enum defined here, with 0 lifetime parameters
28-
--> $DIR/E0107.rs:4:6
28+
--> $DIR/E0107.rs:6:6
2929
|
3030
LL | enum Bar {
3131
| ^^^
3232

3333
error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
34-
--> $DIR/E0107.rs:19:11
34+
--> $DIR/E0107.rs:21:11
3535
|
3636
LL | foo2: Foo<'a, 'b, 'c>,
3737
| ^^^ ------ help: remove these lifetime arguments
@@ -44,6 +44,90 @@ note: struct defined here, with 1 lifetime parameter: `'a`
4444
LL | struct Foo<'a>(&'a str);
4545
| ^^^ --
4646

47-
error: aborting due to 3 previous errors
47+
error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
48+
--> $DIR/E0107.rs:25:11
49+
|
50+
LL | qux1: Qux<'a, 'b, i32>,
51+
| ^^^ -- help: remove this lifetime argument
52+
| |
53+
| expected 1 lifetime argument
54+
|
55+
note: struct defined here, with 1 lifetime parameter: `'a`
56+
--> $DIR/E0107.rs:3:8
57+
|
58+
LL | struct Qux<'a, T>(&'a T);
59+
| ^^^ --
60+
61+
error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
62+
--> $DIR/E0107.rs:29:11
63+
|
64+
LL | qux2: Qux<'a, i32, 'b>,
65+
| ^^^ -- help: remove this lifetime argument
66+
| |
67+
| expected 1 lifetime argument
68+
|
69+
note: struct defined here, with 1 lifetime parameter: `'a`
70+
--> $DIR/E0107.rs:3:8
71+
|
72+
LL | struct Qux<'a, T>(&'a T);
73+
| ^^^ --
74+
75+
error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
76+
--> $DIR/E0107.rs:33:11
77+
|
78+
LL | qux3: Qux<'a, 'b, 'c, i32>,
79+
| ^^^ ------ help: remove these lifetime arguments
80+
| |
81+
| expected 1 lifetime argument
82+
|
83+
note: struct defined here, with 1 lifetime parameter: `'a`
84+
--> $DIR/E0107.rs:3:8
85+
|
86+
LL | struct Qux<'a, T>(&'a T);
87+
| ^^^ --
88+
89+
error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
90+
--> $DIR/E0107.rs:37:11
91+
|
92+
LL | qux4: Qux<'a, i32, 'b, 'c>,
93+
| ^^^ ------ help: remove these lifetime arguments
94+
| |
95+
| expected 1 lifetime argument
96+
|
97+
note: struct defined here, with 1 lifetime parameter: `'a`
98+
--> $DIR/E0107.rs:3:8
99+
|
100+
LL | struct Qux<'a, T>(&'a T);
101+
| ^^^ --
102+
103+
error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
104+
--> $DIR/E0107.rs:41:11
105+
|
106+
LL | qux5: Qux<'a, 'b, i32, 'c>,
107+
| ^^^ -- help: remove this lifetime argument
108+
| |
109+
| expected 1 lifetime argument
110+
|
111+
note: struct defined here, with 1 lifetime parameter: `'a`
112+
--> $DIR/E0107.rs:3:8
113+
|
114+
LL | struct Qux<'a, T>(&'a T);
115+
| ^^^ --
116+
117+
error[E0107]: this struct takes 0 lifetime arguments but 2 lifetime arguments were supplied
118+
--> $DIR/E0107.rs:45:11
119+
|
120+
LL | quux: Quux<'a, i32, 'b>,
121+
| ^^^^ -- help: remove this lifetime argument
122+
| |
123+
| expected 0 lifetime arguments
124+
|
125+
note: struct defined here, with 0 lifetime parameters
126+
--> $DIR/E0107.rs:4:8
127+
|
128+
LL | struct Quux<T>(T);
129+
| ^^^^
130+
131+
error: aborting due to 9 previous errors
48132

49133
For more information about this error, try `rustc --explain E0107`.

src/test/ui/generics/wrong-number-of-args.rs

+6
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ mod lifetime_and_type {
6666
//~| ERROR missing lifetime specifier
6767
//~| HELP consider introducing
6868
//~| HELP add missing
69+
70+
type F = Ty<'static, usize, 'static, usize>;
71+
//~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments
72+
//~| ERROR this struct takes 1 generic argument but 2 generic arguments
73+
//~| HELP remove this lifetime argument
74+
//~| HELP remove this generic argument
6975
}
7076

7177
mod type_and_type_and_type {

0 commit comments

Comments
 (0)