Rollup merge of #57886 - davidtwco:issue-57385, r=estebank
Add suggestion for moving type declaration before associated type bindings in generic arguments. Fixes #57385. r? @estebank
This commit is contained in:
commit
7768358e72
4 changed files with 305 additions and 29 deletions
|
@ -5543,22 +5543,31 @@ impl<'a> Parser<'a> {
|
||||||
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
|
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
let mut bindings = Vec::new();
|
let mut bindings = Vec::new();
|
||||||
|
|
||||||
let mut seen_type = false;
|
let mut seen_type = false;
|
||||||
let mut seen_binding = false;
|
let mut seen_binding = false;
|
||||||
let mut first_type_or_binding_span: Option<Span> = None;
|
|
||||||
let mut bad_lifetime_pos = vec![];
|
|
||||||
let mut last_comma_span = None;
|
let mut last_comma_span = None;
|
||||||
let mut suggestions = vec![];
|
let mut first_type_or_binding_span: Option<Span> = None;
|
||||||
|
let mut first_binding_span: Option<Span> = None;
|
||||||
|
|
||||||
|
let mut bad_lifetime_pos = vec![];
|
||||||
|
let mut bad_type_pos = vec![];
|
||||||
|
|
||||||
|
let mut lifetime_suggestions = vec![];
|
||||||
|
let mut type_suggestions = vec![];
|
||||||
loop {
|
loop {
|
||||||
if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
|
if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
|
||||||
// Parse lifetime argument.
|
// Parse lifetime argument.
|
||||||
args.push(GenericArg::Lifetime(self.expect_lifetime()));
|
args.push(GenericArg::Lifetime(self.expect_lifetime()));
|
||||||
|
|
||||||
if seen_type || seen_binding {
|
if seen_type || seen_binding {
|
||||||
let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
|
let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
|
||||||
bad_lifetime_pos.push(self.prev_span);
|
bad_lifetime_pos.push(self.prev_span);
|
||||||
|
|
||||||
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
|
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
|
||||||
suggestions.push((remove_sp, String::new()));
|
lifetime_suggestions.push((remove_sp, String::new()));
|
||||||
suggestions.push((
|
lifetime_suggestions.push((
|
||||||
first_type_or_binding_span.unwrap().shrink_to_lo(),
|
first_type_or_binding_span.unwrap().shrink_to_lo(),
|
||||||
format!("{}, ", snippet)));
|
format!("{}, ", snippet)));
|
||||||
}
|
}
|
||||||
|
@ -5576,24 +5585,29 @@ impl<'a> Parser<'a> {
|
||||||
ty,
|
ty,
|
||||||
span,
|
span,
|
||||||
});
|
});
|
||||||
|
|
||||||
seen_binding = true;
|
seen_binding = true;
|
||||||
if first_type_or_binding_span.is_none() {
|
if first_type_or_binding_span.is_none() {
|
||||||
first_type_or_binding_span = Some(span);
|
first_type_or_binding_span = Some(span);
|
||||||
}
|
}
|
||||||
|
if first_binding_span.is_none() {
|
||||||
|
first_binding_span = Some(span);
|
||||||
|
}
|
||||||
} else if self.check_type() {
|
} else if self.check_type() {
|
||||||
// Parse type argument.
|
// Parse type argument.
|
||||||
let ty_param = self.parse_ty()?;
|
let ty_param = self.parse_ty()?;
|
||||||
if seen_binding {
|
if seen_binding {
|
||||||
self.struct_span_err(
|
let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
|
||||||
ty_param.span,
|
bad_type_pos.push(self.prev_span);
|
||||||
"type parameters must be declared prior to associated type bindings"
|
|
||||||
)
|
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
|
||||||
.span_label(
|
type_suggestions.push((remove_sp, String::new()));
|
||||||
ty_param.span,
|
type_suggestions.push((
|
||||||
"must be declared prior to associated type bindings",
|
first_binding_span.unwrap().shrink_to_lo(),
|
||||||
)
|
format!("{}, ", snippet)));
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if first_type_or_binding_span.is_none() {
|
if first_type_or_binding_span.is_none() {
|
||||||
first_type_or_binding_span = Some(ty_param.span);
|
first_type_or_binding_span = Some(ty_param.span);
|
||||||
}
|
}
|
||||||
|
@ -5609,28 +5623,94 @@ impl<'a> Parser<'a> {
|
||||||
last_comma_span = Some(self.prev_span);
|
last_comma_span = Some(self.prev_span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !bad_lifetime_pos.is_empty() {
|
|
||||||
let mut err = self.struct_span_err(
|
self.maybe_report_incorrect_generic_argument_order(
|
||||||
|
bad_lifetime_pos, bad_type_pos, lifetime_suggestions, type_suggestions
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok((args, bindings))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maybe report an error about incorrect generic argument order - "lifetime parameters
|
||||||
|
/// must be declared before type parameters", "type parameters must be declared before
|
||||||
|
/// associated type bindings" or both.
|
||||||
|
fn maybe_report_incorrect_generic_argument_order(
|
||||||
|
&self,
|
||||||
|
bad_lifetime_pos: Vec<Span>,
|
||||||
|
bad_type_pos: Vec<Span>,
|
||||||
|
lifetime_suggestions: Vec<(Span, String)>,
|
||||||
|
type_suggestions: Vec<(Span, String)>,
|
||||||
|
) {
|
||||||
|
let mut err = if !bad_lifetime_pos.is_empty() && !bad_type_pos.is_empty() {
|
||||||
|
let mut positions = bad_lifetime_pos.clone();
|
||||||
|
positions.extend_from_slice(&bad_type_pos);
|
||||||
|
|
||||||
|
self.struct_span_err(
|
||||||
|
positions,
|
||||||
|
"generic arguments must declare lifetimes, types and associated type bindings in \
|
||||||
|
that order",
|
||||||
|
)
|
||||||
|
} else if !bad_lifetime_pos.is_empty() {
|
||||||
|
self.struct_span_err(
|
||||||
bad_lifetime_pos.clone(),
|
bad_lifetime_pos.clone(),
|
||||||
"lifetime parameters must be declared prior to type parameters"
|
"lifetime parameters must be declared prior to type parameters"
|
||||||
);
|
)
|
||||||
|
} else if !bad_type_pos.is_empty() {
|
||||||
|
self.struct_span_err(
|
||||||
|
bad_type_pos.clone(),
|
||||||
|
"type parameters must be declared prior to associated type bindings"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if !bad_lifetime_pos.is_empty() {
|
||||||
for sp in &bad_lifetime_pos {
|
for sp in &bad_lifetime_pos {
|
||||||
err.span_label(*sp, "must be declared prior to type parameters");
|
err.span_label(*sp, "must be declared prior to type parameters");
|
||||||
}
|
}
|
||||||
if !suggestions.is_empty() {
|
}
|
||||||
|
|
||||||
|
if !bad_type_pos.is_empty() {
|
||||||
|
for sp in &bad_type_pos {
|
||||||
|
err.span_label(*sp, "must be declared prior to associated type bindings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !lifetime_suggestions.is_empty() && !type_suggestions.is_empty() {
|
||||||
|
let mut suggestions = lifetime_suggestions;
|
||||||
|
suggestions.extend_from_slice(&type_suggestions);
|
||||||
|
|
||||||
|
let plural = bad_lifetime_pos.len() + bad_type_pos.len() > 1;
|
||||||
|
err.multipart_suggestion_with_applicability(
|
||||||
|
&format!(
|
||||||
|
"move the parameter{}",
|
||||||
|
if plural { "s" } else { "" },
|
||||||
|
),
|
||||||
|
suggestions,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else if !lifetime_suggestions.is_empty() {
|
||||||
err.multipart_suggestion_with_applicability(
|
err.multipart_suggestion_with_applicability(
|
||||||
&format!(
|
&format!(
|
||||||
"move the lifetime parameter{} prior to the first type parameter",
|
"move the lifetime parameter{} prior to the first type parameter",
|
||||||
if bad_lifetime_pos.len() > 1 { "s" } else { "" },
|
if bad_lifetime_pos.len() > 1 { "s" } else { "" },
|
||||||
),
|
),
|
||||||
suggestions,
|
lifetime_suggestions,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else if !type_suggestions.is_empty() {
|
||||||
|
err.multipart_suggestion_with_applicability(
|
||||||
|
&format!(
|
||||||
|
"move the type parameter{} prior to the first associated type binding",
|
||||||
|
if bad_type_pos.len() > 1 { "s" } else { "" },
|
||||||
|
),
|
||||||
|
type_suggestions,
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
Ok((args, bindings))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses an optional `where` clause and places it in `generics`.
|
/// Parses an optional `where` clause and places it in `generics`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -3,6 +3,10 @@ error: type parameters must be declared prior to associated type bindings
|
||||||
|
|
|
|
||||||
LL | pub fn test<W, I: Trait<Item=(), W> >() {}
|
LL | pub fn test<W, I: Trait<Item=(), W> >() {}
|
||||||
| ^ must be declared prior to associated type bindings
|
| ^ must be declared prior to associated type bindings
|
||||||
|
help: move the type parameter prior to the first associated type binding
|
||||||
|
|
|
||||||
|
LL | pub fn test<W, I: Trait<W, Item=()> >() {}
|
||||||
|
| ^^ --
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
85
src/test/ui/suggestions/suggest-move-types.rs
Normal file
85
src/test/ui/suggestions/suggest-move-types.rs
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
// This test verifies that the suggestion to move types before associated type bindings
|
||||||
|
// is correct.
|
||||||
|
|
||||||
|
trait One<T> {
|
||||||
|
type A;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait OneWithLifetime<'a, T> {
|
||||||
|
type A;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Three<T, U, V> {
|
||||||
|
type A;
|
||||||
|
type B;
|
||||||
|
type C;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ThreeWithLifetime<'a, 'b, 'c, T, U, V> {
|
||||||
|
type A;
|
||||||
|
type B;
|
||||||
|
type C;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct A<T, M: One<A=(), T>> { //~ ERROR type parameters must be declared
|
||||||
|
m: M,
|
||||||
|
t: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
|
||||||
|
//~^ ERROR generic arguments must declare lifetimes, types and associated type bindings in that order
|
||||||
|
m: M,
|
||||||
|
t: &'a T,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> { //~ ERROR type parameters must be declared
|
||||||
|
m: M,
|
||||||
|
t: T,
|
||||||
|
u: U,
|
||||||
|
v: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
|
||||||
|
//~^ ERROR generic arguments must declare lifetimes, types and associated type bindings in that order
|
||||||
|
m: M,
|
||||||
|
t: &'a T,
|
||||||
|
u: &'b U,
|
||||||
|
v: &'c V,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> { //~ ERROR type parameters must be declared
|
||||||
|
m: M,
|
||||||
|
t: T,
|
||||||
|
u: U,
|
||||||
|
v: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
|
||||||
|
//~^ ERROR generic arguments must declare lifetimes, types and associated type bindings in that order
|
||||||
|
m: M,
|
||||||
|
t: &'a T,
|
||||||
|
u: &'b U,
|
||||||
|
v: &'c V,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> { //~ ERROR type parameters must be declared
|
||||||
|
m: M,
|
||||||
|
t: T,
|
||||||
|
u: U,
|
||||||
|
v: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
|
||||||
|
//~^ ERROR generic arguments must declare lifetimes, types and associated type bindings in that order
|
||||||
|
m: M,
|
||||||
|
t: &'a T,
|
||||||
|
u: &'b U,
|
||||||
|
v: &'c V,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
107
src/test/ui/suggestions/suggest-move-types.stderr
Normal file
107
src/test/ui/suggestions/suggest-move-types.stderr
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
error: type parameters must be declared prior to associated type bindings
|
||||||
|
--> $DIR/suggest-move-types.rs:28:26
|
||||||
|
|
|
||||||
|
LL | struct A<T, M: One<A=(), T>> { //~ ERROR type parameters must be declared
|
||||||
|
| ^ must be declared prior to associated type bindings
|
||||||
|
help: move the type parameter prior to the first associated type binding
|
||||||
|
|
|
||||||
|
LL | struct A<T, M: One<T, A=()>> { //~ ERROR type parameters must be declared
|
||||||
|
| ^^ --
|
||||||
|
|
||||||
|
error: generic arguments must declare lifetimes, types and associated type bindings in that order
|
||||||
|
--> $DIR/suggest-move-types.rs:34:46
|
||||||
|
|
|
||||||
|
LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
|
||||||
|
| ^ ^^ must be declared prior to type parameters
|
||||||
|
| |
|
||||||
|
| must be declared prior to associated type bindings
|
||||||
|
help: move the parameters
|
||||||
|
|
|
||||||
|
LL | struct Al<'a, T, M: OneWithLifetime<'a, T, A=()>> {
|
||||||
|
| ^^^ ^^ --
|
||||||
|
|
||||||
|
error: type parameters must be declared prior to associated type bindings
|
||||||
|
--> $DIR/suggest-move-types.rs:40:46
|
||||||
|
|
|
||||||
|
LL | struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> { //~ ERROR type parameters must be declared
|
||||||
|
| ^ ^ ^ must be declared prior to associated type bindings
|
||||||
|
| | |
|
||||||
|
| | must be declared prior to associated type bindings
|
||||||
|
| must be declared prior to associated type bindings
|
||||||
|
help: move the type parameters prior to the first associated type binding
|
||||||
|
|
|
||||||
|
LL | struct B<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> { //~ ERROR type parameters must be declared
|
||||||
|
| ^^ ^^ ^^ --
|
||||||
|
|
||||||
|
error: generic arguments must declare lifetimes, types and associated type bindings in that order
|
||||||
|
--> $DIR/suggest-move-types.rs:47:80
|
||||||
|
|
|
||||||
|
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
|
||||||
|
| ^ ^ ^ ^^ ^^ ^^ must be declared prior to type parameters
|
||||||
|
| | | | | |
|
||||||
|
| | | | | must be declared prior to type parameters
|
||||||
|
| | | | must be declared prior to type parameters
|
||||||
|
| | | must be declared prior to associated type bindings
|
||||||
|
| | must be declared prior to associated type bindings
|
||||||
|
| must be declared prior to associated type bindings
|
||||||
|
help: move the parameters
|
||||||
|
|
|
||||||
|
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A=(), B=(), C=()>> {
|
||||||
|
| ^^^ ^^^ ^^^ ^^ ^^ ^^ --
|
||||||
|
|
||||||
|
error: type parameters must be declared prior to associated type bindings
|
||||||
|
--> $DIR/suggest-move-types.rs:55:49
|
||||||
|
|
|
||||||
|
LL | struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> { //~ ERROR type parameters must be declared
|
||||||
|
| ^ ^ must be declared prior to associated type bindings
|
||||||
|
| |
|
||||||
|
| must be declared prior to associated type bindings
|
||||||
|
help: move the type parameters prior to the first associated type binding
|
||||||
|
|
|
||||||
|
LL | struct C<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> { //~ ERROR type parameters must be declared
|
||||||
|
| ^^ ^^ --
|
||||||
|
|
||||||
|
error: generic arguments must declare lifetimes, types and associated type bindings in that order
|
||||||
|
--> $DIR/suggest-move-types.rs:62:56
|
||||||
|
|
|
||||||
|
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
|
||||||
|
| ^^ ^ ^^ ^ ^^ must be declared prior to type parameters
|
||||||
|
| | | | |
|
||||||
|
| | | | must be declared prior to associated type bindings
|
||||||
|
| | | must be declared prior to type parameters
|
||||||
|
| | must be declared prior to associated type bindings
|
||||||
|
| must be declared prior to type parameters
|
||||||
|
help: move the parameters
|
||||||
|
|
|
||||||
|
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A=(), B=(), C=()>> {
|
||||||
|
| ^^^ ^^^ ^^^ -- ^^ ^^ --
|
||||||
|
|
||||||
|
error: type parameters must be declared prior to associated type bindings
|
||||||
|
--> $DIR/suggest-move-types.rs:70:43
|
||||||
|
|
|
||||||
|
LL | struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> { //~ ERROR type parameters must be declared
|
||||||
|
| ^ ^ must be declared prior to associated type bindings
|
||||||
|
| |
|
||||||
|
| must be declared prior to associated type bindings
|
||||||
|
help: move the type parameters prior to the first associated type binding
|
||||||
|
|
|
||||||
|
LL | struct D<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> { //~ ERROR type parameters must be declared
|
||||||
|
| ^^ ^^ -- --
|
||||||
|
|
||||||
|
error: generic arguments must declare lifetimes, types and associated type bindings in that order
|
||||||
|
--> $DIR/suggest-move-types.rs:77:56
|
||||||
|
|
|
||||||
|
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
|
||||||
|
| ^^ ^ ^^ ^ ^^ must be declared prior to type parameters
|
||||||
|
| | | | |
|
||||||
|
| | | | must be declared prior to associated type bindings
|
||||||
|
| | | must be declared prior to type parameters
|
||||||
|
| | must be declared prior to associated type bindings
|
||||||
|
| must be declared prior to type parameters
|
||||||
|
help: move the parameters
|
||||||
|
|
|
||||||
|
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A=(), B=(), C=()>> {
|
||||||
|
| ^^^ ^^^ ^^^ -- ^^ ^^ -- --
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue