Skip to content

Commit

Permalink
Combining move lifetime and type suggestions.
Browse files Browse the repository at this point in the history
This commit combines the move lifetime and move type suggestions so that
when rustfix applies them they don't conflict with each other.
  • Loading branch information
davidtwco committed Jan 25, 2019
1 parent 463e623 commit 7a0abbf
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 35 deletions.
103 changes: 73 additions & 30 deletions src/libsyntax/parse/parser.rs
Expand Up @@ -5611,49 +5611,92 @@ impl<'a> Parser<'a> {
}
}

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(),
"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 {
err.span_label(*sp, "must be declared prior to type parameters");
}
if !lifetime_suggestions.is_empty() {
err.multipart_suggestion_with_applicability(
&format!(
"move the lifetime parameter{} prior to the first type parameter",
if bad_lifetime_pos.len() > 1 { "s" } else { "" },
),
lifetime_suggestions,
Applicability::MachineApplicable,
);
}
err.emit();
}

if !bad_type_pos.is_empty() {
let mut err = self.struct_span_err(
bad_type_pos.clone(),
"type parameters must be declared prior to associated type bindings"
);
for sp in &bad_type_pos {
err.span_label(*sp, "must be declared prior to associated type bindings");
}
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,
);
}
err.emit();
}

Ok((args, 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(
&format!(
"move the lifetime parameter{} prior to the first type parameter",
if bad_lifetime_pos.len() > 1 { "s" } else { "" },
),
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,
);
}

err.emit();
}

/// Parses an optional `where` clause and places it in `generics`.
Expand Down
43 changes: 43 additions & 0 deletions src/test/ui/suggestions/suggest-move-types.rs
@@ -1,3 +1,5 @@
// ignore-tidy-linelength

#![allow(warnings)]

// This test verifies that the suggestion to move types before associated type bindings
Expand All @@ -7,36 +9,77 @@ 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() {}
68 changes: 63 additions & 5 deletions src/test/ui/suggestions/suggest-move-types.stderr
@@ -1,5 +1,5 @@
error: type parameters must be declared prior to associated type bindings
--> $DIR/suggest-move-types.rs:16:26
--> $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
Expand All @@ -8,8 +8,20 @@ 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:21:46
--> $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
Expand All @@ -21,8 +33,24 @@ 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:28:49
--> $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
Expand All @@ -33,8 +61,23 @@ 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:35:43
--> $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
Expand All @@ -45,5 +88,20 @@ 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: aborting due to 4 previous errors
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

0 comments on commit 7a0abbf

Please sign in to comment.