about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs14
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs19
-rw-r--r--compiler/rustc_ast/src/visit.rs18
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs9
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs15
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs8
-rw-r--r--compiler/rustc_ast_passes/src/node_count.rs4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs10
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/intravisit.rs5
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs4
-rw-r--r--compiler/rustc_interface/src/util.rs5
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs19
-rw-r--r--compiler/rustc_parse/src/parser/path.rs37
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs6
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs17
-rw-r--r--compiler/rustc_typeck/src/bounds.rs69
-rw-r--r--compiler/rustc_typeck/src/collect.rs2
-rw-r--r--compiler/rustc_typeck/src/collect/item_bounds.rs6
19 files changed, 167 insertions, 102 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 079b9e43373..9d447f3b5cb 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -224,7 +224,7 @@ pub enum AngleBracketedArg {
     /// Argument for a generic parameter.
     Arg(GenericArg),
     /// Constraint for an associated item.
-    Constraint(AssocTyConstraint),
+    Constraint(AssocConstraint),
 }
 
 impl AngleBracketedArg {
@@ -1843,19 +1843,21 @@ impl UintTy {
 /// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
 /// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
 #[derive(Clone, Encodable, Decodable, Debug)]
-pub struct AssocTyConstraint {
+pub struct AssocConstraint {
     pub id: NodeId,
     pub ident: Ident,
     pub gen_args: Option<GenericArgs>,
-    pub kind: AssocTyConstraintKind,
+    pub kind: AssocConstraintKind,
     pub span: Span,
 }
 
-/// The kinds of an `AssocTyConstraint`.
+/// The kinds of an `AssocConstraint`.
 #[derive(Clone, Encodable, Decodable, Debug)]
-pub enum AssocTyConstraintKind {
-    /// E.g., `A = Bar` in `Foo<A = Bar>`.
+pub enum AssocConstraintKind {
+    /// E.g., `A = Bar` in `Foo<A = Bar>` where A is an associated type.
     Equality { ty: P<Ty> },
+    /// E.g., `A = 3` in `Foo<N = 3>` where N is an associated const.
+    ConstEquality { c: AnonConst },
     /// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
     Bound { bounds: GenericBounds },
 }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 564a8a8c872..ba68ff691ca 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -165,8 +165,8 @@ pub trait MutVisitor: Sized {
         noop_visit_lifetime(l, self);
     }
 
-    fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
-        noop_visit_ty_constraint(t, self);
+    fn visit_constraint(&mut self, t: &mut AssocConstraint) {
+        noop_visit_constraint(t, self);
     }
 
     fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
@@ -430,8 +430,8 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
     smallvec![arm]
 }
 
-pub fn noop_visit_ty_constraint<T: MutVisitor>(
-    AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
+pub fn noop_visit_constraint<T: MutVisitor>(
+    AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint,
     vis: &mut T,
 ) {
     vis.visit_id(id);
@@ -440,12 +440,9 @@ pub fn noop_visit_ty_constraint<T: MutVisitor>(
         vis.visit_generic_args(gen_args);
     }
     match kind {
-        AssocTyConstraintKind::Equality { ref mut ty } => {
-            vis.visit_ty(ty);
-        }
-        AssocTyConstraintKind::Bound { ref mut bounds } => {
-            visit_bounds(bounds, vis);
-        }
+        AssocConstraintKind::Equality { ref mut ty } => vis.visit_ty(ty),
+        AssocConstraintKind::ConstEquality { ref mut c } => vis.visit_anon_const(c),
+        AssocConstraintKind::Bound { ref mut bounds } => visit_bounds(bounds, vis),
     }
     vis.visit_span(span);
 }
@@ -555,7 +552,7 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
     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),
+        AngleBracketedArg::Constraint(constraint) => vis.visit_constraint(constraint),
     });
     vis.visit_span(span);
 }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 0b95270a4e1..f054f4de2f9 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -190,8 +190,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
         walk_generic_arg(self, generic_arg)
     }
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
-        walk_assoc_ty_constraint(self, constraint)
+    fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
+        walk_assoc_constraint(self, constraint)
     }
     fn visit_attribute(&mut self, attr: &'ast Attribute) {
         walk_attribute(self, attr)
@@ -464,7 +464,7 @@ where
             for arg in &data.args {
                 match arg {
                     AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a),
-                    AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c),
+                    AngleBracketedArg::Constraint(c) => visitor.visit_assoc_constraint(c),
                 }
             }
         }
