about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkadmin <julianknodt@gmail.com>2022-01-13 07:39:58 +0000
committerkadmin <julianknodt@gmail.com>2022-01-17 20:01:22 +0000
commit1c1ce2fbda9c5d385fcb222d98d948aa4616fe91 (patch)
treecd857aabfa5104ae08da5c00114dbe6cddb765c2
parentf396888c4d816f7d0980aba041014169dd71a2a7 (diff)
Add term to ExistentialProjection
Also prevent ICE when adding a const in associated const equality.
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs5
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs12
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs5
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs38
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs8
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs10
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs7
-rw-r--r--compiler/rustc_parse/src/parser/path.rs5
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs4
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs11
-rw-r--r--compiler/rustc_typeck/src/variance/constraints.rs13
-rw-r--r--src/etc/check_missing_items.py4
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/test/ui/associated-consts/assoc-const.rs6
-rw-r--r--src/test/ui/associated-consts/assoc-const.stderr33
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs1
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr13
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013.rs1
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr13
-rw-r--r--src/test/ui/feature-gates/feature-gate-associated_const_equality.rs16
-rw-r--r--src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr18
-rw-r--r--src/test/ui/parser/recover-assoc-const-constraint.rs4
-rw-r--r--src/test/ui/parser/recover-assoc-const-constraint.stderr21
-rw-r--r--src/tools/rustfmt/src/types.rs2
35 files changed, 213 insertions, 71 deletions
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 0cc74a1ac0b..89671788255 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -724,6 +724,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
     gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
     gate_all!(inline_const, "inline-const is experimental");
     gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
+    gate_all!(associated_const_equality, "associated const equality is incomplete");
 
     // All uses of `gate_all!` below this point were added in #65742,
     // and subsequently disabled (with the non-early gating readded).
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 61322a6e556..9687fd09a53 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -203,8 +203,9 @@ fn push_debuginfo_type_name<'tcx>(
                 let projection_bounds: SmallVec<[_; 4]> = trait_data
                     .projection_bounds()
                     .map(|bound| {
-                        let ExistentialProjection { item_def_id, ty, .. } = bound.skip_binder();
-                        (item_def_id, ty)
+                        let ExistentialProjection { item_def_id, term, .. } = bound.skip_binder();
+                        // FIXME(associated_const_equality): allow for consts here
+                        (item_def_id, term.ty().unwrap())
                     })
                     .collect();
 
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index ebd12d6ab4e..47010ea3ab6 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -288,6 +288,8 @@ declare_features! (
     (active, asm_sym, "1.58.0", Some(72016), None),
     /// Allows the `may_unwind` option in inline assembly.
     (active, asm_unwind, "1.58.0", Some(72016), None),
+    /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
+    (active, associated_const_equality, "1.58.0", Some(92827), None),
     /// Allows the user of associated type bounds.
     (active, associated_type_bounds, "1.34.0", Some(52662), None),
     /// Allows associated type defaults.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index f1e99faba01..e98b9c3b03c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -69,7 +69,7 @@ use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{
     self,
     subst::{GenericArgKind, Subst, SubstsRef},
-    Region, Term, Ty, TyCtxt, TypeFoldable,
+    Region, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span};
 use rustc_target::spec::abi;
