diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index f13d67b9c1584..2e91a1059fe0c 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1095,7 +1095,11 @@ impl Expr {
     pub fn is_potential_trivial_const_param(&self) -> bool {
         let this = if let ExprKind::Block(ref block, None) = self.kind {
             if block.stmts.len() == 1 {
-                if let StmtKind::Expr(ref expr) = block.stmts[0].kind { expr } else { self }
+                if let StmtKind::Expr(ref expr) = block.stmts[0].kind {
+                    expr
+                } else {
+                    self
+                }
             } else {
                 self
             }
@@ -1833,6 +1837,7 @@ impl UintTy {
 pub struct AssocTyConstraint {
     pub id: NodeId,
     pub ident: Ident,
+    pub gen_args: Vec<GenericArg>,
     pub kind: AssocTyConstraintKind,
     pub span: Span,
 }
@@ -1938,7 +1943,11 @@ impl TyKind {
     }
 
     pub fn is_unit(&self) -> bool {
-        if let TyKind::Tup(ref tys) = *self { tys.is_empty() } else { false }
+        if let TyKind::Tup(ref tys) = *self {
+            tys.is_empty()
+        } else {
+            false
+        }
     }
 }
 
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 517717eebd9d0..81ac388114083 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -444,11 +444,14 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
 }
 
 pub fn noop_visit_ty_constraint<T: MutVisitor>(
-    AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint,
+    AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
     vis: &mut T,
 ) {
     vis.visit_id(id);
     vis.visit_ident(ident);
+    for arg in gen_args {
+        vis.visit_generic_arg(arg);
+    }
     match kind {
         AssocTyConstraintKind::Equality { ref mut ty } => {
             vis.visit_ty(ty);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 2ab6667ac3cf1..b7826a88dda7f 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -490,6 +490,9 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
     constraint: &'a AssocTyConstraint,
 ) {
     visitor.visit_ident(constraint.ident);
+    for arg in &constraint.gen_args {
+        visitor.visit_generic_arg(arg);
+    }
     match constraint.kind {
         AssocTyConstraintKind::Equality { ref ty } => {
             visitor.visit_ty(ty);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index af2f96d5e6253..4d90749613f40 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1032,18 +1032,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_assoc_ty_constraint(
         &mut self,
         constraint: &AssocTyConstraint,
-        itctx: ImplTraitContext<'_, 'hir>,
+        mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
 
         let kind = match constraint.kind {
             AssocTyConstraintKind::Equality { ref ty } => {
-                hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }
+                hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx.reborrow()) }
             }
             AssocTyConstraintKind::Bound { ref bounds } => {
                 let mut capturable_lifetimes;
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
-                let (desugar_to_impl_trait, itctx) = match itctx {
+                let (desugar_to_impl_trait, mut itctx) = match itctx {
                     // We are in the return position:
                     //
                     //     fn foo() -> impl Iterator<Item: Debug>
@@ -1052,7 +1052,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     //
                     //     fn foo() -> impl Iterator<Item = impl Debug>
                     ImplTraitContext::ReturnPositionOpaqueTy { .. }
-                    | ImplTraitContext::OtherOpaqueTy { .. } => (true, itctx),
+                    | ImplTraitContext::OtherOpaqueTy { .. } => (true, itctx.reborrow()),
 
                     // We are in the argument position, but within a dyn type:
                     //
@@ -1061,7 +1061,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // so desugar to
                     //
                     //     fn foo(x: dyn Iterator<Item = impl Debug>)
-                    ImplTraitContext::Universal(..) if self.is_in_dyn_type => (true, itctx),
+                    ImplTraitContext::Universal(..) if self.is_in_dyn_type => {
+                        (true, itctx.reborrow())
+                    }
 
                     // In `type Foo = dyn Iterator<Item: Debug>` we desugar to
                     // `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
@@ -1087,7 +1089,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // so we leave it as is and this gets expanded in astconv to a bound like
                     // `<T as Iterator>::Item: Debug` where `T` is the type parameter for the
                     // `impl Iterator`.
-                    _ => (false, itctx),
+                    _ => (false, itctx.reborrow()),
                 };
 
                 if desugar_to_impl_trait {
@@ -1113,7 +1115,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 span: constraint.span,
                                 tokens: None,
                             },
-                            itctx,
+                            itctx.reborrow(),
                         );
 
                         hir::TypeBindingKind::Equality { ty }
@@ -1121,16 +1123,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 } else {
                     // Desugar `AssocTy: Bounds` into a type binding where the
                     // later desugars into a trait predicate.
-                    let bounds = self.lower_param_bounds(bounds, itctx);
+                    let bounds = self.lower_param_bounds(bounds, itctx.reborrow());
 
                     hir::TypeBindingKind::Constraint { bounds }
                 }
             }
         };
 
+        debug!(
+            "lower_assoc_ty_constraint: generic args of AssocTyConstraint: {:?}",
+            constraint.gen_args
+        );
+        let args: &'hir mut [GenericArg<'hir>] = self.arena.alloc_from_iter(
+            constraint.gen_args.iter().map(|arg| self.lower_generic_arg(&arg, itctx.reborrow())),
+        );
+        debug!("lower_assoc_ty_constraint: lowered generic args: {:?}", args);
+        let bindings: &'hir mut [hir::TypeBinding<'hir>] = arena_vec![self;];
+        let gen_args = self.arena.alloc(hir::GenericArgs { args, bindings, parenthesized: false });
+
         hir::TypeBinding {
             hir_id: self.lower_node_id(constraint.id),
             ident: constraint.ident,
+            gen_args,
             kind,
             span: constraint.span,
         }
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 6afed355dc338..8ca919f56629f 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -426,6 +426,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     ) -> hir::TypeBinding<'hir> {
         let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
         let kind = hir::TypeBindingKind::Equality { ty };
-        hir::TypeBinding { hir_id: self.next_id(), span, ident, kind }
+        let args = arena_vec![self;];
+        let bindings = arena_vec![self;];
+        let gen_args = self.arena.alloc(hir::GenericArgs { args, bindings, parenthesized: false });
+        hir::TypeBinding { hir_id: self.next_id(), gen_args, span, ident, kind }
     }
 }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index d6585bcc4259b..3275a700502b4 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1350,6 +1350,29 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     }
 }
 