@@ -486,19 +486,15 @@ where
     }
 }
 
-pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    constraint: &'a AssocTyConstraint,
-) {
+pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) {
     visitor.visit_ident(constraint.ident);
     if let Some(ref gen_args) = constraint.gen_args {
         visitor.visit_generic_args(gen_args.span(), gen_args);
     }
     match constraint.kind {
-        AssocTyConstraintKind::Equality { ref ty } => {
-            visitor.visit_ty(ty);
-        }
-        AssocTyConstraintKind::Bound { ref bounds } => {
+        AssocConstraintKind::Equality { ref ty } => visitor.visit_ty(ty),
+        AssocConstraintKind::ConstEquality { ref c } => visitor.visit_anon_const(c),
+        AssocConstraintKind::Bound { ref bounds } => {
             walk_list!(visitor, visit_param_bound, bounds);
         }
     }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 35eb716949a..450f4238584 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -960,7 +960,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// returns a `hir::TypeBinding` representing `Item`.
     fn lower_assoc_ty_constraint(
         &mut self,
-        constraint: &AssocTyConstraint,
+        constraint: &AssocConstraint,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
@@ -997,10 +997,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         };
 
         let kind = match constraint.kind {
-            AssocTyConstraintKind::Equality { ref ty } => {
+            AssocConstraintKind::Equality { ref ty } => {
                 hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }
             }
-            AssocTyConstraintKind::Bound { ref bounds } => {
+            AssocConstraintKind::ConstEquality { ref c } => {
+                hir::TypeBindingKind::Const { c: self.lower_anon_const(c) }
+            }
+            AssocConstraintKind::Bound { ref bounds } => {
                 let mut capturable_lifetimes;
                 let mut parent_def_id = self.current_hir_id_owner;
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 45920bb27d5..2c575cfdbdc 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -138,10 +138,11 @@ impl<'a> AstValidator<'a> {
         self.outer_impl_trait = old;
     }
 
-    fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
+    fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
         match constraint.kind {
-            AssocTyConstraintKind::Equality { .. } => {}
-            AssocTyConstraintKind::Bound { .. } => {
+            AssocConstraintKind::Equality { .. } => {}
+            AssocConstraintKind::ConstEquality { .. } => {}
+            AssocConstraintKind::Bound { .. } => {
                 if self.is_assoc_ty_bound_banned {
                     self.err_handler().span_err(
                         constraint.span,
@@ -150,7 +151,7 @@ impl<'a> AstValidator<'a> {
                 }
             }
         }
-        self.visit_assoc_ty_constraint(constraint);
+        self.visit_assoc_constraint(constraint);
     }
 
     // Mirrors `visit::walk_ty`, but tracks relevant state.
@@ -1277,7 +1278,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         // 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);
+                                this.visit_assoc_constraint_from_generic_args(constraint);
                             });
                         }
                     }
@@ -1586,11 +1587,11 @@ fn deny_equality_constraints(
                                     let len = assoc_path.segments.len() - 1;
                                     let gen_args = args.as_ref().map(|p| (**p).clone());
                                     // Build `<Bar = RhsTy>`.
-                                    let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
+                                    let arg = AngleBracketedArg::Constraint(AssocConstraint {
                                         id: rustc_ast::node_id::DUMMY_NODE_ID,
                                         ident: *ident,
                                         gen_args,
-                                        kind: AssocTyConstraintKind::Equality {
+                                        kind: AssocConstraintKind::Equality {
                                             ty: predicate.rhs_ty.clone(),
                                         },
                                         span: ident.span,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 85e35c942b9..0cc74a1ac0b 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,6 +1,6 @@
 use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
+use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
 use rustc_ast::{PatKind, RangeEnd, VariantData};
 use rustc_errors::struct_span_err;
 use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@@ -622,8 +622,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_fn(self, fn_kind, span)
     }
 
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
-        if let AssocTyConstraintKind::Bound { .. } = constraint.kind {
+    fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
+        if let AssocConstraintKind::Bound { .. } = constraint.kind {
             gate_feature_post!(
                 &self,
                 associated_type_bounds,
@@ -631,7 +631,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 "associated type bounds are unstable"
             )
         }
-        visit::walk_assoc_ty_constraint(self, constraint)
+        visit::walk_assoc_constraint(self, constraint)
     }
 
     fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
index 3980e6da682..a4a48cc8e8a 100644
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ b/compiler/rustc_ast_passes/src/node_count.rs
@@ -126,9 +126,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_generic_args(self, path_span, generic_args)
     }
-    fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) {
+    fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) {
         self.count += 1;
-        walk_assoc_ty_constraint(self, constraint)
+        walk_assoc_constraint(self, constraint)
     }
     fn visit_attribute(&mut self, _attr: &Attribute) {
         self.count += 1;
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index dab2e1f5ee1..38186024467 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -952,16 +952,20 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
+    pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
         self.print_ident(constraint.ident);
         constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
         self.space();
         match &constraint.kind {
-            ast::AssocTyConstraintKind::Equality { ty } => {
+            ast::AssocConstraintKind::Equality { ty } => {
                 self.word_space("=");
                 self.print_type(ty);
             }
-            ast::AssocTyConstraintKind::Bound { bounds } => {
+            ast::AssocConstraintKind::ConstEquality { c } => {
+                self.word_space("=");
+                self.print_expr_anon_const(c);
+            }
+            ast::AssocConstraintKind::Bound { bounds } => {
                 self.print_type_bounds(":", &*bounds);
             }
         }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 369b5e6da2d..039bb0db0aa 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2136,6 +2136,8 @@ pub enum TypeBindingKind<'hir> {
     Constraint { bounds: &'hir [GenericBound<'hir>] },
     /// E.g., `Foo<Bar = ()>`.
     Equality { ty: &'hir Ty<'hir> },
+    /// E.g., `Foo<N = 3>`.
+    Const { c: AnonConst },
 }
 
 impl TypeBinding<'_> {
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 52c0538f1bc..56b32cde9d5 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -827,9 +827,8 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
     visitor.visit_ident(type_binding.ident);
     visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
     match type_binding.kind {
-        TypeBindingKind::Equality { ref ty } => {
-            visitor.visit_ty(ty);
-        }
+        TypeBindingKind::Equality { ref ty } => visitor.visit_ty(ty),
+        TypeBindingKind::Const { ref c } => visitor.visit_anon_const(c),
         TypeBindingKind::Constraint { bounds } => {
             walk_list!(visitor, visit_param_bound, bounds);
         }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 7675778ff88..a76af35a8e6 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1756,6 +1756,10 @@ impl<'a> State<'a> {
                         self.word_space("=");
                         self.print_type(ty);
                     }
+                    hir::TypeBindingKind::Const { ref c } => {
+                        self.word_space("=");
+                        self.print_anon_const(c);
+                    }
                     hir::TypeBindingKind::Constraint { bounds } => {
                         self.print_bounds(":", bounds);
                     }
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index cb51555f5ca..abecc8d1a8b 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -738,8 +738,9 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
                                         | ast::GenericArg::Const(_) => false,
                                     },
                                     ast::AngleBracketedArg::Constraint(c) => match c.kind {
-                                        ast::AssocTyConstraintKind::Bound { .. } => true,
-                                        ast::AssocTyConstraintKind::Equality { ref ty } => {
+                                        ast::AssocConstraintKind::Bound { .. } => true,
+                                        ast::AssocConstraintKind::ConstEquality { .. } => false,
+                                        ast::AssocConstraintKind::Equality { ref ty } => {
                                             involves_impl_trait(ty)
                                         }
                                     },
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index d6e89e52b95..9e7e8dc838a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -814,6 +814,25 @@ pub struct ProjectionPredicate<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
+/// This kind of predicate has no *direct* correspondent in the
+/// syntax, but it roughly corresponds to the syntactic forms:
+///
+/// 1. `T: TraitRef<..., Item = Const>`
+/// 2. `<T as TraitRef<...>>::Item == Const` (NYI)
+///
+/// In particular, form #1 is "desugared" to the combination of a
+/// normal trait predicate (`T: TraitRef<...>`) and one of these
+/// predicates. Form #2 is a broader form in that it also permits
+/// equality between arbitrary types. Processing an instance of
+/// Form #2 eventually yields one of these `ProjectionPredicate`
+/// instances to normalize the LHS.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
+#[derive(HashStable, TypeFoldable)]
+pub struct ConstPredicate<'tcx> {
+    pub projection: ProjectionTy<'tcx>,
+    pub c: &'tcx Const<'tcx>,
+}
+
 pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
 
 impl<'tcx> PolyProjectionPredicate<'tcx> {
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 7f8fadb33bd..7c2d8ba21a2 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -4,8 +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, AnonConst, AssocTyConstraint,
-    AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
+    self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint,
+    AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
     Path, PathSegment, QSelf,
 };
 use rustc_errors::{pluralize, Applicability, PResult};
@@ -469,12 +469,9 @@ impl<'a> Parser<'a> {
                         // Parse associated type constraint bound.
 
                         let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
-                        AssocTyConstraintKind::Bound { bounds }
+                        AssocConstraintKind::Bound { bounds }
                     } else if self.eat(&token::Eq) {
-                        // Parse associated type equality constraint
-
-                        let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
-                        AssocTyConstraintKind::Equality { ty }
+                        self.parse_assoc_equality_term(ident, self.prev_token.span)?
                     } else {
                         unreachable!();
                     };
@@ -482,11 +479,11 @@ impl<'a> Parser<'a> {
                     let span = lo.to(self.prev_token.span);
 
                     // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
-                    if let AssocTyConstraintKind::Bound { .. } = kind {
+                    if let AssocConstraintKind::Bound { .. } = kind {
                         self.sess.gated_spans.gate(sym::associated_type_bounds, span);
                     }
                     let constraint =
-                        AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
+                        AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
                     Ok(Some(AngleBracketedArg::Constraint(constraint)))
                 } else {
                     Ok(Some(AngleBracketedArg::Arg(arg)))
@@ -499,22 +496,22 @@ impl<'a> Parser<'a> {
     /// 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: Ident,
+        eq: Span,
+    ) -> PResult<'a, AssocConstraintKind> {
         let arg = self.parse_generic_arg(None)?;
         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();
-            }
+        let ty = match arg {
+            Some(GenericArg::Type(ty)) => ty,
+            Some(GenericArg::Const(c)) => return Ok(AssocConstraintKind::ConstEquality { c }),
             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();
+                self.mk_ty(span, ast::TyKind::Err)
             }
             None => {
                 let after_eq = eq.shrink_to_hi();
@@ -542,8 +539,8 @@ impl<'a> Parser<'a> {
                 };
                 return Err(err);
             }
-        }
-        Ok(self.mk_ty(span, ast::TyKind::Err))
+        };
+        Ok(AssocConstraintKind::Equality { ty })
     }
 
     /// We do not permit arbitrary expressions as const arguments. They must be one of:
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index d665c12f762..963a625aaea 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -338,9 +338,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
         ast_visit::walk_path_segment(self, path_span, path_segment)
     }
 
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) {
-        self.record("AssocTyConstraint", Id::None, constraint);
-        ast_visit::walk_assoc_ty_constraint(self, constraint)
+    fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
+        self.record("AssocConstraint", Id::None, constraint);
+        ast_visit::walk_assoc_constraint(self, constraint)
     }
 
     fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 2ada1c0ddf4..2d847f6145d 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -124,6 +124,7 @@ struct ConvertedBinding<'a, 'tcx> {
 #[derive(Debug)]
 enum ConvertedBindingKind<'a, 'tcx> {
     Equality(Ty<'tcx>),
+    Const(&'tcx Const<'tcx>),
     Constraint(&'a [hir::GenericBound<'a>]),
 }
 
@@ -604,7 +605,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     hir::TypeBindingKind::Equality { ty } => {
                         ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
                     }
-                    hir::TypeBindingKind::Constraint { bounds } => {
+                    hir::TypeBindingKind::Const { ref c } => {
+                        let local_did = self.tcx().hir().local_def_id(c.hir_id);
+                        let c = Const::from_anon_const(self.tcx(), local_did);
+                        ConvertedBindingKind::Const(&c)
+                    }
+                    hir::TypeBindingKind::Constraint { ref bounds } => {
                         ConvertedBindingKind::Constraint(bounds)
                     }
                 };
@@ -1231,6 +1237,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     binding.span,
                 ));
             }