@@ -1780,11 +1780,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 {
                     if projection_predicate.projection_ty.item_def_id == item_def_id {
                         // We don't account for multiple `Future::Output = Ty` contraints.
-                        match projection_predicate.term {
-                            Term::Ty(ty) => return Some(ty),
-                            // Can return None, but not sure if that makes sense?
-                            Term::Const(_c) => todo!(),
-                        }
+                        return projection_predicate.term.ty();
                     }
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index ee00f6c62f3..b4c9cc7782c 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -4,7 +4,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::TyKind::*;
 use crate::ty::{
     ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
-    ProjectionTy, TyCtxt, TyS, TypeAndMut,
+    ProjectionTy, Term, TyCtxt, TyS, TypeAndMut,
 };
 
 use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -105,8 +105,14 @@ impl<'tcx> TyS<'tcx> {
                 ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
                     substs.iter().all(generic_arg_is_suggestible)
                 }
-                ExistentialPredicate::Projection(ExistentialProjection { substs, ty, .. }) => {
-                    ty.is_suggestable() && substs.iter().all(generic_arg_is_suggestible)
+                ExistentialPredicate::Projection(ExistentialProjection {
+                    substs, term, ..
+                }) => {
+                    let term_is_suggestable = match term {
+                        Term::Ty(ty) => ty.is_suggestable(),
+                        Term::Const(c) => const_is_suggestable(c.val),
+                    };
+                    term_is_suggestable && substs.iter().all(generic_arg_is_suggestible)
                 }
                 _ => true,
             }),
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index be9021dc619..f06a1b09cd8 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -320,7 +320,10 @@ impl FlagComputation {
 
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
         self.add_substs(projection.substs);
-        self.add_ty(projection.ty);
+        match projection.term {
+            ty::Term::Ty(ty) => self.add_ty(ty),
+            ty::Term::Const(ct) => self.add_const(ct),
+        }
     }
 
     fn add_projection_ty(&mut self, projection_ty: ty::ProjectionTy<'_>) {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 42e6f3f6ef5..4bc3e23f4a5 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -795,7 +795,7 @@ pub struct CoercePredicate<'tcx> {
 }
 pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub enum Term<'tcx> {
     Ty(Ty<'tcx>),
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index c6b03739927..bbdaf248a9e 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -905,29 +905,27 @@ pub trait PrettyPrinter<'tcx>:
                 }
 
                 for (assoc_item_def_id, term) in assoc_items {
-                    let ty = match term.skip_binder() {
-                        Term::Ty(ty) => ty,
-                        Term::Const(c) => {
-                            p!(print(c));
-                            continue;
-                        }
-                    };
                     if !first {
                         p!(", ");
                     }
                     p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
 
-                    // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
-                    match ty.kind() {
-                        ty::Projection(ty::ProjectionTy { item_def_id, .. })
-                            if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
-                        {
-                            p!("[async output]")
+                    match term.skip_binder() {
+                        Term::Ty(ty) => {
+                            // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
+                            if matches!(
+                              ty.kind(), ty::Projection(ty::ProjectionTy { item_def_id, .. })
+                              if Some(*item_def_id) == self.tcx().lang_items().generator_return()
+                            ) {
+                                p!("[async output]")
+                            } else {
+                                p!(print(ty))
+                            }
                         }
-                        _ => {
-                            p!(print(ty))
+                        Term::Const(c) => {
+                            p!(print(c));
                         }
-                    }
+                    };
 
                     first = false;
                 }
@@ -1031,7 +1029,11 @@ pub trait PrettyPrinter<'tcx>:
                         let mut projections = predicates.projection_bounds();
                         if let (Some(proj), None) = (projections.next(), projections.next()) {
                             let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect();
-                            p!(pretty_fn_sig(&tys, false, proj.skip_binder().ty));
+                            p!(pretty_fn_sig(
+                                &tys,
+                                false,
+                                proj.skip_binder().term.ty().expect("Return type was a const")
+                            ));
                             resugared = true;
                         }
                     }
@@ -2454,7 +2456,7 @@ define_print_and_forward_display! {
 
     ty::ExistentialProjection<'tcx> {
         let name = cx.tcx().associated_item(self.item_def_id).ident;
-        p!(write("{} = ", name), print(self.ty))
+        p!(write("{} = ", name), print(self.term))
     }
 
     ty::ExistentialPredicate<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index bd6c24445ef..bb040acd270 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -291,11 +291,11 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
                 b.item_def_id,
             )))
         } else {
-            let ty = relation.relate_with_variance(
+            let term = relation.relate_with_variance(
                 ty::Invariant,
                 ty::VarianceDiagInfo::default(),
-                a.ty,
-                b.ty,
+                a.term,
+                b.term,
             )?;
             let substs = relation.relate_with_variance(
                 ty::Invariant,
@@ -303,7 +303,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
                 a.substs,
                 b.substs,
             )?;
-            Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
+            Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, term })
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 3cbea92ae67..1c5bc7860db 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -423,7 +423,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> {
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         tcx.lift(self.substs).map(|substs| ty::ExistentialProjection {
             substs,
-            ty: tcx.lift(self.ty).expect("type must lift when substs do"),
+            term: tcx.lift(self.term).expect("type must lift when substs do"),
             item_def_id: self.item_def_id,
         })
     }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index ffc339f3588..20db25f7899 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1540,7 +1540,7 @@ impl From<BoundVar> for BoundTy {
 pub struct ExistentialProjection<'tcx> {
     pub item_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
-    pub ty: Ty<'tcx>,
+    pub term: Term<'tcx>,
 }
 
 pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>;