+fn get_generic_args_from_path_segment(path_segment: &PathSegment) -> Vec<GenericArg> {
+    let mut generic_args: Vec<GenericArg> = vec![];
+    if let Some(ref args) = path_segment.args {
+        match &**args {
+            GenericArgs::AngleBracketed(ref angle_args) => {
+                for arg in &angle_args.args {
+                    match arg {
+                        AngleBracketedArg::Arg(gen_arg) => match gen_arg {
+                            GenericArg::Lifetime(_) | GenericArg::Type(_) => {
+                                generic_args.push((*gen_arg).clone())
+                            }
+                            _ => {}
+                        },
+                        _ => {}
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+    generic_args
+}
+
 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
 /// like it's setting an associated type, provide an appropriate suggestion.
 fn deny_equality_constraints(
@@ -1372,16 +1395,18 @@ fn deny_equality_constraints(
                         if param.ident == *ident {
                             let param = ident;
                             match &full_path.segments[qself.position..] {
-                                [PathSegment { ident, .. }] => {
+                                [path @ PathSegment { ident, .. }] => {
                                     // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
                                     let mut assoc_path = full_path.clone();
                                     // Remove `Bar` from `Foo::Bar`.
                                     assoc_path.segments.pop();
                                     let len = assoc_path.segments.len() - 1;
+                                    let generic_args = get_generic_args_from_path_segment(&path);
                                     // Build `<Bar = RhsTy>`.
                                     let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
                                         id: rustc_ast::node_id::DUMMY_NODE_ID,
                                         ident: *ident,
+                                        gen_args: generic_args,
                                         kind: AssocTyConstraintKind::Equality {
                                             ty: predicate.rhs_ty.clone(),
                                         },
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 9fcba90244330..ddcfce3a721ad 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -937,6 +937,13 @@ impl<'a> State<'a> {
 
     pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
         self.print_ident(constraint.ident);
+        if constraint.gen_args.len() > 0 {
+            self.s.word("<");
+            for arg in &constraint.gen_args {
+                self.print_generic_arg(arg);
+            }
+            self.s.word(">");
+        }
         self.s.space();
         match &constraint.kind {
             ast::AssocTyConstraintKind::Equality { ty } => {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 3c28b48795f56..ff839c4f7b039 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -497,7 +497,11 @@ pub struct WhereClause<'hir> {
 
 impl WhereClause<'_> {
     pub fn span(&self) -> Option<Span> {
-        if self.predicates.is_empty() { None } else { Some(self.span) }
+        if self.predicates.is_empty() {
+            None
+        } else {
+            Some(self.span)
+        }
     }
 
     /// The `WhereClause` under normal circumstances points at either the predicates or the empty
@@ -1940,6 +1944,7 @@ pub struct TypeBinding<'hir> {
     pub hir_id: HirId,
     #[stable_hasher(project(name))]
     pub ident: Ident,
+    pub gen_args: &'hir GenericArgs<'hir>,
     pub kind: TypeBindingKind<'hir>,
     pub span: Span,
 }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 35615af0fc7df..f4012ca919d9b 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -758,6 +758,8 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
 ) {
     visitor.visit_id(type_binding.hir_id);
     visitor.visit_ident(type_binding.ident);
+    // FIXME: Pass the correct span for the generic arguments here
+    visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
     match type_binding.kind {
         TypeBindingKind::Equality { ref ty } => {
             visitor.visit_ty(ty);
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index f7018ae62aa19..dce1d78ff31a9 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1801,6 +1801,7 @@ impl<'a> State<'a> {
             for binding in generic_args.bindings.iter() {
                 start_or_comma(self);
                 self.print_ident(binding.ident);
+                self.print_generic_args(binding.gen_args, false, false);
                 self.s.space();
                 match generic_args.bindings[0].kind {
                     hir::TypeBindingKind::Equality { ref ty } => {
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 79e737490386c..36e62ce0e5eeb 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -4,7 +4,8 @@ use crate::maybe_whole;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token};
 use rustc_ast::{
-    self as ast, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs,
+    self as ast, AngleBracketedArg, AngleBracketedArgs, GenericArg, GenericArgs, ParenthesizedArgs,
+    TyKind,
 };
 use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
 use rustc_ast::{Path, PathSegment, QSelf};
@@ -420,7 +421,7 @@ impl<'a> Parser<'a> {
             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)?;
+                let ty = self.parse_assoc_equality_term(Some(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))?;
@@ -435,38 +436,92 @@ impl<'a> Parser<'a> {
             if let AssocTyConstraintKind::Bound { .. } = kind {
                 self.sess.gated_spans.gate(sym::associated_type_bounds, span);
             }
-
-            let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span };
+            let constraint =
+                AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args: vec![], kind, span };
             Ok(Some(AngleBracketedArg::Constraint(constraint)))
         } else {
-            Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg))
+            let lo = self.token.span;
+            let arg = self.parse_generic_arg()?;
+            if self.eat(&token::Eq) {
+                // Parse the type of the equality constraint even if parsing of the associated type failed
+                match self.get_assoc_type_with_generic_args(arg, lo) {
+                    Ok((ident, gen_args)) => {
+                        let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
+                        let kind = AssocTyConstraintKind::Equality { ty };
+                        let span = lo.to(self.prev_token.span);
+                        let constraint = AssocTyConstraint {
+                            id: ast::DUMMY_NODE_ID,
+                            ident: ident.unwrap(), // parse_assoc_equality_terms return Ok(Some) iff ident is Some
+                            gen_args,
+                            kind,
+                            span,
+                        };
+                        return Ok(Some(AngleBracketedArg::Constraint(constraint)));
+                    }
+                    Err(err) => {
+                        let _ = self.parse_assoc_equality_term(None, self.prev_token.span);
+                        return Err(err);
+                    }
+                }
+            /*
+            let (ident, gen_args) = self.get_assoc_type_with_generic_args(arg, lo)?;
+            // Parse the type of the equality constraint even if parsing of the associated type failed
+            if let Ok(Some(ty)) = self.parse_assoc_equality_term(ident, self.prev_token.span) {
+                let kind = AssocTyConstraintKind::Equality { ty };
+                let span = lo.to(self.prev_token.span);
+                let constraint = AssocTyConstraint {
+                    id: ast::DUMMY_NODE_ID,
+                    ident: ident.unwrap(), // parse_assoc_equality_terms return Ok(Some) iff ident is Some
+                    gen_args,
+                    kind,
+                    span,
+                };
+                return Ok(Some(AngleBracketedArg::Constraint(constraint)));
+            */
+            } else {
+                Ok(arg.map(AngleBracketedArg::Arg))
+            }
         }
     }
 
     /// 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>> {
+    fn parse_assoc_equality_term(
+        &mut self,
+        ident: Option<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")
+
+        if let Some(ident) = ident {
+            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 `=`")
+                }
+                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 `=`",
@@ -480,9 +535,10 @@ impl<'a> Parser<'a> {
                         Applicability::MaybeIncorrect,
                     )
                     .emit();
+                }
             }
         }
-        Ok(self.mk_ty(span, ast::TyKind::Err))
+        Ok(self.mk_ty(eq, ast::TyKind::Err))
     }
 
     /// We do not permit arbitrary expressions as const arguments. They must be one of:
@@ -503,35 +559,141 @@ impl<'a> Parser<'a> {
     /// 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 start = self.token.span;
         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 value = if let token::OpenDelim(token::Brace) = self.token.kind {
+            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.handle_unambiguous_unbraced_const_arg()?
+                self.parse_literal_maybe_minus()?
             };
-            GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
+            GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: expr })
         } else if self.check_type() {
             // Parse type argument.
-            match self.parse_ty() {
-                Ok(ty) => GenericArg::Type(ty),
-                Err(err) => {
-                    // Try to recover from possible `const` arg without braces.
-                    return self.recover_const_arg(start, err).map(Some);
-                }
-            }
+            GenericArg::Type(self.parse_ty()?)
         } else {
             return Ok(None);
         };
         Ok(Some(arg))
     }
+
+    fn get_assoc_type_with_generic_args(
+        &self,
+        gen_arg: Option<GenericArg>,
+        lo: Span,
+    ) -> PResult<'a, (Option<Ident>, Vec<GenericArg>)> {
+        if let Some(arg) = gen_arg {
+            match arg {
+                GenericArg::Type(t) => match &(*t).kind {
+                    TyKind::Path(_, path) => {
+                        if path.segments.len() == 1 {
+                            let path_seg = &path.segments[0];
+                            let ident = path_seg.ident;
+                            let gen_args = self.get_generic_args_from_path_segment(&path_seg)?;
+                            debug!("get_assoc_type_with_generic_args gen_args: {:?}", gen_args);
+                            return Ok((Some(ident), gen_args));
+                        } else {
+                            let mut err = self.struct_span_err(
+                                path.span,
+                                "found a Path with multiple segments, expected a Path with a single segment",
+                            );
+                            err.span_label(path.span, "expected the name of an associated type");
+                            err.span_suggestion(
+                                path.span,
+                                "try to use only the last segment:",
+                                format!("{}", path.segments.last().unwrap().ident),
+                                Applicability::MaybeIncorrect,
+                            );
+                            return Err(err);
+                        }
+                    }
+                    _ => {
+                        let mut err = self.struct_span_err(
+                            lo.to(self.prev_token.span),
+                            "Incorrect type of generic argument, expected a Path with a single path segment",
+                        );
+                        err.span_label(
+                            self.prev_token.span,
+                            "Expected the name of an associated type",
+                        );
+                        return Err(err);
+                    }
+                },
+                _ => {
+                    let span = lo.to(self.prev_token.span);
+                    let mut err = self.struct_span_err(
+                        span,
+                        "Incorrect type of generic argument, expected a path with a single segment",
+                    );
+                    err.span_label(span, "expected the name of an associated type");
+                    return Err(err);
+                }
+            };
+        }
+        // Wrong span here
+        let err = self.struct_span_err(lo, "unable to parse generic argument");
+        Err(err)
+    }
+
+    fn get_generic_args_from_path_segment(
+        &self,
+        path_segment: &PathSegment,
+    ) -> PResult<'a, Vec<GenericArg>> {
+        debug!("get_generic_args_from_path_segment(path_segment: {:?}", path_segment);
+        let span = path_segment.ident.span;
+        let mut generic_args: Vec<GenericArg> = vec![];
+        if let Some(ref args) = path_segment.args {
+            match &**args {
+                GenericArgs::AngleBracketed(ref angle_args) => {
+                    for arg in &angle_args.args {
+                        match arg {
+                            AngleBracketedArg::Arg(gen_arg) => match gen_arg {
+                                GenericArg::Lifetime(_) | GenericArg::Type(_) => {
+                                    generic_args.push((*gen_arg).clone())
+                                }
+                                _ => {
+                                    self.struct_span_err(
+                                        span,
+                                        "generic arguments of associated types must be lifetimes or types",
+                                    )
+                                    .emit();
+                                }
+                            },
+                            AngleBracketedArg::Constraint(_) => unreachable!(),
+                        }
+                    }
+                }
+                GenericArgs::Parenthesized(paren_args) => {
+                    let span = paren_args.span;
+                    self.struct_span_err(
+                        span,
+                        "invalid use of parenthesized generic arguments, expected angle \
+                         bracketed (`<...>`) generic arguments",
+                    )
+                    .emit();
+                }
+            }
+        }
+        Ok(generic_args)
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 32e0991733bd9..5164ed805ee42 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -257,13 +257,11 @@ fn predicates_reference_self(
 }
 
 fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
-    let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
     tcx.associated_items(trait_def_id)
         .in_definition_order()
         .filter(|item| item.kind == ty::AssocKind::Type)
         .flat_map(|item| tcx.explicit_item_bounds(item.def_id))
-        .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
-        .filter_map(|predicate| predicate_references_self(tcx, predicate))
+        .filter_map(|pred_span_tuple| predicate_references_self(tcx, *pred_span_tuple))
         .collect()
 }
 
@@ -276,7 +274,11 @@ fn predicate_references_self(
     match predicate.skip_binders() {
         ty::PredicateAtom::Trait(ref data, _) => {
             // In the case of a trait predicate, we can skip the "self" type.
-            if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
+            if data.trait_ref.substs[1..].iter().any(has_self_ty) {
+                Some(sp)
+            } else {
+                None
+            }
         }
         ty::PredicateAtom::Projection(ref data) => {
             // And similarly for projections. This should be redundant with
@@ -528,7 +530,11 @@ fn receiver_for_self_ty<'tcx>(
 ) -> Ty<'tcx> {
     debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
     let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| {
-        if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
+        if param.index == 0 {
+            self_ty.into()
+        } else {
+            tcx.mk_param_from_def(param)
+        }
     });
 
     let result = receiver_ty.subst(tcx, substs);
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 07e523af3ebf5..afe8a9fd26337 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -64,7 +64,7 @@ pub trait AstConv<'tcx> {
 
     /// Returns the lifetime to use when a lifetime is omitted (and not elided).
     fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span)
-    -> Option<ty::Region<'tcx>>;
+        -> Option<ty::Region<'tcx>>;
 
     /// Returns the type to use when a type is omitted.
     fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>;
@@ -112,12 +112,15 @@ pub enum SizedByDefault {
     No,
 }
 
+#[derive(Debug)]
 struct ConvertedBinding<'a, 'tcx> {
     item_name: Ident,
     kind: ConvertedBindingKind<'a, 'tcx>,
+    gen_args: &'a GenericArgs<'a>,
     span: Span,
 }
 
+#[derive(Debug)]
 enum ConvertedBindingKind<'a, 'tcx> {
     Equality(Ty<'tcx>),
     Constraint(&'a [hir::GenericBound<'a>]),
@@ -475,7 +478,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         ConvertedBindingKind::Constraint(bounds)
                     }
                 };
-                ConvertedBinding { item_name: binding.ident, kind, span: binding.span }
+                ConvertedBinding {
+                    item_name: binding.ident,
+                    kind,
+                    gen_args: binding.gen_args,
+                    span: binding.span,
+                }
             })
             .collect();
 
@@ -812,7 +820,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id());
 
         bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
-            if !self.is_unsized(ast_bounds, span) { Some(span) } else { None }
+            if !self.is_unsized(ast_bounds, span) {
+                Some(span)
+            } else {
+                None
+            }
         } else {
             None
         };
