Skip to content

Commit c2e0e71

Browse files
committed
Suggest correct order for arguments when encountering early constraints
When encountering constraints before type arguments or lifetimes, suggest the correct order.
1 parent dcb4e81 commit c2e0e71

File tree

6 files changed

+74
-46
lines changed

6 files changed

+74
-46
lines changed

src/librustc_ast/ast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ pub enum GenericBound {
300300
impl GenericBound {
301301
pub fn span(&self) -> Span {
302302
match self {
303-
&GenericBound::Trait(ref t, ..) => t.span,
304-
&GenericBound::Outlives(ref l) => l.ident.span,
303+
GenericBound::Trait(ref t, ..) => t.span,
304+
GenericBound::Outlives(ref l) => l.ident.span,
305305
}
306306
}
307307
}

src/librustc_ast_passes/ast_validation.rs

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,32 @@ impl<'a> AstValidator<'a> {
640640
}
641641
}
642642

643+
fn suggest_correct_generic_order(&self, data: &AngleBracketedArgs) -> String {
644+
// Lifetimes always come first.
645+
let lt_sugg = data.args.iter().filter_map(|arg| match arg {
646+
AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
647+
Some(pprust::to_string(|s| s.print_generic_arg(lt)))
648+
}
649+
_ => None,
650+
});
651+
let args_sugg = data.args.iter().filter_map(|a| match a {
652+
AngleBracketedArg::Arg(GenericArg::Lifetime(_)) => None,
653+
AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
654+
AngleBracketedArg::Constraint(_) => None,
655+
});
656+
// Cosntraints always come last.
657+
let constraint_sugg = data.args.iter().filter_map(|a| match a {
658+
AngleBracketedArg::Arg(_) => None,
659+
AngleBracketedArg::Constraint(c) => {
660+
Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
661+
}
662+
});
663+
format!(
664+
"<{}>",
665+
lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
666+
)
667+
}
668+
643669
/// Enforce generic args coming before constraints in `<...>` of a path segment.
644670
fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
645671
// Early exit in case it's partitioned as it should be.
@@ -663,20 +689,7 @@ impl<'a> AstValidator<'a> {
663689
_ => None,
664690
})
665691
.collect::<Vec<_>>();
666-
let snippet_span = match &constraint_spans[..] {
667-
[single] => *single,
668-
[first, .., last] => first.to(*last),
669-
[] => unreachable!(),
670-
};
671-
let removal_span = match &arg_spans[..] {
672-
[first, ..] => snippet_span.until(*first),
673-
[] => unreachable!(),
674-
};
675-
let sugg_span = match &arg_spans[..] {
676-
[.., last] => last.shrink_to_hi(),
677-
[] => unreachable!(),
678-
};
679-
let snippet = self.session.source_map().span_to_snippet(snippet_span).unwrap();
692+
let args_len = arg_spans.len();
680693
let constraint_len = constraint_spans.len();
681694
// ...and then error:
682695
self.err_handler()
@@ -693,13 +706,14 @@ impl<'a> AstValidator<'a> {
693706
),
694707
)
695708
.span_labels(arg_spans, "generic argument")
696-
.multipart_suggestion(
697-
"move the constraints after the generic arguments",
698-
vec![
699-
(removal_span, String::new()),
700-
(sugg_span.shrink_to_lo(), ", ".to_string()),
701-
(sugg_span, snippet),
702-
],
709+
.span_suggestion_verbose(
710+
data.span,
711+
&format!(
712+
"move the constraint{} after the generic argument{}",
713+
pluralize!(constraint_len),
714+
pluralize!(args_len)
715+
),
716+
self.suggest_correct_generic_order(&data),
703717
Applicability::MachineApplicable,
704718
)
705719
.emit();

src/librustc_ast_pretty/pprust.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ impl<'a> State<'a> {
870870
}
871871
}
872872

873-
fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
873+
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
874874
self.print_ident(constraint.ident);
875875
self.s.space();
876876
match &constraint.kind {
@@ -884,7 +884,7 @@ impl<'a> State<'a> {
884884
}
885885
}
886886

