Skip to content

Fix span of redundant generic arguments #85597

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -626,30 +626,35 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();

let remove_lifetime_args = |err: &mut DiagnosticBuilder<'_>| {
let idx_first_redundant_lt_args = self.num_expected_lifetime_args();
let span_lo_redundant_lt_args =
self.gen_args.args[idx_first_redundant_lt_args].span().shrink_to_lo();
let span_hi_redundant_lt_args = self.gen_args.args
[idx_first_redundant_lt_args + num_redundant_lt_args - 1]
.span()
.shrink_to_hi();
let eat_comma =
idx_first_redundant_lt_args + num_redundant_lt_args - 1 != self.gen_args.args.len();

let span_redundant_lt_args = if eat_comma {
let span_hi = self.gen_args.args
[idx_first_redundant_lt_args + num_redundant_lt_args - 1]
.span()
.shrink_to_hi();
span_lo_redundant_lt_args.to(span_hi)
} else {
span_lo_redundant_lt_args.to(span_hi_redundant_lt_args)
};
let mut lt_arg_spans = Vec::new();
let mut found_redundant = false;
for arg in self.gen_args.args {
if let hir::GenericArg::Lifetime(_) = arg {
lt_arg_spans.push(arg.span());
if lt_arg_spans.len() > self.num_expected_lifetime_args() {
found_redundant = true;
}
} else if found_redundant {
// Argument which is redundant and separated like this `'c`
// is not included to avoid including `Bar` in span.
// ```
// type Foo<'a, T> = &'a T;
// let _: Foo<'a, 'b, Bar, 'c>;
// ```
break;
}
}

let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];

let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);

let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
let msg_lifetimes = format!(
"remove {} {} argument{}",
if num_redundant_args == 1 { "this" } else { "these" },
if num_redundant_lt_args == 1 { "this" } else { "these" },
"lifetime",
pluralize!(num_redundant_lt_args),
);
Expand All @@ -663,26 +668,34 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
};

let remove_type_or_const_args = |err: &mut DiagnosticBuilder<'_>| {
let idx_first_redundant_type_or_const_args = self.get_lifetime_args_offset()
+ num_redundant_lt_args
+ self.num_expected_type_or_const_args();
let mut gen_arg_spans = Vec::new();
let mut found_redundant = false;
for arg in self.gen_args.args {
match arg {
hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => {
gen_arg_spans.push(arg.span());
if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
found_redundant = true;
}
}
_ if found_redundant => break,
_ => {}
}
}

let span_lo_redundant_type_or_const_args =
self.gen_args.args[idx_first_redundant_type_or_const_args].span().shrink_to_lo();

let span_hi_redundant_type_or_const_args = self.gen_args.args
[idx_first_redundant_type_or_const_args + num_redundant_type_or_const_args - 1]
.span()
.shrink_to_hi();
gen_arg_spans[self.num_expected_type_or_const_args()];
let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];

let span_redundant_type_or_const_args =
span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);

debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);

let num_redundant_gen_args =
gen_arg_spans.len() - self.num_expected_type_or_const_args();
let msg_types_or_consts = format!(
"remove {} {} argument{}",
if num_redundant_args == 1 { "this" } else { "these" },
if num_redundant_gen_args == 1 { "this" } else { "these" },
"generic",
pluralize!(num_redundant_type_or_const_args),
);
Expand Down
26 changes: 26 additions & 0 deletions src/test/ui/error-codes/E0107.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
struct Foo<'a>(&'a str);
struct Buzz<'a, 'b>(&'a str, &'b str);
struct Qux<'a, T>(&'a T);
struct Quux<T>(T);

enum Bar {
A,
Expand All @@ -19,6 +21,30 @@ struct Baz<'a, 'b, 'c> {
foo2: Foo<'a, 'b, 'c>,
//~^ ERROR this struct takes 1 lifetime argument
//~| HELP remove these lifetime arguments

qux1: Qux<'a, 'b, i32>,
//~^ ERROR this struct takes 1 lifetime argument
//~| HELP remove this lifetime argument

qux2: Qux<'a, i32, 'b>,
//~^ ERROR this struct takes 1 lifetime argument
//~| HELP remove this lifetime argument

qux3: Qux<'a, 'b, 'c, i32>,
//~^ ERROR this struct takes 1 lifetime argument
//~| HELP remove these lifetime arguments

qux4: Qux<'a, i32, 'b, 'c>,
//~^ ERROR this struct takes 1 lifetime argument
//~| HELP remove these lifetime arguments

qux5: Qux<'a, 'b, i32, 'c>,
//~^ ERROR this struct takes 1 lifetime argument
//~| HELP remove this lifetime argument

quux: Quux<'a, i32, 'b>,
//~^ ERROR this struct takes 0 lifetime arguments
//~| HELP remove this lifetime argument
}