+            ConvertedBindingKind::Const(c) => {
+                bounds.const_bounds.push((
+                    projection_ty.map_bound(|projection_ty| ty::ConstPredicate {
+                        projection: projection_ty,
+                        c,
+                    }),
+                    binding.span,
+                ));
+            }
             ConvertedBindingKind::Constraint(ast_bounds) => {
                 // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
                 //
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs
index 8bc3a48e5b5..47c3ea54575 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_typeck/src/bounds.rs
@@ -37,6 +37,12 @@ pub struct Bounds<'tcx> {
     /// here.
     pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
 
+    /// A list of const equality bounds. So if you had `T:
+    /// Iterator<N = 4>` this would include `<T as
+    /// Iterator>::N => 4`. Note that the self-type is explicit
+    /// here.
+    pub const_bounds: Vec<(ty::Binder<'tcx, ty::ConstPredicate<'tcx>>, Span)>,
+
     /// `Some` if there is *no* `?Sized` predicate. The `span`
     /// is the location in the source of the `T` declaration which can
     /// be cited as the source of the `T: Sized` requirement.
@@ -48,14 +54,19 @@ impl<'tcx> Bounds<'tcx> {
     /// where-clauses). Because some of our bounds listings (e.g.,
     /// regions) don't include the self-type, you must supply the
     /// self-type here (the `param_ty` parameter).
-    pub fn predicates(
-        &self,
+    pub fn predicates<'out, 's>(
+        &'s self,
         tcx: TyCtxt<'tcx>,
         param_ty: Ty<'tcx>,
-    ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+        // the output must live shorter than the duration of the borrow of self and 'tcx.
+    ) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
+    where
+        'tcx: 'out,
+        's: 'out,
+    {
         // If it could be sized, and is, add the `Sized` predicate.
         let sized_predicate = self.implicitly_sized.and_then(|span| {
-            tcx.lang_items().sized_trait().map(|sized| {
+            tcx.lang_items().sized_trait().map(move |sized| {
                 let trait_ref = ty::Binder::dummy(ty::TraitRef {
                     def_id: sized,
                     substs: tcx.mk_substs_trait(param_ty, &[]),
@@ -64,25 +75,39 @@ impl<'tcx> Bounds<'tcx> {
             })
         });
 
-        sized_predicate
-            .into_iter()
-            .chain(self.region_bounds.iter().map(|&(region_bound, span)| {
-                (
-                    region_bound
-                        .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
-                        .to_predicate(tcx),
-                    span,
-                )
-            }))
-            .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
+        let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
+            let pred = region_bound
+                .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
+                .to_predicate(tcx);
+            (pred, span)
+        });
+        let trait_bounds =
+            self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
                 let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
                 (predicate, span)
-            }))
-            .chain(
-                self.projection_bounds
-                    .iter()
-                    .map(|&(projection, span)| (projection.to_predicate(tcx), span)),
-            )
-            .collect()
+            });
+        let projection_bounds = self
+            .projection_bounds
+            .iter()
+            .map(move |&(projection, span)| (projection.to_predicate(tcx), span));
+        let const_bounds = self.const_bounds.iter().map(move |&(bound, span)| {
+            // FIXME(...): what about the projection's generics?
+            // Is this the right local defid? Or should I get the self ty then
+            let pred = bound
+                .map_bound(|cp| {
+                    let got =
+                        ty::Const::from_anon_const(tcx, cp.projection.item_def_id.expect_local());
+                    ty::PredicateKind::ConstEquate(cp.c, got)
+                })
+                .to_predicate(tcx);
+            (pred, span)
+        });
+
+        sized_predicate
+            .into_iter()
+            .chain(region_preds)
+            .chain(trait_bounds)
+            .chain(projection_bounds)
+            .chain(const_bounds)
     }
 }
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index fbb630004ca..7cb100a0a83 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -2450,7 +2450,7 @@ fn predicates_from_bound<'tcx>(
 ) -> Vec<(ty::Predicate<'tcx>, Span)> {
     let mut bounds = Bounds::default();
     astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
-    bounds.predicates(astconv.tcx(), param_ty)
+    bounds.predicates(astconv.tcx(), param_ty).collect()
 }
 
 fn compute_sig_of_foreign_fn_decl<'tcx>(
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index 26cad8fb180..6d992629a00 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -67,11 +67,11 @@ fn opaque_type_bounds<'tcx>(
         let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
         <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
-        let bounds = bounds.predicates(tcx, item_ty);
+        let preds = bounds.predicates(tcx, item_ty);
 
+        let bounds = tcx.arena.alloc_from_iter(preds);
         debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
-
-        tcx.arena.alloc_slice(&bounds)
+        bounds
     })
 }