From e7529d6a3867ed1692818702b40814ee992eba2d Mon Sep 17 00:00:00 2001
From: kadmin <julianknodt@gmail.com>
Date: Mon, 10 Jan 2022 23:39:21 +0000
Subject: [PATCH] Update term for use in more places

Replace use of `ty()` on term and use it in more places. This will allow more flexibility in the
future, but slightly worried it allows items which are consts which only accept types.
---
 .../rustc_infer/src/infer/opaque_types.rs     | 11 +---
 compiler/rustc_interface/src/util.rs          |  2 +
 compiler/rustc_middle/src/ty/assoc.rs         | 13 ++++
 compiler/rustc_middle/src/ty/consts.rs        | 12 ++--
 compiler/rustc_middle/src/ty/flags.rs         |  2 +-
 compiler/rustc_middle/src/ty/mod.rs           |  8 +--
 compiler/rustc_middle/src/ty/print/pretty.rs  | 24 +++++---
 compiler/rustc_middle/src/ty/relate.rs        | 25 +++++---
 compiler/rustc_middle/src/ty/sty.rs           |  2 +-
 compiler/rustc_privacy/src/lib.rs             | 17 ++++--
 .../src/traits/auto_trait.rs                  | 16 +++--
 .../src/traits/error_reporting/mod.rs         | 10 ++--
 .../src/traits/project.rs                     | 11 ++--
 .../src/traits/relationships.rs               |  2 +-
 .../rustc_trait_selection/src/traits/wf.rs    |  7 ++-
 compiler/rustc_traits/src/chalk/lowering.rs   | 16 ++++-
 compiler/rustc_typeck/src/astconv/mod.rs      | 41 +++++++------
 compiler/rustc_typeck/src/check/closure.rs    |  8 ++-
 .../rustc_typeck/src/check/method/suggest.rs  |  9 ++-
 compiler/rustc_typeck/src/check/mod.rs        |  5 +-
 src/librustdoc/clean/auto_trait.rs            |  8 ++-
 src/librustdoc/clean/mod.rs                   | 60 +++++++++++++------
 src/librustdoc/clean/simplify.rs              | 10 ++--
 src/librustdoc/clean/types.rs                 | 33 ++++++++--
 src/librustdoc/html/format.rs                 | 18 +++++-
 src/librustdoc/json/conversions.rs            | 11 +++-
 src/rustdoc-json-types/lib.rs                 | 11 +++-
 .../repeated_projection_type.stderr           |  2 +-
 .../clippy/clippy_lints/src/methods/mod.rs    |  8 ++-
 .../src/methods/unnecessary_to_owned.rs       |  5 +-
 .../src/unit_return_expecting_ord.rs          |  5 +-
 31 files changed, 284 insertions(+), 128 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 39339da9a0bfc..4851e637d3a62 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -7,7 +7,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::subst::{GenericArgKind, Subst};
