about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
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`.