Skip to content

Commit

Permalink
Fix span of redundant generic arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
0yoyoyo committed May 30, 2021
1 parent 69b352e commit 0edf4da
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 124 deletions.
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
@@ -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
@@ -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
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

0 comments on commit 0edf4da

Please sign in to comment.