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:
parent
dcb4e817bc
commit
c2e0e71a09
@ -300,8 +300,8 @@ pub enum GenericBound {
|
||||
impl GenericBound {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
&GenericBound::Trait(ref t, ..) => t.span,
|
||||
&GenericBound::Outlives(ref l) => l.ident.span,
|
||||
GenericBound::Trait(ref t, ..) => t.span,
|
||||
GenericBound::Outlives(ref l) => l.ident.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
|
||||
// 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,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let snippet_span = match &constraint_spans[..] {
|
||||
[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 args_len = arg_spans.len();
|
||||
let constraint_len = constraint_spans.len();
|
||||
// ...and then error:
|
||||
self.err_handler()
|
||||
@ -693,13 +706,14 @@ fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
|
||||
),
|
||||
)
|
||||
.span_labels(arg_spans, "generic argument")
|
||||
.multipart_suggestion(
|
||||
"move the constraints after the generic arguments",
|
||||
vec![
|
||||
(removal_span, String::new()),
|
||||
(sugg_span.shrink_to_lo(), ", ".to_string()),
|
||||
(sugg_span, snippet),
|
||||
],
|
||||
.span_suggestion_verbose(
|
||||
data.span,
|
||||
&format!(
|
||||
"move the constraint{} after the generic argument{}",
|
||||
pluralize!(constraint_len),
|
||||
pluralize!(args_len)
|
||||
),
|
||||
self.suggest_correct_generic_order(&data),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
@ -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.s.space();
|
||||
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 {
|
||||
GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
|
||||
GenericArg::Type(ty) => self.print_type(ty),
|
||||
|
@ -315,6 +315,20 @@ pub fn span_suggestion_short(
|
||||
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(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
|
@ -6,10 +6,10 @@ LL | pub fn test<W, I: Trait<Item=(), W> >() {}
|
||||
| |
|
||||
| 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
|
||||
|
||||
|
@ -6,10 +6,10 @@ LL | struct A<T, M: One<A=(), T>> {
|
||||
| |
|
||||
| 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
|
||||
--> $DIR/suggest-move-types.rs:33:43
|
||||
@ -20,10 +20,10 @@ LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
|
||||
| | generic argument
|
||||
| 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
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
--> $DIR/suggest-move-types.rs:33:43
|
||||
|
Loading…
Reference in New Issue
Block a user