-use rustc_middle::ty::{self, OpaqueTypeKey, Term, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_span::Span;
 
 use std::ops::ControlFlow;
@@ -584,13 +584,8 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
             debug!(?predicate);
 
             if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
-                if let Term::Ty(ty) = projection.term {
-                    if ty.references_error() {
-                        // No point on adding these obligations since there's a type error involved.
-                        return tcx.ty_error();
-                    }
-                } else {
-                    todo!();
+                if projection.term.references_error() {
+                    return tcx.ty_error();
                 }
             }
 
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 0d1081ee26b77..3921187baa55e 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -742,6 +742,8 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
                                         ast::AssocConstraintKind::Equality { ref term } => {
                                             match term {
                                                 Term::Ty(ty) => involves_impl_trait(ty),
+                                                // FIXME(...): This should check if the constant
+                                                // involves a trait impl, but for now ignore.
                                                 Term::Const(_) => false,
                                             }
                                         }
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 8563bac0bbf87..2776370ba6f46 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -152,6 +152,19 @@ impl<'tcx> AssocItems<'tcx> {
             .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
     }
 
+    /// Returns the associated item with the given name and any of `AssocKind`, if one exists.
+    pub fn find_by_name_and_kinds(
+        &self,
+        tcx: TyCtxt<'_>,
+        ident: Ident,
+        kinds: &[AssocKind],
+        parent_def_id: DefId,
+    ) -> Option<&ty::AssocItem> {
+        self.filter_by_name_unhygienic(ident.name)
+            .filter(|item| kinds.contains(&item.kind))
+            .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
+    }
+
     /// Returns the associated item with the given name in the given `Namespace`, if one exists.
     pub fn find_by_name_and_namespace(
         &self,
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 75705d40a6c80..d6c35dfef8888 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -86,10 +86,14 @@ impl<'tcx> Const<'tcx> {
         if let Some(lit_input) = lit_input {
             // If an error occurred, ignore that it's a literal and leave reporting the error up to
             // mir.
-            if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
-                return Some(c);
-            } else {
-                tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
+            match tcx.at(expr.span).lit_to_const(lit_input) {
+                Ok(c) => return Some(c),
+                Err(e) => {
+                    tcx.sess.delay_span_bug(
+                        expr.span,
+                        &format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
+                    );
+                }
             }
         }
 
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 74c8d7b777722..be9021dc61989 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -245,7 +245,7 @@ impl FlagComputation {
                 self.add_projection_ty(projection_ty);
                 match term {
                     Term::Ty(ty) => self.add_ty(ty),
-                    Term::Const(_c) => todo!(),
+                    Term::Const(c) => self.add_const(c),
                 }
             }
             ty::PredicateKind::WellFormed(arg) => {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f1851150e38e8..42e6f3f6ef584 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -815,8 +815,8 @@ impl<'tcx> From<&'tcx Const<'tcx>> for Term<'tcx> {
 }
 
 impl<'tcx> Term<'tcx> {
-    pub fn ty(&self) -> Ty<'tcx> {
-        if let Term::Ty(ty) = self { ty } else { panic!("Expected type") }
+    pub fn ty(&self) -> Option<Ty<'tcx>> {
+        if let Term::Ty(ty) = self { Some(ty) } else { None }
     }
 }
 
@@ -861,8 +861,8 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
         self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
     }
 
-    pub fn ty(&self) -> Binder<'tcx, Ty<'tcx>> {
-        self.map_bound(|predicate| if let Term::Ty(ty) = predicate.term { ty } else { todo!() })
+    pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
+        self.map_bound(|predicate| predicate.term)
     }
 
     /// The `DefId` of the `TraitItem` for the associated type.
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 8c07f154637e3..6fcb6ac5f4c0b 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,6 +1,6 @@
 use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
-use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable};
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sso::SsoHashSet;
@@ -799,7 +799,7 @@ pub trait PrettyPrinter<'tcx>:
                     let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
 
                     // Projection type entry -- the def-id for naming, and the ty.
-                    let proj_ty = (proj_ref.projection_def_id(), proj_ref.ty());
+                    let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
 
                     self.insert_trait_and_projection(
                         trait_ref,
@@ -850,8 +850,10 @@ pub trait PrettyPrinter<'tcx>:
                     }
 
                     p!(")");
-                    if !return_ty.skip_binder().is_unit() {
-                        p!("-> ", print(return_ty));
+                    if let Term::Ty(ty) = return_ty.skip_binder() {
+                        if !ty.is_unit() {
+                            p!("-> ", print(return_ty));
+                        }
                     }
                     p!(write("{}", if paren_needed { ")" } else { "" }));
 
@@ -902,14 +904,15 @@ pub trait PrettyPrinter<'tcx>:
                     first = false;
                 }
 
-                for (assoc_item_def_id, ty) in assoc_items {
+                for (assoc_item_def_id, term) in assoc_items {
+                    let ty = if let Term::Ty(ty) = term.skip_binder() { ty } else { 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.skip_binder().kind() {
+                    match ty.kind() {
                         ty::Projection(ty::ProjectionTy { item_def_id, .. })
                             if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
                         {
@@ -943,8 +946,11 @@ pub trait PrettyPrinter<'tcx>:
     fn insert_trait_and_projection(
         &mut self,
         trait_ref: ty::PolyTraitRef<'tcx>,
-        proj_ty: Option<(DefId, ty::Binder<'tcx, Ty<'tcx>>)>,
-        traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, BTreeMap<DefId, ty::Binder<'tcx, Ty<'tcx>>>>,
+        proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
+        traits: &mut BTreeMap<
+            ty::PolyTraitRef<'tcx>,
+            BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
+        >,
         fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
     ) {
         let trait_def_id = trait_ref.def_id();
@@ -2716,5 +2722,5 @@ pub struct OpaqueFnEntry<'tcx> {
     has_fn_once: bool,
     fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
     fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
-    return_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
+    return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
 }
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 851c4592f4fad..bd6c24445ef51 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -833,19 +833,30 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
     }
 }
 
+impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
+    fn relate<R: TypeRelation<'tcx>>(
+        relation: &mut R,
+        a: Self,
+        b: Self,
+    ) -> RelateResult<'tcx, Self> {
+        Ok(match (a, b) {
+            (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
+            (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
+            _ => return Err(TypeError::Mismatch),
+        })
+    }
+}
+
 impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
         a: ty::ProjectionPredicate<'tcx>,
         b: ty::ProjectionPredicate<'tcx>,
     ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
-        match (a.term, b.term) {
-            (Term::Ty(a_ty), Term::Ty(b_ty)) => Ok(ty::ProjectionPredicate {
-                projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
-                term: relation.relate(a_ty, b_ty)?.into(),
-            }),
-            _ => todo!(),
-        }
+        Ok(ty::ProjectionPredicate {
+            projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
+            term: relation.relate(a.term, b.term)?.into(),
+        })
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 50d0862905bbf..453e380f6e3a0 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1583,7 +1583,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
         let ty = if let Term::Ty(ty) = projection_predicate.term {
             ty
         } else {
-            todo!();
+            panic!("Only types are permitted here");
         };
 
         Self {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index dc432905b1c7c..73873c8cf0d91 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -128,8 +128,10 @@ where
                 polarity: _,
             }) => self.visit_trait(trait_ref),
             ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
-                let ty = term.ty();
-                ty.visit_with(self)?;
+                match term {
+                    ty::Term::Ty(ty) => ty.visit_with(self)?,
+                    ty::Term::Const(ct) => ct.visit_with(self)?,
+                }
                 self.visit_projection_ty(projection_ty)
             }
             ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
@@ -1186,10 +1188,13 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
             }
 
             for (poly_predicate, _) in bounds.projection_bounds {
-                if self.visit(poly_predicate.skip_binder().term.ty()).is_break()
-                    || self
-                        .visit_projection_ty(poly_predicate.skip_binder().projection_ty)
-                        .is_break()
+                let pred = poly_predicate.skip_binder();
+                let poly_pred_term = match pred.term {
+                    ty::Term::Ty(ty) => self.visit(ty),
+                    ty::Term::Const(ct) => self.visit(ct),
+                };
+                if poly_pred_term.is_break()
+                    || self.visit_projection_ty(pred.projection_ty).is_break()
                 {
                     return;
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 05d2a373dc639..cc20c1179452c 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -6,7 +6,7 @@ use super::*;
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::InferCtxt;
 use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::ty::{Region, RegionVid, Term};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 
@@ -606,7 +606,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
     }
 
     fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
-        matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
+        if let Term::Ty(ty) = p.term().skip_binder() {
+            matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
+        } else {
+            false
+        }
     }
 
     fn evaluate_nested_obligations(
@@ -663,7 +667,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                     // Additionally, we check if we've seen this predicate before,
                     // to avoid rendering duplicate bounds to the user.
                     if self.is_param_no_infer(p.skip_binder().projection_ty.substs)
-                        && !p.ty().skip_binder().has_infer_types()
+                        && !p.term().skip_binder().has_infer_types()
                         && is_new_pred
                     {
                         debug!(
@@ -752,7 +756,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                             // when we started out trying to unify
                             // some inference variables. See the comment above
                             // for more infomration
-                            if p.ty().skip_binder().has_infer_types() {
+                            if p.term().skip_binder().ty().map_or(false, |ty| ty.has_infer_types())
+                            {
                                 if !self.evaluate_nested_obligations(
                                     ty,
                                     v.into_iter(),
@@ -774,7 +779,8 @@ 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.ty().skip_binder().has_infer_types() {
+                            if p.term().skip_binder().ty().map_or(false, |ty| ty.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 85135383b8062..43a961c5c9116 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1304,8 +1304,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
 
                 debug!(
                     "report_projection_error normalized_ty={:?} data.ty={:?}",
-                    normalized_ty,
-                    data.term.ty()
+                    normalized_ty, data.term,
                 );
 
                 let is_normalized_ty_expected = !matches!(
@@ -1315,16 +1314,17 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                         | ObligationCauseCode::ObjectCastObligation(_)
                         | ObligationCauseCode::OpaqueType
                 );
-
+                // FIXME(...): 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,
                     normalized_ty,
-                    data.term.ty(),
+                    data_ty,
                 ) {
                     values = Some(infer::ValuePairs::Types(ExpectedFound::new(
                         is_normalized_ty_expected,
                         normalized_ty,
-                        data.term.ty(),
+                        data_ty,
                     )));
 
                     err_buf = error;
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 4995590baec23..4b53b624c72f1 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -212,10 +212,9 @@ fn project_and_unify_type<'cx, 'tcx>(
     debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
 
     let infcx = selcx.infcx();
-    match infcx
-        .at(&obligation.cause, obligation.param_env)
-        .eq(normalized_ty, obligation.predicate.term.ty())
-    {
+    // FIXME(...): 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: () }) => {
             obligations.extend(inferred_obligations);
             Ok(Ok(Some(obligations)))
@@ -1803,7 +1802,9 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
         Ok(InferOk { value: _, obligations }) => {
             nested_obligations.extend(obligations);
             assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
-            Progress { ty: cache_entry.term.ty(), obligations: nested_obligations }
+            // FIXME(...): Handle consts here as well? Maybe this progress type should just take
+            // a term instead.
+            Progress { ty: cache_entry.term.ty().unwrap(), obligations: nested_obligations }
         }
         Err(e) => {
             let msg = format!(
diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs
index acac76cdfaaf0..aea44841b8f12 100644
--- a/compiler/rustc_trait_selection/src/traits/relationships.rs
+++ b/compiler/rustc_trait_selection/src/traits/relationships.rs
@@ -62,7 +62,7 @@ pub(crate) fn update<'tcx, T>(
     if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
         // If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
         // we need to make it into one.
-        if let Some(vid) = predicate.term.ty().ty_vid() {
+        if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
             debug!("relationship: {:?}.output = true", vid);
             engine.relationships().entry(vid).or_default().output = true;
         }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index e3b366c65bf5c..6a355b567e091 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -116,7 +116,10 @@ pub fn predicate_obligations<'a, 'tcx>(
         }
         ty::PredicateKind::Projection(t) => {
             wf.compute_projection(t.projection_ty);
-            wf.compute(t.term.ty().into());
+            wf.compute(match t.term {
+                ty::Term::Ty(ty) => ty.into(),
+                ty::Term::Const(c) => c.into(),
+            })
         }
         ty::PredicateKind::WellFormed(arg) => {
             wf.compute(arg);
@@ -219,7 +222,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
             // projection coming from another associated type. See
             // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
             // `traits-assoc-type-in-supertrait-bad.rs`.
-            if let ty::Projection(projection_ty) = proj.term.ty().kind() {
+            if let Some(ty::Projection(projection_ty)) = proj.term.ty().map(|ty| ty.kind()) {
                 if let Some(&impl_item_id) =
                     tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
                 {
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index e651ff63c5249..dd98e4ae81b34 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -227,12 +227,24 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>>
 {
     fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> {
         chalk_ir::AliasEq {
-            ty: self.term.ty().lower_into(interner),
+            ty: self.term.ty().unwrap().lower_into(interner),
             alias: self.projection_ty.lower_into(interner),
         }
     }
 }
 
+/*
+// FIXME(...): Where do I add this to Chalk? I can't find it in the rustc repo anywhere.
+impl<'tcx> LowerInto<'tcx, chalk_ir::Term<RustInterner<'tcx>>> for rustc_middle::ty::Term<'tcx> {
+  fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Term<RustInterner<'tcx>> {
+    match self {
+      ty::Term::Ty(ty) => ty.lower_into(interner).into(),
+      ty::Term::Const(c) => c.lower_into(interner).into(),
+    }
+  }
+}
+*/
+
 impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
     fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
         let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i));
@@ -787,7 +799,7 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
             trait_bound: trait_ref.lower_into(interner),
             associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
             parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
-            value: self.term.ty().lower_into(interner),
+            value: self.term.ty().unwrap().lower_into(interner),
         }
     }
 }
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 2866a7884a77a..a13eaa6f178de 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -123,8 +123,7 @@ struct ConvertedBinding<'a, 'tcx> {
 
 #[derive(Debug)]
 enum ConvertedBindingKind<'a, 'tcx> {
-    Equality(Ty<'tcx>),
-    Const(&'tcx Const<'tcx>),
+    Equality(ty::Term<'tcx>),
     Constraint(&'a [hir::GenericBound<'a>]),
 }
 
@@ -604,12 +603,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let kind = match binding.kind {
                     hir::TypeBindingKind::Equality { ref term } => match term {
                         hir::Term::Ty(ref ty) => {
-                            ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
+                            ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
                         }
                         hir::Term::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)
+                            ConvertedBindingKind::Equality(c.into())
                         }
                     },
                     hir::TypeBindingKind::Constraint { ref bounds } => {
@@ -875,6 +874,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
             .is_some()
     }
+    fn trait_defines_associated_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
+        self.tcx()
+            .associated_items(trait_def_id)
+            .find_by_name_and_kinds(
+                self.tcx(),
+                assoc_name,
+                &[ty::AssocKind::Type, ty::AssocKind::Const],
+                trait_def_id,
+            )
+            .is_some()
+    }
 
     // Sets `implicitly_sized` to true on `Bounds` if necessary
     pub(crate) fn add_implicitly_sized<'hir>(
@@ -1223,7 +1233,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         }
 
         match binding.kind {
-            ConvertedBindingKind::Equality(ty) => {
+            ConvertedBindingKind::Equality(term) => {
                 // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
                 // the "projection predicate" for:
                 //
@@ -1231,16 +1241,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 bounds.projection_bounds.push((
                     projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
                         projection_ty,
-                        term: ty.into(),
-                    }),
-                    binding.span,
-                ));
-            }
-            ConvertedBindingKind::Const(c) => {
-                bounds.projection_bounds.push((
-                    projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
-                        projection_ty,
-                        term: c.into(),
+                        term: term,
                     }),
                     binding.span,
                 ));
@@ -1391,8 +1392,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         let pred = bound_predicate.rebind(pred);
                         // A `Self` within the original bound will be substituted with a
                         // `trait_object_dummy_self`, so check for that.
-                        let references_self =
-                            pred.skip_binder().term.ty().walk().any(|arg| arg == dummy_self.into());
+                        let references_self = match pred.skip_binder().term {
+                            ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
+                            ty::Term::Const(c) => {
+                                c.ty.walk().any(|arg| arg == dummy_self.into())
+                            }
+                        };
 
                         // If the projection output contains `Self`, force the user to
                         // elaborate it explicitly to avoid a lot of complexity.
@@ -1615,7 +1620,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
     {
         let mut matching_candidates = all_candidates()
-            .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
+            .filter(|r| self.trait_defines_associated_named(r.def_id(), assoc_name));
 
         let bound = match matching_candidates.next() {
             Some(bound) => bound,
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index c8e1d8b190c9d..504807e87b69a 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -279,7 +279,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return None;
         };
 
-        let ret_param_ty = projection.skip_binder().term.ty();
+        // Since this is a return parameter type it is safe to unwrap.
+        let ret_param_ty = projection.skip_binder().term.ty().unwrap();
         let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
         debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
 
@@ -706,9 +707,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Extract the type from the projection. Note that there can
         // be no bound variables in this type because the "self type"
         // does not have any regions in it.
-        let output_ty = self.resolve_vars_if_possible(predicate.term.ty());
+        let output_ty = self.resolve_vars_if_possible(predicate.term);
         debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty);
-        Some(output_ty)
+        // FIXME(...): How to handle consts here? Will this always be a const?
+        Some(output_ty.ty().unwrap())
     }
 
     /// Converts the types that the user supplied, in case that doing
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 590d65b7cba3f..bf362357ed073 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -789,10 +789,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     item_def_id: projection_ty.item_def_id,
                                 };
 
-                                let ty: Ty<'_> = pred.skip_binder().term.ty();
+                                let fmt = match pred.skip_binder().term {
+                                    ty::Term::Ty(ty) => format!("{}", ty),
+                                    ty::Term::Const(c) => format!("{}", c),
+                                };
 
-                                let obligation = format!("{} = {}", projection_ty, ty);
-                                let quiet = format!("{} = {}", quiet_projection_ty, ty);
+                                let obligation = format!("{} = {}", projection_ty, fmt);
+                                let quiet = format!("{} = {}", quiet_projection_ty, fmt);
 
                                 bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
                                 Some((obligation, projection_ty.self_ty()))
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 8d06b8a7a170b..9f67713d585bd 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -694,7 +694,10 @@ fn bounds_from_generic_predicates<'tcx>(
         where_clauses.push(format!(
             "{} = {}",
             tcx.def_path_str(p.projection_ty.item_def_id),
-            p.term.ty()
+            match p.term {
+                ty::Term::Ty(ty) => format!("{}", ty),
+                ty::Term::Const(c) => format!("{}", c),
+            }
         ));
     }
     let where_clauses = if where_clauses.is_empty() {
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 09692d27e8fbe..18a4d8a475380 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -553,8 +553,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                             if self.is_fn_trait(trait_) && left_name == sym::Output {
                                 ty_to_fn
                                     .entry(*ty.clone())
-                                    .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone())))
-                                    .or_insert((None, Some(rhs)));
+                                    .and_modify(|e| {
+                                        *e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
+                                    })
+                                    .or_insert((None, Some(rhs.ty().unwrap().clone())));
                                 continue;
                             }
 
@@ -570,7 +572,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                                 GenericArgs::AngleBracketed { ref mut bindings, .. } => {
                                     bindings.push(TypeBinding {
                                         name: left_name,
-                                        kind: TypeBindingKind::Equality { ty: rhs },
+                                        kind: TypeBindingKind::Equality { term: rhs },
                                     });
                                 }
                                 GenericArgs::Parenthesized { .. } => {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f6af81769b7a1..6a3cdcc2c20da 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -272,9 +272,10 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
                 bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
             },
 
-            hir::WherePredicate::EqPredicate(ref wrp) => {
-                WherePredicate::EqPredicate { lhs: wrp.lhs_ty.clean(cx), rhs: wrp.rhs_ty.clean(cx) }
-            }
+            hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
+                lhs: wrp.lhs_ty.clean(cx),
+                rhs: wrp.rhs_ty.clean(cx).into(),
+            },
         }
     }
 }
@@ -352,11 +353,31 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
     }
 }
 