@@ -836,60 +848,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         dup_bindings: &mut FxHashMap<DefId, Span>,
         path_span: Span,
     ) -> Result<(), ErrorReported> {
-        let tcx = self.tcx();
-
-        if !speculative {
-            // Given something like `U: SomeTrait<T = X>`, we want to produce a
-            // predicate like `<U as SomeTrait>::T = X`. This is somewhat
-            // subtle in the event that `T` is defined in a supertrait of
-            // `SomeTrait`, because in that case we need to upcast.
-            //
-            // That is, consider this case:
-            //
-            // ```
-            // trait SubTrait: SuperTrait<i32> { }
-            // trait SuperTrait<A> { type T; }
-            //
-            // ... B: SubTrait<T = foo> ...
-            // ```
-            //
-            // We want to produce `<B as SuperTrait<i32>>::T == foo`.
-
-            // Find any late-bound regions declared in `ty` that are not
-            // declared in the trait-ref. These are not well-formed.
-            //
-            // Example:
-            //
-            //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
-            //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
-            if let ConvertedBindingKind::Equality(ty) = binding.kind {
-                let late_bound_in_trait_ref =
-                    tcx.collect_constrained_late_bound_regions(&trait_ref);
-                let late_bound_in_ty =
-                    tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
-                debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
-                debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+        // Given something like `U: SomeTrait<T = X>`, we want to produce a
+        // predicate like `<U as SomeTrait>::T = X`. This is somewhat
+        // subtle in the event that `T` is defined in a supertrait of
+        // `SomeTrait`, because in that case we need to upcast.
+        //
+        // That is, consider this case:
+        //
+        // ```
+        // trait SubTrait: SuperTrait<i32> { }
+        // trait SuperTrait<A> { type T; }
+        //
+        // ... B: SubTrait<T = foo> ...
+        // ```
+        //
+        // We want to produce `<B as SuperTrait<i32>>::T == foo`.
 
-                // FIXME: point at the type params that don't have appropriate lifetimes:
-                // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
-                //                         ----  ----     ^^^^^^^
-                self.validate_late_bound_regions(
-                    late_bound_in_trait_ref,
-                    late_bound_in_ty,
-                    |br_name| {
-                        struct_span_err!(
-                            tcx.sess,
-                            binding.span,
-                            E0582,
-                            "binding for associated type `{}` references {}, \
-                             which does not appear in the trait input types",
-                            binding.item_name,
-                            br_name
-                        )
-                    },
-                );
-            }
-        }
+        debug!("add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}",
+               hir_ref_id, trait_ref, binding, bounds);
+        let tcx = self.tcx();
 
         let candidate =
             if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
@@ -948,20 +925,81 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 .or_insert(binding.span);
         }
 
