about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_ast/ast.rs29
-rw-r--r--src/librustc_ast/mut_visit.rs8
-rw-r--r--src/librustc_ast/visit.rs8
-rw-r--r--src/librustc_ast_lowering/lib.rs1
-rw-r--r--src/librustc_ast_lowering/path.rs35
-rw-r--r--src/librustc_ast_passes/ast_validation.rs53
-rw-r--r--src/librustc_ast_passes/lib.rs4
-rw-r--r--src/librustc_ast_pretty/pprust.rs41
-rw-r--r--src/librustc_expand/build.rs3
-rw-r--r--src/librustc_interface/util.rs16
-rw-r--r--src/librustc_parse/parser/path.rs228
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs4
-rw-r--r--src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs9
-rw-r--r--src/test/ui/parser/issue-32214.rs2
-rw-r--r--src/test/ui/parser/issue-32214.stderr8
-rw-r--r--src/test/ui/parser/recover-assoc-const-constraint.rs7
-rw-r--r--src/test/ui/parser/recover-assoc-const-constraint.stderr20
-rw-r--r--src/test/ui/parser/recover-assoc-eq-missing-term.rs6
-rw-r--r--src/test/ui/parser/recover-assoc-eq-missing-term.stderr17
-rw-r--r--src/test/ui/parser/recover-assoc-lifetime-constraint.rs6
-rw-r--r--src/test/ui/parser/recover-assoc-lifetime-constraint.stderr12
-rw-r--r--src/test/ui/suggestions/suggest-move-types.rs22
-rw-r--r--src/test/ui/suggestions/suggest-move-types.stderr112
23 files changed, 404 insertions, 247 deletions
diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs
index 646294a7cca..6586280d214 100644
--- a/src/librustc_ast/ast.rs
+++ b/src/librustc_ast/ast.rs
@@ -214,11 +214,18 @@ impl GenericArg {
 pub struct AngleBracketedArgs {
     /// The overall span.
     pub span: Span,
-    /// The arguments for this path segment.
-    pub args: Vec<GenericArg>,
-    /// Constraints on associated types, if any.
-    /// E.g., `Foo<A = Bar, B: Baz>`.
-    pub constraints: Vec<AssocTyConstraint>,
+    /// The comma separated parts in the `<...>`.
+    pub args: Vec<AngleBracketedArg>,
+}
+
+/// Either an argument for a parameter e.g., `'a`, `Vec<u8>`, `0`,
+/// or a constraint on an associated item, e.g., `Item = String` or `Item: Bound`.
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub enum AngleBracketedArg {
+    /// Argument for a generic parameter.
+    Arg(GenericArg),
+    /// Constraint for an associated item.
+    Constraint(AssocTyConstraint),
 }
 
 impl Into<Option<P<GenericArgs>>> for AngleBracketedArgs {
@@ -248,11 +255,13 @@ pub struct ParenthesizedArgs {
 
 impl ParenthesizedArgs {
     pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs {
-        AngleBracketedArgs {
-            span: self.span,
-            args: self.inputs.iter().cloned().map(GenericArg::Type).collect(),
-            constraints: vec![],
-        }
+        let args = self
+            .inputs
+            .iter()
+            .cloned()
+            .map(|input| AngleBracketedArg::Arg(GenericArg::Type(input)))
+            .collect();
+        AngleBracketedArgs { span: self.span, args }
     }
 }
 
diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs
index 67f7764d5bb..a72a60c30b2 100644
--- a/src/librustc_ast/mut_visit.rs
+++ b/src/librustc_ast/mut_visit.rs
@@ -546,9 +546,11 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
     data: &mut AngleBracketedArgs,
     vis: &mut T,
 ) {
-    let AngleBracketedArgs { args, constraints, span } = data;
-    visit_vec(args, |arg| vis.visit_generic_arg(arg));
-    visit_vec(constraints, |constraint| vis.visit_ty_constraint(constraint));
+    let AngleBracketedArgs { args, span } = data;
+    visit_vec(args, |arg| match arg {
+        AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
+        AngleBracketedArg::Constraint(constraint) => vis.visit_ty_constraint(constraint),
+    });
     vis.visit_span(span);
 }
 
diff --git a/src/librustc_ast/visit.rs b/src/librustc_ast/visit.rs
index cc2b1c48b51..51863350a8c 100644
--- a/src/librustc_ast/visit.rs
+++ b/src/librustc_ast/visit.rs
@@ -464,8 +464,12 @@ where
 {
     match *generic_args {
         GenericArgs::AngleBracketed(ref data) => {
-            walk_list!(visitor, visit_generic_arg, &data.args);
-            walk_list!(visitor, visit_assoc_ty_constraint, &data.constraints);
+            for arg in &data.args {
+                match arg {
+                    AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a),
+                    AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c),
+                }
+            }
         }
         GenericArgs::Parenthesized(ref data) => {
             walk_list!(visitor, visit_ty, &data.inputs);
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index 68cb1f8585f..45ee7265c15 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -34,6 +34,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(marker_trait_attr)]
 #![feature(specialization)]
+#![feature(or_patterns)]
 #![recursion_limit = "256"]
 
 use rustc_ast::ast;
diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs
index e996bdac7cb..dde73475651 100644
--- a/src/librustc_ast_lowering/path.rs
+++ b/src/librustc_ast_lowering/path.rs
@@ -366,22 +366,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         param_mode: ParamMode,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> (GenericArgsCtor<'hir>, bool) {
-        let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
-        let has_non_lt_args = args.iter().any(|arg| match arg {
-            ast::GenericArg::Lifetime(_) => false,
-            ast::GenericArg::Type(_) => true,
-            ast::GenericArg::Const(_) => true,
+        let has_non_lt_args = data.args.iter().any(|arg| match arg {
+            AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
+            | AngleBracketedArg::Constraint(_) => false,
+            AngleBracketedArg::Arg(ast::GenericArg::Type(_) | ast::GenericArg::Const(_)) => true,
         });
-        (
-            GenericArgsCtor {
-                args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
-                bindings: self.arena.alloc_from_iter(
-                    constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())),
-                ),
-                parenthesized: false,
-            },
-            !has_non_lt_args && param_mode == ParamMode::Optional,
-        )
+        let args = data
+            .args
+            .iter()
+            .filter_map(|arg| match arg {
+                AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx.reborrow())),
+                AngleBracketedArg::Constraint(_) => None,
+            })
+            .collect();
+        let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
+            AngleBracketedArg::Constraint(c) => {
+                Some(self.lower_assoc_ty_constraint(c, itctx.reborrow()))
+            }
+            AngleBracketedArg::Arg(_) => None,
+        }));
+        let ctor = GenericArgsCtor { args, bindings, parenthesized: false };
+        (ctor, !has_non_lt_args && param_mode == ParamMode::Optional)
     }
 
     fn lower_parenthesized_parameter_data(
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 885f2f939a6..de7ae10723f 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -639,6 +639,34 @@ impl<'a> AstValidator<'a> {
             .emit();
         }
     }