fn main() {}
94 changes: 89 additions & 5 deletions src/test/ui/error-codes/E0107.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0107]: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/E0107.rs:11:11
--> $DIR/E0107.rs:13:11
|
LL | buzz: Buzz<'a>,
| ^^^^ -- supplied 1 lifetime argument
Expand All @@ -17,21 +17,21 @@ LL | buzz: Buzz<'a, 'a>,
| ^^^^

error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/E0107.rs:15:10
--> $DIR/E0107.rs:17:10
|
LL | bar: Bar<'a>,
| ^^^---- help: remove these generics
| |
| expected 0 lifetime arguments
|
note: enum defined here, with 0 lifetime parameters
--> $DIR/E0107.rs:4:6
--> $DIR/E0107.rs:6:6
|
LL | enum Bar {
| ^^^

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

error: aborting due to 3 previous errors
error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
--> $DIR/E0107.rs:25:11
|
LL | qux1: Qux<'a, 'b, i32>,
| ^^^ -- help: remove this lifetime argument
| |
| expected 1 lifetime argument
|
note: struct defined here, with 1 lifetime parameter: `'a`
--> $DIR/E0107.rs:3:8
|
LL | struct Qux<'a, T>(&'a T);
| ^^^ --

error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
--> $DIR/E0107.rs:29:11
|
LL | qux2: Qux<'a, i32, 'b>,
| ^^^ -- help: remove this lifetime argument
| |
| expected 1 lifetime argument
|
note: struct defined here, with 1 lifetime parameter: `'a`
--> $DIR/E0107.rs:3:8
|
LL | struct Qux<'a, T>(&'a T);
| ^^^ --

error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
--> $DIR/E0107.rs:33:11
|
LL | qux3: Qux<'a, 'b, 'c, i32>,
| ^^^ ------ help: remove these lifetime arguments
| |
| expected 1 lifetime argument
|
note: struct defined here, with 1 lifetime parameter: `'a`
--> $DIR/E0107.rs:3:8
|
LL | struct Qux<'a, T>(&'a T);
| ^^^ --

error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
--> $DIR/E0107.rs:37:11
|
LL | qux4: Qux<'a, i32, 'b, 'c>,
| ^^^ ------ help: remove these lifetime arguments
| |
| expected 1 lifetime argument
|
note: struct defined here, with 1 lifetime parameter: `'a`
--> $DIR/E0107.rs:3:8
|
LL | struct Qux<'a, T>(&'a T);
| ^^^ --

error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
--> $DIR/E0107.rs:41:11
|
LL | qux5: Qux<'a, 'b, i32, 'c>,
| ^^^ -- help: remove this lifetime argument
| |
| expected 1 lifetime argument
|
note: struct defined here, with 1 lifetime parameter: `'a`
--> $DIR/E0107.rs:3:8
|
LL | struct Qux<'a, T>(&'a T);
| ^^^ --

error[E0107]: this struct takes 0 lifetime arguments but 2 lifetime arguments were supplied
--> $DIR/E0107.rs:45:11
|
LL | quux: Quux<'a, i32, 'b>,
| ^^^^ -- help: remove this lifetime argument
| |
| expected 0 lifetime arguments
|
note: struct defined here, with 0 lifetime parameters
--> $DIR/E0107.rs:4:8
|
LL | struct Quux<T>(T);
| ^^^^

error: aborting due to 9 previous errors

For more information about this error, try `rustc --explain E0107`.
6 changes: 6 additions & 0 deletions src/test/ui/generics/wrong-number-of-args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ mod lifetime_and_type {
//~| ERROR missing lifetime specifier
//~| HELP consider introducing
//~| HELP add missing

type F = Ty<'static, usize, 'static, usize>;
//~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments
//~| ERROR this struct takes 1 generic argument but 2 generic arguments
//~| HELP remove this lifetime argument
//~| HELP remove this generic argument
}

mod type_and_type_and_type {
Expand Down
Loading