]> git.lizzy.rs Git - rust.git/commitdiff
Suggest correct order for arguments when encountering early constraints
authorEsteban Küber <esteban@kuber.com.ar>
Sun, 29 Mar 2020 18:31:58 +0000 (11:31 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Sun, 29 Mar 2020 18:31:58 +0000 (11:31 -0700)
When encountering constraints before type arguments or lifetimes,
suggest the correct order.

src/librustc_ast/ast.rs
src/librustc_ast_passes/ast_validation.rs
src/librustc_ast_pretty/pprust.rs
src/librustc_errors/diagnostic_builder.rs
src/test/ui/parser/issue-32214.stderr
src/test/ui/suggestions/suggest-move-types.stderr

index 6586280d21454aa63aa5e2a8fcbfdc46cf5235d5..f91cbe51d85d184094fdac9e63d0b363b45181c7 100644 (file)
@@ -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,
         }
     }
 }
index 4c7edfc83fa333b319a09910dadbfc191d0d0c9a..4f076c963c1b60b7a626a186677c1f7aaba7ca24 100644 (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.
     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();
index 4aabbe7efbef456866710ed954d93109d96d219d..5ac96c5c8cb55607da341a1160d80a6db979238c 100644 (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.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),
index fffae0bfd24d967f84a141a6ef540e246619b200..2dbd9f4e52fad36f5633d7faf18fc224771b51d6 100644 (file)
@@ -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,
index 959a1ab121b2902ba2a0a81685ddaef64ff6b001..8daf76993bc066f36ca0ce2ef2e0342feec3c081 100644 (file)
@@ -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
 
index 3d2b35fcf454d30e1e2781ab39fbcf77d7f090c6..e8cf54e276771244f63a66d322cae6edf4b2ae0d 100644 (file)
@@ -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