+
+    /// 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.
+        if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
+            return;
+        }
+        // Find all generic argument coming after the first constraint...
+        let mut misplaced_args = Vec::new();
+        let mut first = None;
+        for arg in &data.args {
+            match (arg, first) {
+                (AngleBracketedArg::Arg(a), Some(_)) => misplaced_args.push(a.span()),
+                (AngleBracketedArg::Constraint(c), None) => first = Some(c.span),
+                (AngleBracketedArg::Arg(_), None) | (AngleBracketedArg::Constraint(_), Some(_)) => {
+                }
+            }
+        }
+        // ...and then error:
+        self.err_handler()
+            .struct_span_err(
+                misplaced_args.clone(),
+                "generic arguments must come before the first constraint",
+            )
+            .span_label(first.unwrap(), "the first constraint is provided here")
+            .span_labels(misplaced_args, "generic argument")
+            .emit();
+    }
 }
 
 /// Checks that generic parameters are in the correct order,
@@ -1008,17 +1036,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
         match *generic_args {
             GenericArgs::AngleBracketed(ref data) => {
-                walk_list!(self, visit_generic_arg, &data.args);
-
-                // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
-                // are allowed to contain nested `impl Trait`.
-                self.with_impl_trait(None, |this| {
-                    walk_list!(
-                        this,
-                        visit_assoc_ty_constraint_from_generic_args,
-                        &data.constraints
-                    );
-                });
+                self.check_generic_args_before_constraints(data);
+
+                for arg in &data.args {
+                    match arg {
+                        AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
+                        // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
+                        // are allowed to contain nested `impl Trait`.
+                        AngleBracketedArg::Constraint(constraint) => {
+                            self.with_impl_trait(None, |this| {
+                                this.visit_assoc_ty_constraint_from_generic_args(constraint);
+                            });
+                        }
+                    }
+                }
             }
             GenericArgs::Parenthesized(ref data) => {
                 walk_list!(self, visit_ty, &data.inputs);
diff --git a/src/librustc_ast_passes/lib.rs b/src/librustc_ast_passes/lib.rs
index 10081d36754..bfe30441980 100644
--- a/src/librustc_ast_passes/lib.rs
+++ b/src/librustc_ast_passes/lib.rs
@@ -1,10 +1,12 @@
-#![feature(bindings_after_at)]
 //! The `rustc_ast_passes` crate contains passes which validate the AST in `syntax`
 //! parsed by `rustc_parse` and then lowered, after the passes in this crate,
 //! by `rustc_ast_lowering`.
 //!
 //! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
 
+#![feature(bindings_after_at)]
+#![feature(iter_is_partitioned)]
+
 pub mod ast_validation;
 pub mod feature_gate;
 pub mod node_count;
diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index 2d6932ffbee..4aabbe7efbe 100644
--- a/src/librustc_ast_pretty/pprust.rs
+++ b/src/librustc_ast_pretty/pprust.rs
@@ -796,31 +796,10 @@ impl<'a> PrintState<'a> for State<'a> {
         match *args {
             ast::GenericArgs::AngleBracketed(ref data) => {
                 self.s.word("<");
-
-                self.commasep(Inconsistent, &data.args, |s, generic_arg| {
-                    s.print_generic_arg(generic_arg)
+                self.commasep(Inconsistent, &data.args, |s, arg| match arg {
+                    ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
+                    ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c),
                 });
-
-                let mut comma = !data.args.is_empty();
-
-                for constraint in data.constraints.iter() {
-                    if comma {
-                        self.word_space(",")
-                    }
-                    self.print_ident(constraint.ident);
-                    self.s.space();
-                    match constraint.kind {
-                        ast::AssocTyConstraintKind::Equality { ref ty } => {
-                            self.word_space("=");
-                            self.print_type(ty);
-                        }
-                        ast::AssocTyConstraintKind::Bound { ref bounds } => {
-                            self.print_type_bounds(":", &*bounds);
-                        }
-                    }
-                    comma = true;
-                }
-
                 self.s.word(">")
             }
 
@@ -891,6 +870,20 @@ impl<'a> State<'a> {
         }
     }
 
+    fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
+        self.print_ident(constraint.ident);
+        self.s.space();
+        match &constraint.kind {
+            ast::AssocTyConstraintKind::Equality { ty } => {
+                self.word_space("=");
+                self.print_type(ty);
+            }
+            ast::AssocTyConstraintKind::Bound { bounds } => {
+                self.print_type_bounds(":", &*bounds);
+            }
+        }
+    }
+
     crate fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
         match generic_arg {
             GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs
index 48ceaf5fccd..4d89bf79e7c 100644
--- a/src/librustc_expand/build.rs
+++ b/src/librustc_expand/build.rs
@@ -36,7 +36,8 @@ impl<'a> ExtCtxt<'a> {
             idents.into_iter().map(|ident| ast::PathSegment::from_ident(ident.with_span_pos(span))),
         );
         let args = if !args.is_empty() {
-            ast::AngleBracketedArgs { args, constraints: Vec::new(), span }.into()
+            let args = args.into_iter().map(ast::AngleBracketedArg::Arg).collect();
+            ast::AngleBracketedArgs { args, span }.into()
         } else {
             None
         };
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index c6f2d1b82fc..eff7dacef79 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -634,17 +634,19 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
                         match seg.args.as_ref().map(|generic_arg| &**generic_arg) {
                             None => false,
                             Some(&ast::GenericArgs::AngleBracketed(ref data)) => {
-                                let types = data.args.iter().filter_map(|arg| match arg {
-                                    ast::GenericArg::Type(ty) => Some(ty),
-                                    _ => None,
-                                });
-                                any_involves_impl_trait(types)
-                                    || data.constraints.iter().any(|c| match c.kind {
+                                data.args.iter().any(|arg| match arg {
+                                    ast::AngleBracketedArg::Arg(arg) => match arg {
+                                        ast::GenericArg::Type(ty) => involves_impl_trait(ty),
+                                        ast::GenericArg::Lifetime(_)
+                                        | ast::GenericArg::Const(_) => false,
+                                    },
+                                    ast::AngleBracketedArg::Constraint(c) => match c.kind {
                                         ast::AssocTyConstraintKind::Bound { .. } => true,
                                         ast::AssocTyConstraintKind::Equality { ref ty } => {
                                             involves_impl_trait(ty)
                                         }
-                                    })
+                                    },
+                                })
                             }
                             Some(&ast::GenericArgs::Parenthesized(ref data)) => {
                                 any_involves_impl_trait(data.inputs.iter())
diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs
index f88b4fe6ff0..9fa7bc027b8 100644
--- a/src/librustc_parse/parser/path.rs
+++ b/src/librustc_parse/parser/path.rs
@@ -1,12 +1,10 @@
 use super::ty::{AllowPlus, RecoverQPath};
 use super::{Parser, TokenType};
 use crate::maybe_whole;
-use rustc_ast::ast::{
-    self, AngleBracketedArgs, Ident, ParenthesizedArgs, Path, PathSegment, QSelf,
-};
-use rustc_ast::ast::{
-    AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode, GenericArg,
-};
+use rustc_ast::ast::{self, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs};
+use rustc_ast::ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
+use rustc_ast::ast::{Ident, Path, PathSegment, QSelf};
+use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token};
 use rustc_errors::{pluralize, Applicability, PResult};
 use rustc_span::source_map::{BytePos, Span};
@@ -218,11 +216,11 @@ impl<'a> Parser<'a> {
                 let lo = self.token.span;
                 let args = if self.eat_lt() {
                     // `<'a, T, A = U>`
-                    let (args, constraints) =
-                        self.parse_generic_args_with_leading_angle_bracket_recovery(style, lo)?;
+                    let args =
+                        self.parse_angle_args_with_leading_angle_bracket_recovery(style, lo)?;
                     self.expect_gt()?;
                     let span = lo.to(self.prev_token.span);
-                    AngleBracketedArgs { args, constraints, span }.into()
+                    AngleBracketedArgs { args, span }.into()
                 } else {
                     // `(T, U) -> R`
                     let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
@@ -251,18 +249,18 @@ impl<'a> Parser<'a> {
 
     /// Parses generic args (within a path segment) with recovery for extra leading angle brackets.
     /// For the purposes of understanding the parsing logic of generic arguments, this function
-    /// can be thought of being the same as just calling `self.parse_generic_args()` if the source
+    /// can be thought of being the same as just calling `self.parse_angle_args()` if the source
     /// had the correct amount of leading angle brackets.
     ///
     /// ```ignore (diagnostics)
     /// bar::<<<<T as Foo>::Output>();
     ///      ^^ help: remove extra angle brackets
     /// ```
-    fn parse_generic_args_with_leading_angle_bracket_recovery(
+    fn parse_angle_args_with_leading_angle_bracket_recovery(
         &mut self,
         style: PathStyle,
         lo: Span,
-    ) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
+    ) -> PResult<'a, Vec<AngleBracketedArg>> {
         // We need to detect whether there are extra leading left angle brackets and produce an
         // appropriate error and suggestion. This cannot be implemented by looking ahead at
         // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
@@ -337,8 +335,8 @@ impl<'a> Parser<'a> {
         let snapshot = if is_first_invocation { Some(self.clone()) } else { None };
 
         debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
-        match self.parse_generic_args() {
-            Ok(value) => Ok(value),
+        match self.parse_angle_args() {
+            Ok(args) => Ok(args),
             Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
                 // Cancel error from being unable to find `>`. We know the error
                 // must have been this due to a non-zero unmatched angle bracket
@@ -381,110 +379,136 @@ impl<'a> Parser<'a> {
                 .emit();
 
                 // Try again without unmatched angle bracket characters.
-                self.parse_generic_args()
+                self.parse_angle_args()
             }
             Err(e) => Err(e),
         }
     }
 
-    /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
+    /// Parses (possibly empty) list of generic arguments / associated item constraints,
     /// possibly including trailing comma.
-    fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
+    fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
         let mut args = Vec::new();
-        let mut constraints = Vec::new();
-        let mut misplaced_assoc_ty_constraints: Vec<Span> = Vec::new();
-        let mut assoc_ty_constraints: Vec<Span> = Vec::new();
-
-        let args_lo = self.token.span;
-
-        loop {
-            if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
-                // Parse lifetime argument.
-                args.push(GenericArg::Lifetime(self.expect_lifetime()));
-                misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
-            } else if self.check_ident()
-                && self.look_ahead(1, |t| t == &token::Eq || t == &token::Colon)
-            {
-                // Parse associated type constraint.
-                let lo = self.token.span;
-                let ident = self.parse_ident()?;
-                let kind = if self.eat(&token::Eq) {
-                    AssocTyConstraintKind::Equality { ty: self.parse_ty()? }
-                } else if self.eat(&token::Colon) {
-                    AssocTyConstraintKind::Bound {
-                        bounds: self.parse_generic_bounds(Some(self.prev_token.span))?,
-                    }
-                } else {
-                    unreachable!();
-                };
+        while let Some(arg) = self.parse_angle_arg()? {
+            args.push(arg);
+            if !self.eat(&token::Comma) {
+                break;
+            }
+        }
+        Ok(args)
+    }
 
-                let span = lo.to(self.prev_token.span);
+    /// Parses a single argument in the angle arguments `<...>` of a path segment.
+    fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> {
+        if self.check_ident() && self.look_ahead(1, |t| matches!(t.kind, token::Eq | token::Colon))
+        {
+            // Parse associated type constraint.
+            let lo = self.token.span;
+            let ident = self.parse_ident()?;
+            let kind = if self.eat(&token::Eq) {
+                let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
+                AssocTyConstraintKind::Equality { ty }
+            } else if self.eat(&token::Colon) {
+                let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
+                AssocTyConstraintKind::Bound { bounds }
+            } else {
+                unreachable!();
+            };
 
-                // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
-                if let AssocTyConstraintKind::Bound { .. } = kind {
-                    self.sess.gated_spans.gate(sym::associated_type_bounds, span);
-                }
+            let span = lo.to(self.prev_token.span);
 
-                constraints.push(AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span });
-                assoc_ty_constraints.push(span);
-            } else if self.check_const_arg() {
-                // Parse const argument.
-                let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
-                    self.parse_block_expr(
-                        None,
-                        self.token.span,
-                        BlockCheckMode::Default,
-                        ast::AttrVec::new(),
-                    )?
-                } else if self.token.is_ident() {
-                    // FIXME(const_generics): to distinguish between idents for types and consts,
-                    // we should introduce a GenericArg::Ident in the AST and distinguish when
-                    // lowering to the HIR. For now, idents for const args are not permitted.
-                    if self.token.is_bool_lit() {
-                        self.parse_literal_maybe_minus()?
-                    } else {
-                        let span = self.token.span;
-                        let msg = "identifiers may currently not be used for const generics";
-                        self.struct_span_err(span, msg).emit();
-                        let block = self.mk_block_err(span);
-                        self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new())
-                    }
-                } else {
-                    self.parse_literal_maybe_minus()?
-                };
-                let value = AnonConst { id: ast::DUMMY_NODE_ID, value: expr };
-                args.push(GenericArg::Const(value));
-                misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
-            } else if self.check_type() {
-                // Parse type argument.
-                args.push(GenericArg::Type(self.parse_ty()?));
-                misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
-            } else {
-                break;
+            // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
+            if let AssocTyConstraintKind::Bound { .. } = kind {
+                self.sess.gated_spans.gate(sym::associated_type_bounds, span);
             }
 
-            if !self.eat(&token::Comma) {
-                break;
-            }
+            let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span };
+            Ok(Some(AngleBracketedArg::Constraint(constraint)))
+        } else {
+            Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg))
         }
+    }
 
-        // FIXME: we would like to report this in ast_validation instead, but we currently do not
-        // preserve ordering of generic parameters with respect to associated type binding, so we
-        // lose that information after parsing.
-        if !misplaced_assoc_ty_constraints.is_empty() {
-            let mut err = self.struct_span_err(
-                args_lo.to(self.prev_token.span),
-                "associated type bindings must be declared after generic parameters",
-            );
-            for span in misplaced_assoc_ty_constraints {
-                err.span_label(
-                    span,
-                    "this associated type binding should be moved after the generic parameters",
-                );
+    /// Parse the term to the right of an associated item equality constraint.
+    /// That is, parse `<term>` in `Item = <term>`.
+    /// Right now, this only admits types in `<term>`.
+    fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
+        let arg = self.parse_generic_arg()?;
+        let span = ident.span.to(self.prev_token.span);
+        match arg {
+            Some(GenericArg::Type(ty)) => return Ok(ty),
+            Some(GenericArg::Const(expr)) => {
+                self.struct_span_err(span, "cannot constrain an associated constant to a value")
+                    .span_label(ident.span, "this associated constant...")
+                    .span_label(expr.value.span, "...cannot be constrained to this value")
+                    .emit();
+            }
+            Some(GenericArg::Lifetime(lt)) => {
+                self.struct_span_err(span, "associated lifetimes are not supported")
+                    .span_label(lt.ident.span, "the lifetime is given here")
+                    .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
+                    .emit();
+            }
+            None => {
+                let after_eq = eq.shrink_to_hi();
+                let before_next = self.token.span.shrink_to_lo();
+                self.struct_span_err(after_eq.to(before_next), "missing type to the right of `=`")
+                    .span_suggestion(
+                        self.sess.source_map().next_point(eq).to(before_next),
+                        "to constrain the associated type, add a type after `=`",
+                        " TheType".to_string(),
+                        Applicability::HasPlaceholders,
+                    )
+                    .span_suggestion(
+                        eq.to(before_next),
+                        &format!("remove the `=` if `{}` is a type", ident),
+                        String::new(),
+                        Applicability::MaybeIncorrect,
+                    )
+                    .emit();
             }
-            err.emit();
         }
+        Ok(self.mk_ty(span, ast::TyKind::Err))
+    }
 
-        Ok((args, constraints))
+    /// Parse a generic argument in a path segment.
+    /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
+    fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
+        let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
+            // Parse lifetime argument.
+            GenericArg::Lifetime(self.expect_lifetime())
+        } else if self.check_const_arg() {
+            // Parse const argument.
+            let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
+                self.parse_block_expr(
+                    None,
+                    self.token.span,
+                    BlockCheckMode::Default,
+                    ast::AttrVec::new(),
+                )?
+            } else if self.token.is_ident() {
+                // FIXME(const_generics): to distinguish between idents for types and consts,
+                // we should introduce a GenericArg::Ident in the AST and distinguish when
+                // lowering to the HIR. For now, idents for const args are not permitted.
+                if self.token.is_bool_lit() {
+                    self.parse_literal_maybe_minus()?
+                } else {
+                    let span = self.token.span;
+                    let msg = "identifiers may currently not be used for const generics";
+                    self.struct_span_err(span, msg).emit();
+                    let block = self.mk_block_err(span);
+                    self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new())
+                }
+            } else {
+                self.parse_literal_maybe_minus()?
+            };
+            GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: expr })
+        } else if self.check_type() {
+            // Parse type argument.
+            GenericArg::Type(self.parse_ty()?)
+        } else {
+            return Ok(None);
+        };
+        Ok(Some(arg))
     }
 }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index c0ac9e7f6b6..e5637e4e6e6 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -783,7 +783,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                 match **generic_args {
                     ast::GenericArgs::AngleBracketed(ref data) => {
                         for arg in &data.args {
-                            if let ast::GenericArg::Type(ty) = arg {
+                            if let ast::AngleBracketedArg::Arg(ast::GenericArg::Type(ty)) = arg {
                                 self.visit_ty(ty);
                             }
                         }
@@ -849,7 +849,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
             if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
                 for arg in &data.args {
                     match arg {
-                        ast::GenericArg::Type(ty) => self.visit_ty(ty),
+                        ast::AngleBracketedArg::Arg(ast::GenericArg::Type(ty)) => self.visit_ty(ty),
                         _ => {}
                     }
                 }
diff --git a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs
new file mode 100644
index 00000000000..afbd13e6fd9
--- /dev/null
+++ b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+#[cfg(FALSE)]
+fn syntax() {
+    foo::<T = u8, T: Ord, String>();
+    foo::<T = u8, 'a, T: Ord>();
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-32214.rs b/src/test/ui/parser/issue-32214.rs
index 82f7ce62b94..1379eeb58e6 100644
--- a/src/test/ui/parser/issue-32214.rs
+++ b/src/test/ui/parser/issue-32214.rs
@@ -1,6 +1,6 @@
 trait Trait<T> { type Item; }
 
 pub fn test<W, I: Trait<Item=(), W> >() {}
-//~^ ERROR associated type bindings must be declared after generic parameters
+//~^ ERROR generic arguments must come before the first constraint
 
 fn main() { }
diff --git a/src/test/ui/parser/issue-32214.stderr b/src/test/ui/parser/issue-32214.stderr
index 08b230a14f5..742f4fdc38b 100644
--- a/src/test/ui/parser/issue-32214.stderr
+++ b/src/test/ui/parser/issue-32214.stderr
@@ -1,10 +1,10 @@
-error: associated type bindings must be declared after generic parameters
-  --> $DIR/issue-32214.rs:3:25
+error: generic arguments must come before the first constraint
+  --> $DIR/issue-32214.rs:3:34
    |
 LL | pub fn test<W, I: Trait<Item=(), W> >() {}
-   |                         -------^^^
+   |                         -------  ^ generic argument
    |                         |
-   |                         this associated type binding should be moved after the generic parameters
+   |                         the first constraint is provided here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/recover-assoc-const-constraint.rs b/src/test/ui/parser/recover-assoc-const-constraint.rs
new file mode 100644
index 00000000000..06be3cdcc1a
--- /dev/null
+++ b/src/test/ui/parser/recover-assoc-const-constraint.rs
@@ -0,0 +1,7 @@
+#[cfg(FALSE)]
+fn syntax() {
+    bar::<Item = 42>(); //~ ERROR cannot constrain an associated constant to a value
+    bar::<Item = { 42 }>(); //~ ERROR cannot constrain an associated constant to a value
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/recover-assoc-const-constraint.stderr b/src/test/ui/parser/recover-assoc-const-constraint.stderr
new file mode 100644
index 00000000000..c6733b33faa
--- /dev/null
+++ b/src/test/ui/parser/recover-assoc-const-constraint.stderr
@@ -0,0 +1,20 @@
+error: cannot constrain an associated constant to a value
+  --> $DIR/recover-assoc-const-constraint.rs:3:11
+   |
+LL |     bar::<Item = 42>();
+   |           ----^^^--
+   |           |      |
+   |           |      ...cannot be constrained to this value
+   |           this associated constant...
+
+error: cannot constrain an associated constant to a value
+  --> $DIR/recover-assoc-const-constraint.rs:4:11
+   |
+LL |     bar::<Item = { 42 }>();
+   |           ----^^^------
+   |           |      |
+   |           |      ...cannot be constrained to this value
+   |           this associated constant...
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/recover-assoc-eq-missing-term.rs b/src/test/ui/parser/recover-assoc-eq-missing-term.rs
new file mode 100644
index 00000000000..4b42c44dc64
--- /dev/null
+++ b/src/test/ui/parser/recover-assoc-eq-missing-term.rs
@@ -0,0 +1,6 @@
+#[cfg(FALSE)]
+fn syntax() {
+    bar::<Item =   >(); //~ ERROR missing type to the right of `=`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/recover-assoc-eq-missing-term.stderr b/src/test/ui/parser/recover-assoc-eq-missing-term.stderr
new file mode 100644
index 00000000000..6e41e139220
--- /dev/null
+++ b/src/test/ui/parser/recover-assoc-eq-missing-term.stderr
@@ -0,0 +1,17 @@
+error: missing type to the right of `=`
+  --> $DIR/recover-assoc-eq-missing-term.rs:3:17
+   |
+LL |     bar::<Item =   >();
+   |                 ^^^
+   |
+help: to constrain the associated type, add a type after `=`
+   |
+LL |     bar::<Item = TheType>();
+   |                  ^^^^^^^
+help: remove the `=` if `Item` is a type
+   |
+LL |     bar::<Item >();
+   |               --
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/recover-assoc-lifetime-constraint.rs b/src/test/ui/parser/recover-assoc-lifetime-constraint.rs
new file mode 100644
index 00000000000..558fcdfe177
--- /dev/null
+++ b/src/test/ui/parser/recover-assoc-lifetime-constraint.rs
@@ -0,0 +1,6 @@
+#[cfg(FALSE)]
+fn syntax() {
+    bar::<Item = 'a>(); //~ ERROR associated lifetimes are not supported
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/recover-assoc-lifetime-constraint.stderr b/src/test/ui/parser/recover-assoc-lifetime-constraint.stderr
new file mode 100644
index 00000000000..79437533d7c
--- /dev/null
+++ b/src/test/ui/parser/recover-assoc-lifetime-constraint.stderr
@@ -0,0 +1,12 @@
+error: associated lifetimes are not supported
+  --> $DIR/recover-assoc-lifetime-constraint.rs:3:11
+   |
+LL |     bar::<Item = 'a>();
+   |           ^^^^^^^--
+   |                  |
+   |                  the lifetime is given here
+   |
+   = help: if you meant to specify a trait object, write `dyn Trait + 'lifetime`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/suggestions/suggest-move-types.rs b/src/test/ui/suggestions/suggest-move-types.rs
index 6505a97de6e..27930626a62 100644
--- a/src/test/ui/suggestions/suggest-move-types.rs
+++ b/src/test/ui/suggestions/suggest-move-types.rs
@@ -1,5 +1,3 @@
-// ignore-tidy-linelength
-
 #![allow(warnings)]
 
 // This test verifies that the suggestion to move types before associated type bindings
@@ -25,20 +23,22 @@ trait ThreeWithLifetime<'a, 'b, 'c, T, U, V> {
   type C;
 }
 
-struct A<T, M: One<A=(), T>> { //~ ERROR associated type bindings must be declared after generic parameters
+struct A<T, M: One<A=(), T>> {
+//~^ ERROR generic arguments must come before the first constraint
     m: M,
     t: T,
 }
 
 
 struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
-//~^ ERROR associated type bindings must be declared after generic parameters
+//~^ ERROR generic arguments must come before the first constraint
 //~^^ ERROR type provided when a lifetime was expected
     m: M,
     t: &'a T,
 }
 
-struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> { //~ ERROR associated type bindings must be declared after generic parameters
+struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> {
+//~^ ERROR generic arguments must come before the first constraint
     m: M,
     t: T,
     u: U,
@@ -46,7 +46,7 @@ struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> { //~ ERROR associated ty
 }
 
 struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
-//~^ ERROR associated type bindings must be declared after generic parameters
+//~^ ERROR generic arguments must come before the first constraint
 //~^^ ERROR type provided when a lifetime was expected
     m: M,
     t: &'a T,
@@ -54,7 +54,8 @@ struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, '
     v: &'c V,
 }
 
-struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> { //~ ERROR associated type bindings must be declared after generic parameters
+struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> {
+//~^ ERROR generic arguments must come before the first constraint
     m: M,
     t: T,
     u: U,
@@ -62,7 +63,7 @@ struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> { //~ ERROR associated ty
 }
 
 struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
-//~^ ERROR associated type bindings must be declared after generic parameters
+//~^ ERROR generic arguments must come before the first constraint
 //~^^ ERROR lifetime provided when a type was expected
     m: M,
     t: &'a T,
@@ -70,7 +71,8 @@ struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U,
     v: &'c V,
 }
 
-struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> { //~ ERROR associated type bindings must be declared after generic parameters
+struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> {
+//~^ ERROR generic arguments must come before the first constraint
     m: M,
     t: T,
     u: U,
@@ -78,7 +80,7 @@ struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> { //~ ERROR associated ty
 }
 
 struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
-//~^ ERROR associated type bindings must be declared after generic parameters
+//~^ ERROR generic arguments must come before the first constraint
 //~^^ ERROR lifetime provided when a type was expected
     m: M,
     t: &'a T,
diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr
index ac91813f928..4dd0613757a 100644
--- a/src/test/ui/suggestions/suggest-move-types.stderr
+++ b/src/test/ui/suggestions/suggest-move-types.stderr
@@ -1,81 +1,85 @@
-error: associated type bindings must be declared after generic parameters
-  --> $DIR/suggest-move-types.rs:28:20
+error: generic arguments must come before the first constraint
+  --> $DIR/suggest-move-types.rs:26:26
    |
 LL | struct A<T, M: One<A=(), T>> {
-   |                    ----^^^
+   |                    ----  ^ generic argument
    |                    |
-   |                    this associated type binding should be moved after the generic parameters
+   |                    the first constraint is provided here
 
-error: associated type bindings must be declared after generic parameters
-  --> $DIR/suggest-move-types.rs:34:37
+error: generic arguments must come before the first constraint
+  --> $DIR/suggest-move-types.rs:33:43
    |
 LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
-   |                                     ----^^^^^^^
-   |                                     |
-   |                                     this associated type binding should be moved after the generic parameters
+   |                                     ----  ^  ^^ generic argument
+   |                                     |     |
+   |                                     |     generic argument
+   |                                     the first constraint is provided here
 
-error: associated type bindings must be declared after generic parameters
-  --> $DIR/suggest-move-types.rs:41:28
+error: generic arguments must come before the first constraint
+  --> $DIR/suggest-move-types.rs:40:46
    |
 LL | struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> {
-   |                            ----^^----^^----^^^^^^^^^
-   |                            |     |     |
-   |                            |     |     this associated type binding should be moved after the generic parameters
-   |                            |     this associated type binding should be moved after the generic parameters
-   |                            this associated type binding should be moved after the generic parameters
+   |                            ----              ^  ^  ^ generic argument
+   |                            |                 |  |
+   |                            |                 |  generic argument
+   |                            |                 generic argument
+   |                            the first constraint is provided here
 
-error: associated type bindings must be declared after generic parameters
-  --> $DIR/suggest-move-types.rs:48:53
+error: generic arguments must come before the first constraint
+  --> $DIR/suggest-move-types.rs:48:71
    |
 LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
-   |                                                     ----^^----^^----^^^^^^^^^^^^^^^^^^^^^
-   |                                                     |     |     |
-   |                                                     |     |     this associated type binding should be moved after the generic parameters
-   |                                                     |     this associated type binding should be moved after the generic parameters
-   |                                                     this associated type binding should be moved after the generic parameters
+   |                                                     ----              ^  ^  ^  ^^  ^^  ^^ generic argument
+   |                                                     |                 |  |  |  |   |
+   |                                                     |                 |  |  |  |   generic argument
+   |                                                     |                 |  |  |  generic argument
+   |                                                     |                 |  |  generic argument
+   |                                                     |                 |  generic argument
+   |                                                     |                 generic argument
+   |                                                     the first constraint is provided here
 
-error: associated type bindings must be declared after generic parameters
-  --> $DIR/suggest-move-types.rs:57:28
+error: generic arguments must come before the first constraint
+  --> $DIR/suggest-move-types.rs:57:49
    |
 LL | struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> {
-   |                            ^^^----^^----^^----^^^^^^
-   |                               |     |     |
-   |                               |     |     this associated type binding should be moved after the generic parameters
-   |                               |     this associated type binding should be moved after the generic parameters
-   |                               this associated type binding should be moved after the generic parameters
+   |                               ----              ^  ^ generic argument
+   |                               |                 |
+   |                               |                 generic argument
+   |                               the first constraint is provided here
 
-error: associated type bindings must be declared after generic parameters
-  --> $DIR/suggest-move-types.rs:64:53
+error: generic arguments must come before the first constraint
+  --> $DIR/suggest-move-types.rs:65:78
    |
 LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
-   |                                                     ^^^^^^^----^^----^^----^^^^^^^^^^^^^^
-   |                                                            |     |     |
-   |                                                            |     |     this associated type binding should be moved after the generic parameters
-   |                                                            |     this associated type binding should be moved after the generic parameters
-   |                                                            this associated type binding should be moved after the generic parameters
+   |                                                            ----              ^  ^^  ^  ^^ generic argument
+   |                                                            |                 |  |   |
+   |                                                            |                 |  |   generic argument
+   |                                                            |                 |  generic argument
+   |                                                            |                 generic argument
+   |                                                            the first constraint is provided here
 
-error: associated type bindings must be declared after generic parameters
-  --> $DIR/suggest-move-types.rs:73:28
+error: generic arguments must come before the first constraint
+  --> $DIR/suggest-move-types.rs:74:43
    |
 LL | struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> {
-   |                            ^^^----^^----^^^^^----^^^
-   |                               |     |        |
-   |                               |     |        this associated type binding should be moved after the generic parameters
-   |                               |     this associated type binding should be moved after the generic parameters
-   |                               this associated type binding should be moved after the generic parameters
+   |                               ----        ^        ^ generic argument
+   |                               |           |
+   |                               |           generic argument
+   |                               the first constraint is provided here
 
-error: associated type bindings must be declared after generic parameters
-  --> $DIR/suggest-move-types.rs:80:53
+error: generic arguments must come before the first constraint
+  --> $DIR/suggest-move-types.rs:82:72
    |
 LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
-   |                                                     ^^^^^^^----^^----^^^^^^^^^----^^^^^^^
-   |                                                            |     |            |
-   |                                                            |     |            this associated type binding should be moved after the generic parameters
-   |                                                            |     this associated type binding should be moved after the generic parameters
-   |                                                            this associated type binding should be moved after the generic parameters
+   |                                                            ----        ^  ^^        ^  ^^ generic argument
+   |                                                            |           |  |         |
+   |                                                            |           |  |         generic argument
+   |                                                            |           |  generic argument
+   |                                                            |           generic argument
+   |                                                            the first constraint is provided here
 
 error[E0747]: type provided when a lifetime was expected
-  --> $DIR/suggest-move-types.rs:34:43
+  --> $DIR/suggest-move-types.rs:33:43
    |
 LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
    |                                           ^
@@ -91,7 +95,7 @@ LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U,
    = note: lifetime arguments must be provided before type arguments
 
 error[E0747]: lifetime provided when a type was expected
-  --> $DIR/suggest-move-types.rs:64:56
+  --> $DIR/suggest-move-types.rs:65:56
    |
 LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
    |                                                        ^^
@@ -99,7 +103,7 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=()
    = note: type arguments must be provided before lifetime arguments
 
 error[E0747]: lifetime provided when a type was expected
-  --> $DIR/suggest-move-types.rs:80:56
+  --> $DIR/suggest-move-types.rs:82:56
    |
 LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
    |                                                        ^^