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.rs67
1 files changed, 52 insertions, 15 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c7e33a16564..232b8bb5966 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5530,22 +5530,31 @@ impl<'a> Parser<'a> {
     fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
         let mut args = Vec::new();
         let mut bindings = Vec::new();
+
         let mut seen_type = false;
         let mut seen_binding = false;
+
+        let mut last_comma_span = None;
         let mut first_type_or_binding_span: Option<Span> = None;
+        let mut first_binding_span: Option<Span> = None;
+
         let mut bad_lifetime_pos = vec![];
-        let mut last_comma_span = None;
-        let mut suggestions = vec![];
+        let mut bad_type_pos = vec![];
+
+        let mut lifetime_suggestions = vec![];
+        let mut type_suggestions = vec![];
         loop {
             if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
                 // Parse lifetime argument.
                 args.push(GenericArg::Lifetime(self.expect_lifetime()));
+
                 if seen_type || seen_binding {
                     let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
                     bad_lifetime_pos.push(self.prev_span);
+
                     if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
-                        suggestions.push((remove_sp, String::new()));
-                        suggestions.push((
+                        lifetime_suggestions.push((remove_sp, String::new()));
+                        lifetime_suggestions.push((
                             first_type_or_binding_span.unwrap().shrink_to_lo(),
                             format!("{}, ", snippet)));
                     }
@@ -5563,24 +5572,29 @@ impl<'a> Parser<'a> {
                     ty,
                     span,
                 });
+
                 seen_binding = true;
                 if first_type_or_binding_span.is_none() {
                     first_type_or_binding_span = Some(span);
                 }
+                if first_binding_span.is_none() {
+                    first_binding_span = Some(span);
+                }
             } else if self.check_type() {
                 // Parse type argument.
                 let ty_param = self.parse_ty()?;
                 if seen_binding {
-                    self.struct_span_err(
-                        ty_param.span,
-                        "type parameters must be declared prior to associated type bindings"
-                    )
-                        .span_label(
-                            ty_param.span,
-                            "must be declared prior to associated type bindings",
-                        )
-                        .emit();
+                    let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
+                    bad_type_pos.push(self.prev_span);
+
+                    if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
+                        type_suggestions.push((remove_sp, String::new()));
+                        type_suggestions.push((
+                            first_binding_span.unwrap().shrink_to_lo(),
+                            format!("{}, ", snippet)));
+                    }
                 }
+
                 if first_type_or_binding_span.is_none() {
                     first_type_or_binding_span = Some(ty_param.span);
                 }
@@ -5596,6 +5610,7 @@ impl<'a> Parser<'a> {
                 last_comma_span = Some(self.prev_span);
             }
         }
+
         if !bad_lifetime_pos.is_empty() {
             let mut err = self.struct_span_err(
                 bad_lifetime_pos.clone(),
@@ -5604,18 +5619,40 @@ impl<'a> Parser<'a> {
             for sp in &bad_lifetime_pos {
                 err.span_label(*sp, "must be declared prior to type parameters");
             }
-            if !suggestions.is_empty() {
+            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 { "" },
                     ),
-                    suggestions,
+                    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))
     }