+        // Include substitutions for generic parameters of associated types
+        let candidate_new = candidate.map_bound(|trait_ref| {
+            let item_segment = hir::PathSegment {
+                ident: assoc_ty.ident,
+                hir_id: None,
+                res: None,
+                args: Some(binding.gen_args),
+                infer_args: false,
+            };
+
+            let substs_assoc_item = self.create_substs_for_associated_item(
+                tcx,
+                path_span,
+                assoc_ty.def_id,
+                &item_segment,
+                trait_ref.substs,
+            );
+
+            debug!("substs for assoc_item: {:?}", substs_assoc_item);
+            ty::TraitRef::new(trait_ref.def_id, substs_assoc_item)
+        });
+
+        if !speculative {
+            // Find any late-bound regions declared in `ty` that are not
+            // declared in the trait-ref. These are not well-formed.
+            //
+            // Example:
+            //
+            //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
+            //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
+            if let ConvertedBindingKind::Equality(ty) = binding.kind {
+                let late_bound_in_trait_ref =
+                    tcx.collect_constrained_late_bound_regions(&candidate_new);
+                let late_bound_in_ty =
+                    tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
+                debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
+                debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+
+                // FIXME: point at the type params that don't have appropriate lifetimes:
+                // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
+                //                         ----  ----     ^^^^^^^
+                self.validate_late_bound_regions(
+                    late_bound_in_trait_ref,
+                    late_bound_in_ty,
+                    |br_name| {
+                        struct_span_err!(
+                            tcx.sess,
+                            binding.span,
+                            E0582,
+                            "binding for associated type `{}` references {}, \
+                             which does not appear in the trait input types",
+                            binding.item_name,
+                            br_name
+                        )
+                    },
+                );
+            }
+        }
+
         match binding.kind {
             ConvertedBindingKind::Equality(ref ty) => {
                 // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
                 // the "projection predicate" for:
                 //
                 // `<T as Iterator>::Item = u32`
+
                 bounds.projection_bounds.push((
-                    candidate.map_bound(|trait_ref| ty::ProjectionPredicate {
-                        projection_ty: ty::ProjectionTy::from_ref_and_name(
-                            tcx,
-                            trait_ref,
-                            binding.item_name,
-                        ),
-                        ty,
+                    candidate_new.map_bound(|trait_ref| {
+                        let projection_ty =
+                            ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, binding.item_name);
+                        debug!(
+                            "projection_ty {:?}, substs: {:?}",
+                            projection_ty, projection_ty.substs
+                        );
+                        ty::ProjectionPredicate { projection_ty, ty }
                     }),
                     binding.span,
                 ));
@@ -1908,7 +1946,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     path_segs.iter().map(|PathSeg(_, index)| index).collect();
                 self.prohibit_generics(path.segments.iter().enumerate().filter_map(
                     |(index, seg)| {
-                        if !generic_segs.contains(&index) { Some(seg) } else { None }
+                        if !generic_segs.contains(&index) {
+                            Some(seg)
+                        } else {
+                            None
+                        }
                     },
                 ));
 
diff --git a/src/test/ui/generic-associated-types/gat_in_trait_path.rs b/src/test/ui/generic-associated-types/gat_in_trait_path.rs
new file mode 100644
index 0000000000000..c47c1e2eab0a4
--- /dev/null
+++ b/src/test/ui/generic-associated-types/gat_in_trait_path.rs
@@ -0,0 +1,27 @@
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+
+trait Foo {
+    type A<'a> where Self: 'a;
+}
+
+struct Fooy;
+
+impl Foo for Fooy {
+    type A<'a> = (&'a ());
+}
+
+#[derive(Clone)]
+struct Fooer<T>(T);
+
+impl<T> Foo for Fooer<T> {
+    type A<'x> where T: 'x = (&'x ());
+}
+
+fn f(arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
+
+
+fn main() {
+  let foo = Fooer(5);
+  f(Box::new(foo));
+}
diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.rs b/src/test/ui/generic-associated-types/issue-67510-pass.rs
new file mode 100644
index 0000000000000..d89298753ace3
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-67510-pass.rs
@@ -0,0 +1,11 @@
+#![feature(generic_associated_types)]
+
+trait X {
+    type Y<'a>;
+}
+
+fn func1<'a>(x: Box<dyn X<Y<'a>=&'a ()>>) {}
+
+fn func2(x: Box<dyn for<'a> X<Y<'a>=&'a ()>>) {}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.stderr b/src/test/ui/generic-associated-types/issue-67510-pass.stderr
new file mode 100644
index 0000000000000..4ea12356432c7
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-67510-pass.stderr
@@ -0,0 +1,39 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510-pass.rs:1:12
+  |
+1 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+
+warning: unused variable: `x`
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510-pass.rs:7:14
+  |
+7 | fn func1<'a>(x: Box<dyn X<Y<'a>=&'a ()>>) {}
+  |              ^ help: if this is intentional, prefix it with an underscore: `_x`
+  |
+  = note: `#[warn(unused_variables)]` on by default
+
+warning: unused variable: `x`
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510-pass.rs:9:10
+  |
+9 | fn func2(x: Box<dyn for<'a> X<Y<'a>=&'a ()>>) {}
+  |          ^ help: if this is intentional, prefix it with an underscore: `_x`
+
+warning: function is never used: `func1`
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510-pass.rs:7:4
+  |
+7 | fn func1<'a>(x: Box<dyn X<Y<'a>=&'a ()>>) {}
+  |    ^^^^^
+  |
+  = note: `#[warn(dead_code)]` on by default
+
+warning: function is never used: `func2`
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510-pass.rs:9:4
+  |
+9 | fn func2(x: Box<dyn for<'a> X<Y<'a>=&'a ()>>) {}
+  |    ^^^^^
+
+warning: 5 warnings emitted
diff --git a/src/test/ui/generic-associated-types/issue-67510.rs b/src/test/ui/generic-associated-types/issue-67510.rs
new file mode 100644
index 0000000000000..834913f9ec6a3
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-67510.rs
@@ -0,0 +1,9 @@
+#![feature(generic_associated_types)]
+
+trait X {
+    type Y<'a>;
+}
+
+fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-67510.stderr b/src/test/ui/generic-associated-types/issue-67510.stderr
new file mode 100644
index 0000000000000..b518295476fa0
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-67510.stderr
@@ -0,0 +1,33 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510.rs:1:12
+  |
+1 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+
+error[E0261]: use of undeclared lifetime name `'a`
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510.rs:7:21
+  |
+7 | fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
+  |     -               ^^ undeclared lifetime
+  |     |
+  |     help: consider introducing lifetime `'a` here: `<'a>`
+  |
+  = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
+
+error[E0261]: use of undeclared lifetime name `'a`
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510.rs:7:26
+  |
+7 | fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
+  |     -                    ^^ undeclared lifetime
+  |     |
+  |     help: consider introducing lifetime `'a` here: `<'a>`
+  |
+  = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0261`.
diff --git a/src/test/ui/generic-associated-types/issue-68648-fail-1.rs b/src/test/ui/generic-associated-types/issue-68648-fail-1.rs
new file mode 100644
index 0000000000000..7a56f8c69cc64
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68648-fail-1.rs
@@ -0,0 +1,22 @@
+#![feature(generic_associated_types)]
+
+trait Fun {
+    type F<'a>;
+    
+    fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t }
+}
+
+impl <T> Fun for T {
+    type F<'a> = Self;
+}
+
+fn bug<'a, T: Fun<F = T>>(t: T) -> T::F<'a> {
+    T::identity(t)
+}
+
+
+fn main() {
+    let x = 10;
+    
+    bug(x);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68648-fail-1.stderr b/src/test/ui/generic-associated-types/issue-68648-fail-1.stderr
new file mode 100644
index 0000000000000..6cb6798ed004d
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68648-fail-1.stderr
@@ -0,0 +1,18 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-68648-fail-1.rs:1:12
+  |
+1 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0107]: wrong number of lifetime arguments: expected 1, found 0
+  --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-68648-fail-1.rs:13:19
+   |
+13 | fn bug<'a, T: Fun<F = T>>(t: T) -> T::F<'a> {
+   |                   ^^^^^ expected 1 lifetime argument
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/generic-associated-types/issue-68648-pass-2.rs b/src/test/ui/generic-associated-types/issue-68648-pass-2.rs
new file mode 100644
index 0000000000000..9460e08a4229a
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68648-pass-2.rs
@@ -0,0 +1,22 @@
+#![feature(generic_associated_types)]
+
+trait Fun {
+    type F<'a>;
+    
+    fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t }
+}
+
+impl <T> Fun for T {
+    type F<'a> = Self;
+}
+
+fn bug<'a, T: for<'b> Fun<F<'b> = T>>(t: T) -> T::F<'a> {
+    T::identity(t)
+}
+
+
+fn main() {
+    let x = 10;
+    
+    bug(x);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68648-pass.rs b/src/test/ui/generic-associated-types/issue-68648-pass.rs
new file mode 100644
index 0000000000000..2a1c98c3040b1
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68648-pass.rs
@@ -0,0 +1,24 @@
+// build-pass
+
+#![feature(generic_associated_types)]
+
+trait Fun {
+    type F<'a>;
+    
+    fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t }
+}
+
+impl <T> Fun for T {
+    type F<'a> = Self;
+}
+
+fn bug<'a, T: Fun<F<'a> = T>>(t: T) -> T::F<'a> {
+    T::identity(t)
+}
+
+
+fn main() {
+    let x = 10;
+    
+    bug(x);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68649-pass.rs b/src/test/ui/generic-associated-types/issue-68649-pass.rs
new file mode 100644
index 0000000000000..295f999389655
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68649-pass.rs
@@ -0,0 +1,22 @@
+#![feature(generic_associated_types)]
+
+trait Fun {
+    type F<'a>;
+    
+    fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t }
+}
+
+impl <T> Fun for T {
+    type F<'a> = Self;
+}
+
+fn bug<'a, T: Fun<F = ()>>(t: T) -> T::F<'a> {
+    T::identity(())
+}
+
+
+fn main() {
+    let x = 10;
+    
+    bug(x);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68649.rs b/src/test/ui/generic-associated-types/issue-68649.rs
new file mode 100644
index 0000000000000..20e18cf052993
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68649.rs
@@ -0,0 +1,23 @@
+#![feature(generic_associated_types)]
+
+trait Fun {
+    type F<'a>;
+    
+    fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t }
+}
+
+impl <T> Fun for T {
+    type F<'a> = Self;
+}
+
+fn bug<'a, T: for<'b> Fun<F<'b> = ()>>(t: T) -> T::F<'a> {
+    T::identity(())
+    //~^ ERROR: type mismatch resolving `for<'b> <{integer} as Fun>::F<'b> == ()`
+}
+
+
+fn main() {
+    let x = 10;
+    
+    bug(x);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68649.stderr b/src/test/ui/generic-associated-types/issue-68649.stderr
new file mode 100644
index 0000000000000..c52fe8900e0c3
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68649.stderr
@@ -0,0 +1,21 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-68649.rs:1:12
+  |
+1 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0271]: type mismatch resolving `for<'b> <{integer} as Fun>::F<'b> == ()`
+  --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-68649.rs:22:5
+   |
+13 | fn bug<'a, T: for<'b> Fun<F<'b> = ()>>(t: T) -> T::F<'a> {
+   |                           ---------- required by this bound in `bug`
+...
+22 |     bug(x);
+   |     ^^^ expected `()`, found integer
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generic-associated-types/issue-74684-fail-1.rs b/src/test/ui/generic-associated-types/issue-74684-fail-1.rs
new file mode 100644
index 0000000000000..f1fbb9ba0b113
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-74684-fail-1.rs
@@ -0,0 +1,24 @@
+#![feature(generic_associated_types)]
+trait Fun {
+    type F<'a>: ?Sized;
+    
+    fn identity<'a>(t: &'a Self::F<'a>) -> &'a Self::F<'a> { t }
+}
+
+impl <T> Fun for T {
+    type F<'a> = i32;
+}
+
+fn bug<'a, T: ?Sized + Fun<F = [u8]>>(t: Box<T>) -> &'static T::F<'a> {
+    //~^ ERROR: wrong number of lifetime arguments: expected 1, found 0
+    let a = [0; 1];
+    let x = T::identity(&a);
+    todo!()
+}
+
+
+fn main() {
+    let x = 10;
+    
+    bug(Box::new(x));
+}
diff --git a/src/test/ui/generic-associated-types/issue-74684-fail-1.stderr b/src/test/ui/generic-associated-types/issue-74684-fail-1.stderr
new file mode 100644
index 0000000000000..f4d202e65c70d
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-74684-fail-1.stderr
@@ -0,0 +1,18 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-74684-fail-1.rs:1:12
+  |
+1 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0107]: wrong number of lifetime arguments: expected 1, found 0
+  --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-74684-fail-1.rs:12:28
+   |
+12 | fn bug<'a, T: ?Sized + Fun<F = [u8]>>(t: Box<T>) -> &'static T::F<'a> {
+   |                            ^^^^^^^^ expected 1 lifetime argument
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/generic-associated-types/issue-74684-fail-2.rs b/src/test/ui/generic-associated-types/issue-74684-fail-2.rs
new file mode 100644
index 0000000000000..0d1c078df009b
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-74684-fail-2.rs
@@ -0,0 +1,23 @@
+#![feature(generic_associated_types)]
+trait Fun {
+    type F<'a>: ?Sized;
+    
+    fn identity<'a>(t: &'a Self::F<'a>) -> &'a Self::F<'a> { t }
+}
+
+impl <T> Fun for T {
+    type F<'a> = i32;
+}
+
+fn bug<'a, T: ?Sized + Fun<F<'a> = [u8]>>(t: Box<T>) -> &'static T::F<'a> {
+    let a = [0; 1];
+    let x = T::identity(&a);
+    todo!()
+}
+
+
+fn main() {
+    let x = 10;
+    
+    bug(Box::new(x));
+}
diff --git a/src/test/ui/generic-associated-types/issue-74684-fail-2.stderr b/src/test/ui/generic-associated-types/issue-74684-fail-2.stderr
new file mode 100644
index 0000000000000..3fa3119694c32
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-74684-fail-2.stderr
@@ -0,0 +1,21 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-74684-fail-2.rs:1:12
+  |
+1 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0271]: type mismatch resolving `<{integer} as Fun>::F<'_> == [u8]`
+  --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-74684-fail-2.rs:22:5
+   |
+12 | fn bug<'a, T: ?Sized + Fun<F<'a> = [u8]>>(t: Box<T>) -> &'static T::F<'a> {
+   |                            ------------ required by this bound in `bug`
+...
+22 |     bug(Box::new(x));
+   |     ^^^ expected slice `[u8]`, found `i32`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generic-associated-types/issue-74684-pass.rs b/src/test/ui/generic-associated-types/issue-74684-pass.rs
new file mode 100644
index 0000000000000..7d27954e0fbe4
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-74684-pass.rs
@@ -0,0 +1,26 @@
+// build-pass
+
+#![feature(generic_associated_types)]
+
+trait Fun {
+    type F<'a>: ?Sized;
+
+    fn identity<'a>(t: &'a Self::F<'a>) -> &'a Self::F<'a> { t }
+}
+
+impl <T> Fun for T {
+    type F<'a> = [u8];
+}
+
+fn bug<'a, T: ?Sized + Fun<F<'a> = [u8]>>(t: Box<T>) -> &'static T::F<'a> {
+    let a = [0; 1];
+    let x = T::identity(&a);
+    todo!()
+}
+
+
+fn main() {
+    let x = 10;
+
+    bug(Box::new(x));
+}
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-1.rs b/src/test/ui/generic-associated-types/parse/issue-67510-1.rs
new file mode 100644
index 0000000000000..5be5013283ec0
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-1.rs
@@ -0,0 +1,16 @@
+// Several parsing errors for associated type constraints that are supposed
+// to trigger all errors in ´get_assoc_type_with_generics´ and
+// ´get_generic_args_from_path_segment´ 
+
+#![feature(generic_associated_types)]
+
+trait X {
+    type Y<'a>;
+}
+
+trait Z {}
+
+impl<T : X<X::Y<'a> = &'a u32>> Z for T {} 
+    //~^ ERROR: associated types cannot contain multiple path segments 
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-1.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-1.stderr
new file mode 100644
index 0000000000000..256c926919d25
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-1.stderr
@@ -0,0 +1,10 @@
+error: found a Path with multiple segments, expected a Path with a single segment
+  --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-1.rs:13:12
+   |
+13 | impl<T : X<X::Y<'a> = &'a u32>> Z for T {} 
+   |            ^^^^^^^^
+   |            |
+   |            expected the name of an associated type
+   |            help: try to use only the last segment:: `Y`
+
+error: aborting due to previous error
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-2.rs b/src/test/ui/generic-associated-types/parse/issue-67510-2.rs
new file mode 100644
index 0000000000000..4f946d50d9cef
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-2.rs
@@ -0,0 +1,12 @@
+// Only accept generic arguments of typeTyKind::Path as associated types in
+// trait paths
+#![feature(generic_associated_types)]
+
+trait X { 
+    type Y<'a>;
+}
+
+fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {} 
+    //~^ ERROR: Expected the name of an associated type
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-2.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-2.stderr
new file mode 100644
index 0000000000000..40816c27fa17f
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-2.stderr
@@ -0,0 +1,18 @@
+error: Incorrect type of generic argument, expected a Path with a single path segment
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-2.rs:9:27
+  |
+9 | fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {} 
+  |                           ^^^^^^^^-
+  |                                   |
+  |                                   Expected the name of an associated type
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-2.rs:3:12
+  |
+3 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to previous error; 1 warning emitted
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-3.rs b/src/test/ui/generic-associated-types/parse/issue-67510-3.rs
new file mode 100644
index 0000000000000..6cdf4fdb7cafd
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-3.rs
@@ -0,0 +1,12 @@
+// Test to ensure that only GenericArg::Type is accepted in associated type
+// constraints
+#![feature(generic_associated_types)]
+
+trait X { 
+    type Y<'a>;
+}
+
+fn f1<'a>(arg : Box<dyn X<'a = &'a ()>>) {}  
+    //~^ ERROR: Expected the name of an associated type
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-3.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-3.stderr
new file mode 100644
index 0000000000000..faa8a18f000b3
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-3.stderr
@@ -0,0 +1,16 @@
+error: Incorrect type of generic argument, expected a path with a single segment
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-3.rs:9:27
+  |
+9 | fn f1<'a>(arg : Box<dyn X<'a = &'a ()>>) {}  
+  |                           ^^^^ expected the name of an associated type
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-3.rs:3:12
+  |
+3 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to previous error; 1 warning emitted
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-4.rs b/src/test/ui/generic-associated-types/parse/issue-67510-4.rs
new file mode 100644
index 0000000000000..fef5b286b8333
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-4.rs
@@ -0,0 +1,14 @@
+// Only accept lifetimes or types as generic arguments for associated types 
+// in trait paths
+
+#![feature(generic_associated_types)]
+
+trait X { 
+    type Y<'a>;
+}
+
+fn f1<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}  
+    //~^  ERROR: generic arguments of associated types must be lifetimes or types
+    //~^^ ERROR: wrong number of lifetime arguments: expected 1, found 0 
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-4.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-4.stderr
new file mode 100644
index 0000000000000..780a44a455059
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-4.stderr
@@ -0,0 +1,24 @@
+error: generic arguments of associated types must be lifetimes or types
+  --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-4.rs:10:27
+   |
+10 | fn f1<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}  
+   |                           ^
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-4.rs:4:12
+  |
+4 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0107]: wrong number of lifetime arguments: expected 1, found 0
+  --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-4.rs:10:27
+   |
+10 | fn f1<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}  
+   |                           ^^^^^^^^^^^^^ expected 1 lifetime argument
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-5.rs b/src/test/ui/generic-associated-types/parse/issue-67510-5.rs
new file mode 100644
index 0000000000000..778b68467cad7
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-5.rs
@@ -0,0 +1,12 @@
+// Test to ensure that the Constraint branch of the pattern match on AngleBracketedArg
+// in `get_assoc_type_with_generic_args` is unreachable
+#![feature(generic_associated_types)]
+
+trait X { 
+    type Y<'a>;
+}
+
+fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}  
+    //~^ ERROR: Expected the name of an associated type
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-5.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-5.stderr
new file mode 100644
index 0000000000000..e3ce57ee662c0
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-5.stderr
@@ -0,0 +1,16 @@
+error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-5.rs:9:33
+  |
+9 | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}  
+  |                                 ^ expected one of 7 possible tokens
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-5.rs:3:12
+  |
+3 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to previous error; 1 warning emitted
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-6.rs b/src/test/ui/generic-associated-types/parse/issue-67510-6.rs
new file mode 100644
index 0000000000000..8b9ce62da1528
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-6.rs
@@ -0,0 +1,16 @@
+// Parser shouldn't accept parenthesized generic arguments for associated types in
+// trait paths
+#![feature(generic_associated_types)]
+
+trait X { 
+    type Y<'a>;
+}
+
+fn f1<'a>(arg : Box<dyn X<Y('a) = &'a ()>>) {}  
+    //~^  ERROR: lifetime in trait object type must be followed by `+`
+    //~^^ ERROR: invalid use of parenthesized generic arguments, expected angle 
+    //           bracketed (`<...>`) generic arguments
+    //~^^^^ ERROR: wrong number of lifetime arguments: expected 1, found 0
+    
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-6.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-6.stderr
new file mode 100644
index 0000000000000..d24a1b2acc9f8
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/issue-67510-6.stderr
@@ -0,0 +1,30 @@
+error: lifetime in trait object type must be followed by `+`
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-6.rs:9:29
+  |
+9 | fn f1<'a>(arg : Box<dyn X<Y('a) = &'a ()>>) {}  
+  |                             ^^
+
+error: invalid use of parenthesized generic arguments, expected angle bracketed (`<...>`) generic arguments
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-6.rs:9:27
+  |
+9 | fn f1<'a>(arg : Box<dyn X<Y('a) = &'a ()>>) {}  
+  |                           ^^^^^
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-6.rs:3:12
+  |
+3 | #![feature(generic_associated_types)]
+  |            ^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(incomplete_features)]` on by default
+  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0107]: wrong number of lifetime arguments: expected 1, found 0
+ --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-6.rs:9:27
+  |
+9 | fn f1<'a>(arg : Box<dyn X<Y('a) = &'a ()>>) {}  
+  |                           ^^^^^^^^^^^^^^ expected 1 lifetime argument
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0107`.