Suggest correct order for arguments when encountering early constraints

When encountering constraints before type arguments or lifetimes,
suggest the correct order.
This commit is contained in:
Esteban Küber 2020-03-29 11:31:58 -07:00
parent dcb4e817bc
commit c2e0e71a09
6 changed files with 74 additions and 46 deletions

View File

@ -300,8 +300,8 @@ pub enum GenericBound {
impl GenericBound { impl GenericBound {
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
match self { match self {
&GenericBound::Trait(ref t, ..) => t.span, GenericBound::Trait(ref t, ..) => t.span,
&GenericBound::Outlives(ref l) => l.ident.span, GenericBound::Outlives(ref l) => l.ident.span,
} }
} }
} }

View File

@ -640,6 +640,32 @@ fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
} }
} }
fn suggest_correct_generic_order(&self, data: &AngleBracketedArgs) -> String {
// Lifetimes always come first.
let lt_sugg = data.args.iter().filter_map(|arg| match arg {
AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
Some(pprust::to_string(|s| s.print_generic_arg(lt)))
}
_ => None,
});
let args_sugg = data.args.iter().filter_map(|a| match a {
AngleBracketedArg::Arg(GenericArg::Lifetime(_)) => None,
AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
AngleBracketedArg::Constraint(_) => None,
});
// Cosntraints always come last.
let constraint_sugg = data.args.iter().filter_map(|a| match a {
AngleBracketedArg::Arg(_) => None,
AngleBracketedArg::Constraint(c) => {
Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
}
});
format!(
"<{}>",
lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
)
}
/// Enforce generic args coming before constraints in `<...>` of a path segment. /// Enforce generic args coming before constraints in `<...>` of a path segment.
fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) { fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
// Early exit in case it's partitioned as it should be. // Early exit in case it's partitioned as it should be.
@ -663,20 +689,7 @@ fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
_ => None, _ => None,
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let snippet_span = match &constraint_spans[..] { let args_len = arg_spans.len();
[single] => *single,
[first, .., last] => first.to(*last),
[] => unreachable!(),
};
let removal_span = match &arg_spans[..] {
[first, ..] => snippet_span.until(*first),
[] => unreachable!(),
};
let sugg_span = match &arg_spans[..] {
[.., last] => last.shrink_to_hi(),
[] => unreachable!(),
};
let snippet = self.session.source_map().span_to_snippet(snippet_span).unwrap();
let constraint_len = constraint_spans.len(); let constraint_len = constraint_spans.len();
// ...and then error: // ...and then error:
self.err_handler() self.err_handler()
@ -693,13 +706,14 @@ fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
), ),
) )
.span_labels(arg_spans, "generic argument") .span_labels(arg_spans, "generic argument")
.multipart_suggestion( .span_suggestion_verbose(
"move the constraints after the generic arguments", data.span,
vec![ &format!(
(removal_span, String::new()), "move the constraint{} after the generic argument{}",
(sugg_span.shrink_to_lo(), ", ".to_string()), pluralize!(constraint_len),
(sugg_span, snippet), pluralize!(args_len)
], ),
self.suggest_correct_generic_order(&data),
Applicability::MachineApplicable, Applicability::MachineApplicable,
) )
.emit(); .emit();

View File