@@ -1570,7 +1570,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
                 item_def_id: self.item_def_id,
                 substs: tcx.mk_substs_trait(self_ty, self.substs),
             },
-            term: self.ty.into(),
+            term: self.term,
         }
     }
 
@@ -1580,15 +1580,11 @@ impl<'tcx> ExistentialProjection<'tcx> {
     ) -> Self {
         // Assert there is a Self.
         projection_predicate.projection_ty.substs.type_at(0);
-        let ty = match projection_predicate.term {
-            Term::Ty(ty) => ty,
-            Term::Const(_c) => unimplemented!(),
-        };
 
         Self {
             item_def_id: projection_predicate.projection_ty.item_def_id,
             substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
-            ty,
+            term: projection_predicate.term,
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 6808316a230..38aa7633385 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -157,7 +157,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
                 stack.extend(obj.iter().rev().flat_map(|predicate| {
                     let (substs, opt_ty) = match predicate.skip_binder() {
                         ty::ExistentialPredicate::Trait(tr) => (tr.substs, None),
-                        ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)),
+                        ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.term)),
                         ty::ExistentialPredicate::AutoTrait(_) =>
                         // Empty iterator
                         {
@@ -165,7 +165,10 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
                         }
                     };
 
-                    substs.iter().rev().chain(opt_ty.map(|ty| ty.into()))
+                    substs.iter().rev().chain(opt_ty.map(|term| match term {
+                        ty::Term::Ty(ty) => ty.into(),
+                        ty::Term::Const(ct) => ct.into(),
+                    }))
                 }));
             }
             ty::Adt(_, substs)
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 531cac1f57e..4e60b7593c6 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -505,7 +505,10 @@ impl<'a> Parser<'a> {
         let span = ident.span.to(self.prev_token.span);
         let term = match arg {
             Some(GenericArg::Type(ty)) => ty.into(),
-            Some(GenericArg::Const(c)) => c.into(),
+            Some(GenericArg::Const(c)) => {
+                self.sess.gated_spans.gate(sym::associated_const_equality, span);
+                c.into()
+            }
             Some(GenericArg::Lifetime(lt)) => {
                 self.struct_span_err(span, "associated lifetimes are not supported")
                     .span_label(lt.ident.span, "the lifetime is given here")
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8020893e166..2ff888bfb48 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -343,6 +343,7 @@ symbols! {
         assert_receiver_is_total_eq,
         assert_uninit_valid,
         assert_zero_valid,
+        associated_const_equality,
         associated_consts,
         associated_type_bounds,
         associated_type_defaults,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 14e12bed59e..809b9732529 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -559,7 +559,10 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
                         let name = cx.tcx.associated_item(projection.item_def_id).ident;
                         cx.push("p");
                         cx.push_ident(name.as_str());
-                        cx = projection.ty.print(cx)?;
+                        cx = match projection.term {
+                            ty::Term::Ty(ty) => ty.print(cx),
+                            ty::Term::Const(c) => c.print(cx),
+                        }?;
                     }
                     ty::ExistentialPredicate::AutoTrait(def_id) => {
                         cx = cx.print_def_path(*def_id, &[])?;
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 8a33d26fa86..e2afea76b77 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -756,8 +756,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                             // when we started out trying to unify
                             // some inference variables. See the comment above
                             // for more infomration
-                            if p.term().skip_binder().ty().map_or(false, |ty| ty.has_infer_types())
-                            {
+                            if p.term().skip_binder().ty().has_infer_types() {
                                 if !self.evaluate_nested_obligations(
                                     ty,
                                     v.into_iter(),
@@ -779,7 +778,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                             // However, we should always make progress (either by generating
                             // subobligations or getting an error) when we started off with
                             // inference variables
-                            if p.term().skip_binder().ty().has_infer_types() {
+                            if p.term().skip_binder().has_infer_types() {
                                 panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
                             }
                         }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 43a961c5c91..65385851d05 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1314,7 +1314,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                         | ObligationCauseCode::ObjectCastObligation(_)
                         | ObligationCauseCode::OpaqueType
                 );
-                // FIXME(...): Handle Consts here
+                // FIXME(associated_const_equality): Handle Consts here
                 let data_ty = data.term.ty().unwrap();
                 if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
                     is_normalized_ty_expected,
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 185d64eab70..7bfedecbdc7 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -571,7 +571,7 @@ fn object_ty_for_trait<'tcx>(
         // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
         super_trait_ref.map_bound(|super_trait_ref| {
             ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
-                ty: tcx.mk_projection(item.def_id, super_trait_ref.substs),
+                term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
                 item_def_id: item.def_id,
                 substs: super_trait_ref.substs,
             })
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 4b53b624c72..2bbdb72a4fb 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -212,7 +212,7 @@ fn project_and_unify_type<'cx, 'tcx>(
     debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
 
     let infcx = selcx.infcx();
-    // FIXME(...): Handle consts here as well as types.
+    // FIXME(associated_const_equality): Handle consts here as well as types.
     let obligation_pred_ty = obligation.predicate.term.ty().unwrap();
     match infcx.at(&obligation.cause, obligation.param_env).eq(normalized_ty, obligation_pred_ty) {
         Ok(InferOk { obligations: inferred_obligations, value: () }) => {
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index dd98e4ae81b..67d0ba39667 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -226,6 +226,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>>
     for rustc_middle::ty::ProjectionPredicate<'tcx>
 {
     fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> {
+        // FIXME(associated_const_equality): teach chalk about terms for alias eq.
         chalk_ir::AliasEq {
             ty: self.term.ty().unwrap().lower_into(interner),
             alias: self.projection_ty.lower_into(interner),
@@ -663,7 +664,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
                                 .mk_substs_trait(self_ty, predicate.substs)
                                 .lower_into(interner),
                         }),
-                        ty: predicate.ty.lower_into(interner),
+                        // FIXME(associated_const_equality): teach chalk about terms for alias eq.
+                        ty: predicate.term.ty().unwrap().lower_into(interner),
                     }),
                 ),
                 ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index a13eaa6f178..a1f1adb8058 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1136,9 +1136,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .associated_items(candidate.def_id())
             .filter_by_name_unhygienic(assoc_ident.name)
             .find(|i| {
-                i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident
+                (i.kind == ty::AssocKind::Type || i.kind == ty::AssocKind::Const)
+                    && i.ident.normalize_to_macros_2_0() == assoc_ident
             })
             .expect("missing associated type");
+        // FIXME(associated_const_equality): need to handle assoc_consts here as well.
+        if assoc_ty.kind == ty::AssocKind::Const {
+            tcx.sess
+                .struct_span_err(path_span, &format!("associated const equality is incomplete"))
+                .span_label(path_span, "cannot yet relate associated const")
+                .emit();
+            return Err(ErrorReported);
+        }
 
         if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
             tcx.sess
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index b2b607a2ffc..7c504a0d89c 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -308,11 +308,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 }
 
                 for projection in data.projection_bounds() {
-                    self.add_constraints_from_ty(
-                        current,
-                        projection.skip_binder().ty,
-                        self.invariant,
-                    );
+                    match projection.skip_binder().term {
+                        ty::Term::Ty(ty) => {
+                            self.add_constraints_from_ty(current, ty, self.invariant);
+                        }
+                        ty::Term::Const(c) => {
+                            self.add_constraints_from_const(current, c, self.invariant)
+                        }
+                    }
                 }
             }
 
diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py
index 7ed317c778f..de1717b3f3f 100644
--- a/src/etc/check_missing_items.py
+++ b/src/etc/check_missing_items.py
@@ -83,7 +83,9 @@ def check_type(ty):
                         check_type(arg["const"]["type"])
                 for binding in args["angle_bracketed"]["bindings"]:
                     if "equality" in binding["binding"]:
-                        check_type(binding["binding"]["equality"])
+                        term = binding["binding"]["equality"]
+                        if "type" in term: check_type(term["type"])
+                        elif "const" in term: check_type(term["const"])
                     elif "constraint" in binding["binding"]:
                         for bound in binding["binding"]["constraint"]:
                             check_generic_bound(bound)
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 6a3cdcc2c20..e759baa0458 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1523,7 +1523,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     bindings.push(TypeBinding {
                         name: cx.tcx.associated_item(pb.item_def_id()).ident.name,
                         kind: TypeBindingKind::Equality {
-                            term: pb.skip_binder().ty.clean(cx).into(),
+                            term: pb.skip_binder().term.clean(cx).into(),
                         },
                     });
                 }
diff --git a/src/test/ui/associated-consts/assoc-const.rs b/src/test/ui/associated-consts/assoc-const.rs
index 582d0a69229..9e6bfa346ec 100644
--- a/src/test/ui/associated-consts/assoc-const.rs
+++ b/src/test/ui/associated-consts/assoc-const.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 pub trait Foo {
   const N: usize;
 }
@@ -14,6 +12,10 @@ const TEST:usize = 3;
 
 
 fn foo<F: Foo<N=3>>() {}
+//~^ ERROR associated const equality is incomplete
+//~| ERROR associated const equality is incomplete
 fn bar<F: Foo<N={TEST}>>() {}
+//~^ ERROR associated const equality is incomplete
+//~| ERROR associated const equality is incomplete
 
 fn main() {}
diff --git a/src/test/ui/associated-consts/assoc-const.stderr b/src/test/ui/associated-consts/assoc-const.stderr
new file mode 100644
index 00000000000..07da190bc8f
--- /dev/null
+++ b/src/test/ui/associated-consts/assoc-const.stderr
@@ -0,0 +1,33 @@
+error[E0658]: associated const equality is incomplete
+  --> $DIR/assoc-const.rs:14:15
+   |
+LL | fn foo<F: Foo<N=3>>() {}
+   |               ^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0658]: associated const equality is incomplete
+  --> $DIR/assoc-const.rs:17:15
+   |
+LL | fn bar<F: Foo<N={TEST}>>() {}
+   |               ^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error: associated const equality is incomplete
+  --> $DIR/assoc-const.rs:14:15
+   |
+LL | fn foo<F: Foo<N=3>>() {}
+   |               ^^^ cannot yet relate associated const
+
+error: associated const equality is incomplete
+  --> $DIR/assoc-const.rs:17:15
+   |
+LL | fn bar<F: Foo<N={TEST}>>() {}
+   |               ^^^^^^^^ cannot yet relate associated const
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
index 32b08fb97f2..b126b24853f 100644
--- a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
@@ -9,6 +9,7 @@ const T: usize = 42;
 impl Foo<N = 3> for Bar {
 //~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied
 //~| ERROR associated type bindings are not allowed here
+//~| ERROR associated const equality is incomplete
     fn do_x(&self) -> [u8; 3] {
         [0u8; 3]
     }
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
index 455f6f61aad..59ba054aa11 100644
--- a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
@@ -1,3 +1,12 @@
+error[E0658]: associated const equality is incomplete
+  --> $DIR/issue-89013-no-kw.rs:9:10
+   |
+LL | impl Foo<N = 3> for Bar {
+   |          ^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/issue-89013-no-kw.rs:9:6
    |
@@ -20,7 +29,7 @@ error[E0229]: associated type bindings are not allowed here
 LL | impl Foo<N = 3> for Bar {
    |          ^^^^^ associated type not allowed here
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0107, E0229.
+Some errors have detailed explanations: E0107, E0229, E0658.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs
index 97c22fa7862..9431779faf8 100644
--- a/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs
@@ -10,6 +10,7 @@ impl Foo<N = const 3> for Bar {
 //~^ ERROR expected lifetime, type, or constant, found keyword `const`
 //~| ERROR this trait takes 1 generic
 //~| ERROR associated type bindings are not allowed here
+//~| ERROR associated const equality is incomplete
     fn do_x(&self) -> [u8; 3] {
         [0u8; 3]
     }
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr
index 57108d718cf..9d473992670 100644
--- a/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr
@@ -10,6 +10,15 @@ LL - impl Foo<N = const 3> for Bar {
 LL + impl Foo<N = 3> for Bar {
    | 
 
+error[E0658]: associated const equality is incomplete
+  --> $DIR/issue-89013.rs:9:10
+   |
+LL | impl Foo<N = const 3> for Bar {
+   |          ^^^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/issue-89013.rs:9:6
    |
@@ -32,7 +41,7 @@ error[E0229]: associated type bindings are not allowed here
 LL | impl Foo<N = const 3> for Bar {
    |          ^^^^^^^^^^^ associated type not allowed here
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0107, E0229.
+Some errors have detailed explanations: E0107, E0229, E0658.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/feature-gates/feature-gate-associated_const_equality.rs b/src/test/ui/feature-gates/feature-gate-associated_const_equality.rs
new file mode 100644
index 00000000000..b51ead2a188
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-associated_const_equality.rs
@@ -0,0 +1,16 @@
+pub trait TraitWAssocConst {
+  const A: usize;
+}
+pub struct Demo {}
+
+impl TraitWAssocConst for Demo {
+  const A: usize = 32;
+}
+
+fn foo<A: TraitWAssocConst<A=32>>() {}
+//~^ ERROR associated const equality
+//~| ERROR associated const equality
+
+fn main() {
+  foo::<Demo>();
+}
diff --git a/src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr b/src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr
new file mode 100644
index 00000000000..f4db49c4af8
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr
@@ -0,0 +1,18 @@
+error[E0658]: associated const equality is incomplete
+  --> $DIR/feature-gate-associated_const_equality.rs:10:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {}
+   |                            ^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error: associated const equality is incomplete
+  --> $DIR/feature-gate-associated_const_equality.rs:10:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {}
+   |                            ^^^^ cannot yet relate associated const
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/parser/recover-assoc-const-constraint.rs b/src/test/ui/parser/recover-assoc-const-constraint.rs
index 3f7423dcb8e..1453e6cb5cd 100644
--- a/src/test/ui/parser/recover-assoc-const-constraint.rs
+++ b/src/test/ui/parser/recover-assoc-const-constraint.rs
@@ -1,9 +1,9 @@
-// run-pass
-
 #[cfg(FALSE)]
 fn syntax() {
     bar::<Item = 42>();
+    //~^ ERROR associated const equality is incomplete
     bar::<Item = { 42 }>();
+    //~^ ERROR associated const equality is incomplete
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/recover-assoc-const-constraint.stderr b/src/test/ui/parser/recover-assoc-const-constraint.stderr
new file mode 100644
index 00000000000..2d36ce4e986
--- /dev/null
+++ b/src/test/ui/parser/recover-assoc-const-constraint.stderr
@@ -0,0 +1,21 @@
+error[E0658]: associated const equality is incomplete
+  --> $DIR/recover-assoc-const-constraint.rs:3:11
+   |
+LL |     bar::<Item = 42>();
+   |           ^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0658]: associated const equality is incomplete
+  --> $DIR/recover-assoc-const-constraint.rs:5:11
+   |
+LL |     bar::<Item = { 42 }>();
+   |           ^^^^^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 9d5f790e809..5de30129266 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -211,7 +211,7 @@ impl Rewrite for ast::AssocConstraintKind {
         match self {
             ast::AssocConstraintKind::Equality { term } => match term {
                 Term::Ty(ty) => ty.rewrite(context, shape),
-                Term::Const(c) => c.rewrite(context,shape),
+                Term::Const(c) => c.rewrite(context, shape),
             },
             ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
         }