887-
crate fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
887+
pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
888888
match generic_arg {
889889
GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
890890
GenericArg::Type(ty) => self.print_type(ty),

src/librustc_errors/diagnostic_builder.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,20 @@ impl<'a> DiagnosticBuilder<'a> {
315315
self
316316
}
317317

318+
pub fn span_suggestion_verbose(
319+
&mut self,
320+
sp: Span,
321+
msg: &str,
322+
suggestion: String,
323+
applicability: Applicability,
324+
) -> &mut Self {
325+
if !self.0.allow_suggestions {
326+
return self;
327+
}
328+
self.0.diagnostic.span_suggestion_verbose(sp, msg, suggestion, applicability);
329+
self
330+
}
331+
318332
pub fn span_suggestion_hidden(
319333
&mut self,
320334
sp: Span,

src/test/ui/parser/issue-32214.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ LL | pub fn test<W, I: Trait<Item=(), W> >() {}
66
| |
77
| the constraint is provided here
88
|
9-
help: move the constraints after the generic arguments
9+
help: move the constraint after the generic argument
1010
|
11-
LL | pub fn test<W, I: Trait<W, Item=()> >() {}
12-
| --^^^^^^^
11+
LL | pub fn test<W, I: Trait<W, Item = ()> >() {}
12+
| ^^^^^^^^^^^^^^
1313

1414
error: aborting due to previous error
1515

src/test/ui/suggestions/suggest-move-types.stderr

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ LL | struct A<T, M: One<A=(), T>> {
66
| |
77
| the constraint is provided here
88
|
9-
help: move the constraints after the generic arguments
9+
help: move the constraint after the generic argument
1010
|
11-
LL | struct A<T, M: One<T, A=()>> {
12-
| --^^^^
11+
LL | struct A<T, M: One<T, A = ()>> {
12+
| ^^^^^^^^^^^
1313

1414
error: generic arguments must come before the first constraint
1515
--> $DIR/suggest-move-types.rs:33:43
@@ -20,10 +20,10 @@ LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
2020
| | generic argument
2121
| the constraint is provided here
2222
|
23-
help: move the constraints after the generic arguments
23+
help: move the constraint after the generic arguments
2424
|
25-
LL | struct Al<'a, T, M: OneWithLifetime<T, 'a, A=()>> {
26-
| -- ^^^^
25+
LL | struct Al<'a, T, M: OneWithLifetime<'a, T, A = ()>> {
26+
| ^^^^^^^^^^^^^^^
2727

2828
error: generic arguments must come before the first constraint
2929
--> $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>> {
3939
|
4040
help: move the constraints after the generic arguments
4141
|
42-
LL | struct B<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> {
43-
| -- ^^^^^^^^^^^^^^^^
42+
LL | struct B<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
43+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4444

4545
error: generic arguments must come before the first constraint
4646
--> $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,
5959
|
6060
help: move the constraints after the generic arguments
6161
|
62-
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, U, V, 'a, 'b, 'c, A=(), B=(), C=()>> {
63-
| -- ^^^^^^^^^^^^^^^^
62+
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
63+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6464

6565
error: generic arguments must come before the first constraint
6666
--> $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>> {
7676
|
7777
help: move the constraints after the generic arguments
7878
|
79-
LL | struct C<T, U, V, M: Three<A=(), B=(), C=(), U, V, A=(), B=(), C=()>> {
80-
| -- ^^^^^^^^^^^^^^^^
79+
LL | struct C<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
80+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8181

8282
error: generic arguments must come before the first constraint
8383
--> $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=()
9696
|
9797
help: move the constraints after the generic arguments
9898
|
99-
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), U, 'b, V, 'c, A=(), B=(), C=()>> {
100-
| -- ^^^^^^^^^^^^^^^^
99+
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
100+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
101101

102102
error: generic arguments must come before the first constraint
103103
--> $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>> {
113113
|
114114
help: move the constraints after the generic arguments
115115
|
116-
LL | struct D<T, U, V, M: Three<A=(), B=(), U, C=(), V, A=(), B=(), U, C=()>> {
117-
| -- ^^^^^^^^^^^^^^^^^^^
116+
LL | struct D<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
117+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
118118

119119
error: generic arguments must come before the first constraint
120120
--> $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, '
133133
|
134134
help: move the constraints after the generic arguments
135135
|
136-
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), U, 'b, C=(), V, 'c, A=(), B=(), U, 'b, C=()>> {
137-
| -- ^^^^^^^^^^^^^^^^^^^^^^^
136+
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
137+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
138138

139139
error[E0747]: type provided when a lifetime was expected
140140
--> $DIR/suggest-move-types.rs:33:43

0 commit comments

Comments
 (0)