@ -870,7 +870,7 @@ pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
} }
} }
fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) { pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
self.print_ident(constraint.ident); self.print_ident(constraint.ident);
self.s.space(); self.s.space();
match &constraint.kind { match &constraint.kind {
@ -884,7 +884,7 @@ fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
} }
} }
crate fn print_generic_arg(&mut self, generic_arg: &GenericArg) { pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
match generic_arg { match generic_arg {
GenericArg::Lifetime(lt) => self.print_lifetime(*lt), GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
GenericArg::Type(ty) => self.print_type(ty), GenericArg::Type(ty) => self.print_type(ty),

View File

@ -315,6 +315,20 @@ pub fn span_suggestion_short(
self self
} }
pub fn span_suggestion_verbose(
&mut self,
sp: Span,
msg: &str,
suggestion: String,
applicability: Applicability,
) -> &mut Self {
if !self.0.allow_suggestions {
return self;
}
self.0.diagnostic.span_suggestion_verbose(sp, msg, suggestion, applicability);
self
}
pub fn span_suggestion_hidden( pub fn span_suggestion_hidden(
&mut self, &mut self,
sp: Span, sp: Span,

View File

@ -6,10 +6,10 @@ LL | pub fn test<W, I: Trait<Item=(), W> >() {}
| | | |
| the constraint is provided here | the constraint is provided here
| |
help: move the constraints after the generic arguments help: move the constraint after the generic argument
| |
LL | pub fn test<W, I: Trait<W, Item=()> >() {} LL | pub fn test<W, I: Trait<W, Item = ()> >() {}
| --^^^^^^^ | ^^^^^^^^^^^^^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -6,10 +6,10 @@ LL | struct A<T, M: One<A=(), T>> {
| | | |
| the constraint is provided here | the constraint is provided here
| |
help: move the constraints after the generic arguments help: move the constraint after the generic argument
| |
LL | struct A<T, M: One<T, A=()>> { LL | struct A<T, M: One<T, A = ()>> {
| --^^^^ | ^^^^^^^^^^^
error: generic arguments must come before the first constraint error: generic arguments must come before the first constraint
--> $DIR/suggest-move-types.rs:33:43 --> $DIR/suggest-move-types.rs:33:43
@ -20,10 +20,10 @@ LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
| | generic argument | | generic argument
| the constraint is provided here | the constraint is provided here
| |
help: move the constraints after the generic arguments help: move the constraint after the generic arguments
| |
LL | struct Al<'a, T, M: OneWithLifetime<T, 'a, A=()>> { LL | struct Al<'a, T, M: OneWithLifetime<'a, T, A = ()>> {
| -- ^^^^ | ^^^^^^^^^^^^^^^
error: generic arguments must come before the first constraint error: generic arguments must come before the first constraint
--> $DIR/suggest-move-types.rs:40:46 --> $DIR/suggest-move-types.rs:40:46
@ -39,8 +39,8 @@ LL | struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> {
| |
help: move the constraints after the generic arguments help: move the constraints after the generic arguments
| |
LL | struct B<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> { LL | struct B<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
| -- ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: generic arguments must come before the first constraint error: generic arguments must come before the first constraint
--> $DIR/suggest-move-types.rs:48:71 --> $DIR/suggest-move-types.rs:48:71
@ -59,8 +59,8 @@ LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U,
| |
help: move the constraints after the generic arguments help: move the constraints after the generic arguments
| |
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, U, V, 'a, 'b, 'c, A=(), B=(), C=()>> { LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
| -- ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: generic arguments must come before the first constraint error: generic arguments must come before the first constraint
--> $DIR/suggest-move-types.rs:57:28 --> $DIR/suggest-move-types.rs:57:28
@ -76,8 +76,8 @@ LL | struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> {
| |
help: move the constraints after the generic arguments help: move the constraints after the generic arguments
| |
LL | struct C<T, U, V, M: Three<A=(), B=(), C=(), U, V, A=(), B=(), C=()>> { LL | struct C<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
| -- ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: generic arguments must come before the first constraint error: generic arguments must come before the first constraint
--> $DIR/suggest-move-types.rs:65:53 --> $DIR/suggest-move-types.rs:65:53
@ -96,8 +96,8 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=()
| |
help: move the constraints after the generic arguments help: move the constraints after the generic arguments
| |
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), U, 'b, V, 'c, A=(), B=(), C=()>> { LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
| -- ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: generic arguments must come before the first constraint error: generic arguments must come before the first constraint
--> $DIR/suggest-move-types.rs:74:28 --> $DIR/suggest-move-types.rs:74:28
@ -113,8 +113,8 @@ LL | struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> {
| |
help: move the constraints after the generic arguments help: move the constraints after the generic arguments
| |
LL | struct D<T, U, V, M: Three<A=(), B=(), U, C=(), V, A=(), B=(), U, C=()>> { LL | struct D<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
| -- ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: generic arguments must come before the first constraint error: generic arguments must come before the first constraint
--> $DIR/suggest-move-types.rs:82:53 --> $DIR/suggest-move-types.rs:82:53
@ -133,8 +133,8 @@ LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, '
| |
help: move the constraints after the generic arguments help: move the constraints after the generic arguments
| |
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), U, 'b, C=(), V, 'c, A=(), B=(), U, 'b, C=()>> { LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
| -- ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0747]: type provided when a lifetime was expected error[E0747]: type provided when a lifetime was expected
--> $DIR/suggest-move-types.rs:33:43 --> $DIR/suggest-move-types.rs:33:43