+impl<'tcx> Clean<Term> for ty::Term<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Term {
+        match self {
+            ty::Term::Ty(ty) => Term::Type(ty.clean(cx)),
+            ty::Term::Const(c) => Term::Constant(c.clean(cx)),
+        }
+    }
+}
+
+impl<'tcx> Clean<Term> for hir::Term<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Term {
+        match self {
+            hir::Term::Ty(ty) => Term::Type(ty.clean(cx)),
+            hir::Term::Const(c) => {
+                let def_id = cx.tcx.hir().local_def_id(c.hir_id);
+                Term::Constant(ty::Const::from_anon_const(cx.tcx, def_id).clean(cx))
+            }
+        }
+    }
+}
+
 impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
     fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
         let ty::ProjectionPredicate { projection_ty, term } = self;
-        let ty = term.ty();
-        WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
+        WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) }
     }
 }
 
@@ -614,7 +635,7 @@ fn clean_ty_generics(
 
             if let Some(param_idx) = param_idx {
                 if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
-                    let p = p.clean(cx)?;
+                    let p: WherePredicate = p.clean(cx)?;
 
                     b.extend(
                         p.get_bounds()
@@ -624,13 +645,17 @@ fn clean_ty_generics(
                             .filter(|b| !b.is_sized_bound(cx)),
                     );
 
-                    let proj = projection.map(|p| {
-                        (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term.ty())
-                    });
+                    let proj = projection
+                        .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term));
                     if let Some(((_, trait_did, name), rhs)) =
                         proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
                     {
-                        impl_trait_proj.entry(param_idx).or_default().push((trait_did, name, rhs));
+                        // FIXME(...): Remove this unwrap()
+                        impl_trait_proj.entry(param_idx).or_default().push((
+                            trait_did,
+                            name,
+                            rhs.ty().unwrap(),
+                        ));
                     }
 
                     return None;
@@ -649,7 +674,7 @@ fn clean_ty_generics(
             if let Some(proj) = impl_trait_proj.remove(&idx) {
                 for (trait_did, name, rhs) in proj {
                     let rhs = rhs.clean(cx);
-                    simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
+                    simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
                 }
             }
         } else {
@@ -1497,7 +1522,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 for pb in obj.projection_bounds() {
                     bindings.push(TypeBinding {
                         name: cx.tcx.associated_item(pb.item_def_id()).ident.name,
-                        kind: TypeBindingKind::Equality { ty: pb.skip_binder().ty.clean(cx) },
+                        kind: TypeBindingKind::Equality {
+                            term: pb.skip_binder().ty.clean(cx).into(),
+                        },
                     });
                 }
 
@@ -1568,7 +1595,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                                                 .ident
                                                 .name,
                                             kind: TypeBindingKind::Equality {
-                                                ty: proj.term.ty().clean(cx),
+                                                term: proj.term.clean(cx),
                                             },
                                         })
                                     } else {
@@ -2116,10 +2143,9 @@ impl Clean<TypeBinding> for hir::TypeBinding<'_> {
 impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
         match *self {
-            hir::TypeBindingKind::Equality { ref term } => match term {
-                hir::Term::Ty(ref ty) => TypeBindingKind::Equality { ty: ty.clean(cx) },
-                hir::Term::Const(ref _c) => todo!(),
-            },
+            hir::TypeBindingKind::Equality { ref term } => {
+                TypeBindingKind::Equality { term: term.clean(cx) }
+            }
             hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint {
                 bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
             },
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 4c81e75e8d630..0bad153280822 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -92,7 +92,7 @@ crate fn merge_bounds(
     bounds: &mut Vec<clean::GenericBound>,
     trait_did: DefId,
     name: Symbol,
-    rhs: &clean::Type,
+    rhs: &clean::Term,
 ) -> bool {
     !bounds.iter_mut().any(|b| {
         let trait_ref = match *b {
@@ -110,14 +110,14 @@ crate fn merge_bounds(
             PP::AngleBracketed { ref mut bindings, .. } => {
                 bindings.push(clean::TypeBinding {
                     name,
-                    kind: clean::TypeBindingKind::Equality { ty: rhs.clone() },
+                    kind: clean::TypeBindingKind::Equality { term: rhs.clone() },
                 });
             }
             PP::Parenthesized { ref mut output, .. } => match output {
-                Some(o) => assert_eq!(o.as_ref(), rhs),
+                Some(o) => assert_eq!(&clean::Term::Type(o.as_ref().clone()), rhs),
                 None => {
-                    if *rhs != clean::Type::Tuple(Vec::new()) {
-                        *output = Some(Box::new(rhs.clone()));
+                    if *rhs != clean::Term::Type(clean::Type::Tuple(Vec::new())) {
+                        *output = Some(Box::new(rhs.ty().unwrap().clone()));
                     }
                 }
             },
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 00c6e38839f54..ba771c0c1a1a4 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1212,7 +1212,7 @@ impl Lifetime {
 crate enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
     RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
-    EqPredicate { lhs: Type, rhs: Type },
+    EqPredicate { lhs: Type, rhs: Term },
 }
 
 impl WherePredicate {
@@ -1308,7 +1308,12 @@ impl FnDecl {
             FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] {
                 GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
                     let bindings = trait_.bindings().unwrap();
-                    FnRetTy::Return(bindings[0].ty().clone())
+                    let ret_ty = bindings[0].term();
+                    let ty = match ret_ty {
+                        Term::Type(ty) => ty,
+                        Term::Constant(_c) => unreachable!(),
+                    };
+                    FnRetTy::Return(ty.clone())
                 }
                 _ => panic!("unexpected desugaring of async function"),
             },
@@ -2121,6 +2126,24 @@ crate struct Constant {
     crate kind: ConstantKind,
 }
 
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+crate enum Term {
+    Type(Type),
+    Constant(Constant),
+}
+
+impl Term {
+    crate fn ty(&self) -> Option<&Type> {
+        if let Term::Type(ty) = self { Some(ty) } else { None }
+    }
+}
+
+impl From<Type> for Term {
+    fn from(ty: Type) -> Self {
+        Term::Type(ty)
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 crate enum ConstantKind {
     /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
@@ -2283,14 +2306,14 @@ crate struct TypeBinding {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 crate enum TypeBindingKind {
-    Equality { ty: Type },
+    Equality { term: Term },
     Constraint { bounds: Vec<GenericBound> },
 }
 
 impl TypeBinding {
-    crate fn ty(&self) -> &Type {
+    crate fn term(&self) -> &Term {
         match self.kind {
-            TypeBindingKind::Equality { ref ty } => ty,
+            TypeBindingKind::Equality { ref term } => term,
             _ => panic!("expected equality type binding for parenthesized generic args"),
         }
     }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 8571a6a137f51..08840626259dc 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1442,11 +1442,11 @@ impl clean::TypeBinding {
         display_fn(move |f| {
             f.write_str(self.name.as_str())?;
             match self.kind {
-                clean::TypeBindingKind::Equality { ref ty } => {
+                clean::TypeBindingKind::Equality { ref term } => {
                     if f.alternate() {
-                        write!(f, " = {:#}", ty.print(cx))?;
+                        write!(f, " = {:#}", term.print(cx))?;
                     } else {
-                        write!(f, " = {}", ty.print(cx))?;
+                        write!(f, " = {}", term.print(cx))?;
                     }
                 }
                 clean::TypeBindingKind::Constraint { ref bounds } => {
@@ -1492,6 +1492,18 @@ impl clean::GenericArg {
     }
 }
 
+impl clean::types::Term {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cx: &'a Context<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+        match self {
+            clean::types::Term::Type(ty) => ty.print(cx),
+            _ => todo!(),
+        }
+    }
+}
+
 crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
     struct WithFormatter<F>(Cell<Option<F>>);
 
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index c8efa4bbbcc30..e77bd5c922313 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -162,7 +162,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
     fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
         use clean::TypeBindingKind::*;
         match kind {
-            Equality { ty } => TypeBindingKind::Equality(ty.into_tcx(tcx)),
+            Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
             Constraint { bounds } => {
                 TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
             }
@@ -452,6 +452,15 @@ impl FromWithTcx<clean::Type> for Type {
     }
 }
 
+impl FromWithTcx<clean::Term> for Term {
+    fn from_tcx(term: clean::Term, tcx: TyCtxt<'_>) -> Term {
+        match term {
+            clean::Term::Type(ty) => Term::Type(FromWithTcx::from_tcx(ty, tcx)),
+            clean::Term::Constant(c) => Term::Constant(FromWithTcx::from_tcx(c, tcx)),
+        }
+    }
+}
+
 impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
     fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
         let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 9466f84ffcd59..618c8aab86a19 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -148,7 +148,7 @@ pub struct TypeBinding {
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "snake_case")]
 pub enum TypeBindingKind {
-    Equality(Type),
+    Equality(Term),
     Constraint(Vec<GenericBound>),
 }
 
@@ -335,7 +335,7 @@ pub enum GenericParamDefKind {
 pub enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
     RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },
-    EqPredicate { lhs: Type, rhs: Type },
+    EqPredicate { lhs: Type, rhs: Term },
 }
 
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@@ -359,6 +359,13 @@ pub enum TraitBoundModifier {
     MaybeConst,
 }
 
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub enum Term {
+    Type(Type),
+    Constant(Constant),
+}
+
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "kind", content = "inner")]
diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
index 07d194476a5db..ad51707070f9f 100644
--- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
+++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
@@ -1,4 +1,4 @@
-error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, (I,)), [])`
+error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, Ty((I,))), [])`
   --> $DIR/repeated_projection_type.rs:19:1
    |
 LL | / impl<I, V: Id<This = (I,)>> X for V {
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index c0e65e520f23a..ca8bbbd8f9169 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -2141,12 +2141,16 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 // one of the associated types must be Self
                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
                     if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
+                        let assoc_ty = match projection_predicate.term {
+                          ty::Term::Ty(ty) => ty,
+                          ty::Term::Const(c) => c.ty,
+                        };
                         // walk the associated type and check for Self
                         if let Some(self_adt) = self_ty.ty_adt_def() {
-                            if contains_adt_constructor(projection_predicate.term.ty(), self_adt) {
+                            if contains_adt_constructor(assoc_ty, self_adt) {
                                 return;
                             }
-                        } else if contains_ty(projection_predicate.term.ty(), self_ty) {
+                        } else if contains_ty(assoc_ty, self_ty) {
                             return;
                         }
                     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 865a36a5cd1d6..9162de3cceafa 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -243,9 +243,10 @@ fn check_other_call_arg<'tcx>(
         if if trait_predicate.def_id() == deref_trait_id {
             if let [projection_predicate] = projection_predicates[..] {
                 let normalized_ty =
-                    cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term.ty());
+                    cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
                 implements_trait(cx, receiver_ty, deref_trait_id, &[])
-                    && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(normalized_ty)
+                    && get_associated_type(cx, receiver_ty, deref_trait_id,
+                    "Target").map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
             } else {
                 false
             }
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index 09f9e1ee09990..68156df2ecea8 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -98,9 +98,10 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
                         if trait_pred.self_ty() == inp;
                         if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
                         then {
-                            if ord_preds.iter().any(|ord| ord.self_ty() == return_ty_pred.term.ty()) {
+                            if ord_preds.iter().any(|ord| Some(ord.self_ty()) ==
+                            return_ty_pred.term.ty()) {
                                 args_to_check.push((i, "Ord".to_string()));
-                            } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty()) {
+                            } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) {
                                 args_to_check.push((i, "PartialOrd".to_string()));
                             }
                         }