about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2019-01-25 00:36:28 +0100
committerDavid Wood <david@davidtw.co>2019-01-25 11:54:21 +0100
commit7a0abbff8be746e46841ac7eef5a17364d6b8b51 (patch)
treef101163d5a0add1b28cea162488b4fbcfdd3fda5 /src/libsyntax/parse/parser.rs
parent463e623ca967c2bd301cc0291fae219130b53daf (diff)
downloadrust-7a0abbff8be746e46841ac7eef5a17364d6b8b51.tar.gz
rust-7a0abbff8be746e46841ac7eef5a17364d6b8b51.zip
Combining move lifetime and type suggestions.
This commit combines the move lifetime and move type suggestions so that
when rustfix applies them they don't conflict with each other.
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
-rw-r--r--src/libsyntax/parse/parser.rs103
1 files changed, 73 insertions, 30 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 232b8bb5966..955dce47721 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -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`.