about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-07-05 08:45:45 -0700
committerGitHub <noreply@github.com>2023-07-05 08:45:45 -0700
commitb2b1a507516c9b6df949e15c5e3590bb8ff9e65b (patch)
tree63f8a575e099fb1389c4652dfb6c81decf1eadf3
parent0334b64cbba082469d6f473a29d4fc201beb0756 (diff)
parent62174bfe7255f2e238b44923ad6d6abde630f1ab (diff)
downloadrust-b2b1a507516c9b6df949e15c5e3590bb8ff9e65b.tar.gz
rust-b2b1a507516c9b6df949e15c5e3590bb8ff9e65b.zip
Rollup merge of #113321 - BoxyUwU:move_constkind_to_typeir, r=oli-obk
Move `ty::ConstKind` to `rustc_type_ir`

Needed this in another PR for custom debug impls, and this will also be required to move the new solver into a separate crate that does not use `TyCtxt` so that r-a and friends can depend on the trait solver.

Rebased on top of #113325, only the second and third commits needs reviewing
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs1
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs160
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs204
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs2
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs46
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/util.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs6
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--compiler/rustc_type_ir/src/lib.rs10
-rw-r--r--compiler/rustc_type_ir/src/structural_impls.rs20
-rw-r--r--compiler/rustc_type_ir/src/sty.rs218
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs4
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.mir2
22 files changed, 459 insertions, 250 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index ce10780f9de..5f78cce50e6 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -706,7 +706,6 @@ fn codegen_stmt<'tcx>(
                     let times = fx
                         .monomorphize(times)
                         .eval(fx.tcx, ParamEnv::reveal_all())
-                        .kind()
                         .try_to_bits(fx.tcx.data_layout.pointer_size)
                         .unwrap();
                     if operand.layout().size.bytes() == 0 {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 124b5692048..49563d0eee0 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2329,7 +2329,7 @@ impl<'tcx> ConstantKind<'tcx> {
     pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
         match self {
             Self::Ty(c) => {
-                if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) {
+                if let Some(val) = c.try_eval_for_mir(tcx, param_env) {
                     match val {
                         Ok(val) => Self::Val(val, c.ty()),
                         Err(guar) => Self::Ty(ty::Const::new_error(tcx, guar, self.ty())),
@@ -2867,7 +2867,7 @@ fn pretty_print_const_value<'tcx>(
                 }
             }
             (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
-                let n = n.kind().try_to_bits(tcx.data_layout.pointer_size).unwrap();
+                let n = n.try_to_bits(tcx.data_layout.pointer_size).unwrap();
                 // cast is ok because we already checked for pointer size (32 or 64 bit) above
                 let range = AllocRange { start: offset, size: Size::from_bytes(n) };
                 let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap();
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 44cdb9b1cd8..78943cb0ddb 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,6 +1,6 @@
 use crate::middle::resolve_bound_vars as rbv;
-use crate::mir::interpret::LitToConstInput;
-use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
+use crate::mir::interpret::{AllocId, ConstValue, LitToConstInput, Scalar};
+use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 use rustc_data_structures::intern::Interned;
 use rustc_error_messages::MultiSpan;
 use rustc_hir as hir;
@@ -14,9 +14,13 @@ mod valtree;
 
 pub use int::*;
 pub use kind::*;
+use rustc_span::ErrorGuaranteed;
 use rustc_span::DUMMY_SP;
+use rustc_target::abi::Size;
 pub use valtree::*;
 
+use super::sty::ConstKind;
+
 /// Use this rather than `ConstData`, whenever possible.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
 #[rustc_pass_by_value]
@@ -32,6 +36,16 @@ pub struct ConstData<'tcx> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(ConstData<'_>, 40);
 
+enum EvalMode {
+    Typeck,
+    Mir,
+}
+
+enum EvalResult<'tcx> {
+    ValTree(ty::ValTree<'tcx>),
+    ConstVal(ConstValue<'tcx>),
+}
+
 impl<'tcx> Const<'tcx> {
     #[inline]
     pub fn ty(self) -> Ty<'tcx> {
@@ -40,7 +54,7 @@ impl<'tcx> Const<'tcx> {
 
     #[inline]
     pub fn kind(self) -> ConstKind<'tcx> {
-        self.0.kind
+        self.0.kind.clone()
     }
 
     #[inline]
@@ -293,12 +307,12 @@ impl<'tcx> Const<'tcx> {
         assert_eq!(self.ty(), ty);
         let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
         // if `ty` does not depend on generic parameters, use an empty param_env
-        self.kind().eval(tcx, param_env).try_to_bits(size)
+        self.eval(tcx, param_env).try_to_bits(size)
     }
 
     #[inline]
     pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
-        self.kind().eval(tcx, param_env).try_to_bool()
+        self.eval(tcx, param_env).try_to_bool()
     }
 
     #[inline]
@@ -307,14 +321,14 @@ impl<'tcx> Const<'tcx> {
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
     ) -> Option<u64> {
-        self.kind().eval(tcx, param_env).try_to_target_usize(tcx)
+        self.eval(tcx, param_env).try_to_target_usize(tcx)
     }
 
     #[inline]
     /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
     /// unevaluated constant.
     pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
-        if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) {
+        if let Some(val) = self.try_eval_for_typeck(tcx, param_env) {
             match val {
                 Ok(val) => ty::Const::new_value(tcx, val, self.ty()),
                 Err(guar) => ty::Const::new_error(tcx, guar, self.ty()),
@@ -339,6 +353,138 @@ impl<'tcx> Const<'tcx> {
             .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
     }
 
+    #[inline]
+    /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
+    /// return `None`.
+    // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
+    pub fn try_eval_for_mir(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+    ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
+        match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
+            Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
+            Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
+            Some(Err(e)) => Some(Err(e)),
+            None => None,
+        }
+    }
+
+    #[inline]
+    /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
+    /// return `None`.
+    // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
+    pub fn try_eval_for_typeck(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+    ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
+        match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
+            Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
+            Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
+            Some(Err(e)) => Some(Err(e)),
+            None => None,
+        }
+    }
+
+    #[inline]
+    fn try_eval_inner(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        eval_mode: EvalMode,
+    ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
+        assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
+        if let ConstKind::Unevaluated(unevaluated) = self.kind() {
+            use crate::mir::interpret::ErrorHandled;
+
+            // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
+            // also does later, but we want to do it before checking for
+            // inference variables.
+            // Note that we erase regions *before* calling `with_reveal_all_normalized`,
+            // so that we don't try to invoke this query with
+            // any region variables.
+
+            // HACK(eddyb) when the query key would contain inference variables,
+            // attempt using identity substs and `ParamEnv` instead, that will succeed
+            // when the expression doesn't depend on any parameters.
+            // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
+            // we can call `infcx.const_eval_resolve` which handles inference variables.
+            let param_env_and = if (param_env, unevaluated).has_non_region_infer() {
+                tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst {
+                    def: unevaluated.def,
+                    substs: InternalSubsts::identity_for_item(tcx, unevaluated.def),
+                })
+            } else {
+                tcx.erase_regions(param_env)
+                    .with_reveal_all_normalized(tcx)
+                    .and(tcx.erase_regions(unevaluated))
+            };
+
+            // FIXME(eddyb) maybe the `const_eval_*` methods should take
+            // `ty::ParamEnvAnd` instead of having them separate.
+            let (param_env, unevaluated) = param_env_and.into_parts();
+            // try to resolve e.g. associated constants to their definition on an impl, and then
+            // evaluate the const.
+            match eval_mode {
+                EvalMode::Typeck => {
+                    match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
+                        // NOTE(eddyb) `val` contains no lifetimes/types/consts,
+                        // and we use the original type, so nothing from `substs`
+                        // (which may be identity substs, see above),
+                        // can leak through `val` into the const we return.
+                        Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
+                        Err(ErrorHandled::TooGeneric) => None,
+                        Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
+                    }
+                }
+                EvalMode::Mir => {
+                    match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) {
+                        // NOTE(eddyb) `val` contains no lifetimes/types/consts,
+                        // and we use the original type, so nothing from `substs`
+                        // (which may be identity substs, see above),
+                        // can leak through `val` into the const we return.
+                        Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
+                        Err(ErrorHandled::TooGeneric) => None,
+                        Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
+                    }
+                }
+            }
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
+        if let ConstKind::Value(val) = self.kind() { Some(val) } else { None }
+    }
+
+    #[inline]
+    pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
+        self.try_to_value()?.try_to_scalar()
+    }
+
+    #[inline]
+    pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
+        self.try_to_value()?.try_to_scalar_int()
+    }
+
+    #[inline]
+    pub fn try_to_bits(self, size: Size) -> Option<u128> {
+        self.try_to_scalar_int()?.to_bits(size).ok()
+    }
+
+    #[inline]
+    pub fn try_to_bool(self) -> Option<bool> {
+        self.try_to_scalar_int()?.try_into().ok()
+    }
+
+    #[inline]
+    pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
+        self.try_to_value()?.try_to_target_usize(tcx)
+    }
+
     pub fn is_ct_infer(self) -> bool {
         matches!(self.kind(), ty::ConstKind::Infer(_))
     }
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 1dd4f8a2437..a6bf7491118 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -1,17 +1,11 @@
 use super::Const;
 use crate::mir;
-use crate::mir::interpret::{AllocId, ConstValue, Scalar};
 use crate::ty::abstract_const::CastKind;
-use crate::ty::subst::{InternalSubsts, SubstsRef};
-use crate::ty::ParamEnv;
-use crate::ty::{self, List, Ty, TyCtxt, TypeVisitableExt};
+use crate::ty::subst::SubstsRef;
+use crate::ty::{self, List, Ty};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
-use rustc_target::abi::Size;
-
-use super::ScalarInt;
 
 /// An unevaluated (potentially generic) constant used in the type-system.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
@@ -41,45 +35,6 @@ impl<'tcx> UnevaluatedConst<'tcx> {
     }
 }
 
-/// Represents a constant in Rust.
-#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
-#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
-#[derive(derive_more::From)]
-pub enum ConstKind<'tcx> {
-    /// A const generic parameter.
-    Param(ty::ParamConst),
-
-    /// Infer the value of the const.
-    Infer(InferConst<'tcx>),
-
-    /// Bound const variable, used only when preparing a trait query.
-    Bound(ty::DebruijnIndex, ty::BoundVar),
-
-    /// A placeholder const - universally quantified higher-ranked const.
-    Placeholder(ty::PlaceholderConst<'tcx>),
-
-    /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
-    /// variants when the code is monomorphic enough for that.
-    Unevaluated(UnevaluatedConst<'tcx>),
-
-    /// Used to hold computed value.
-    Value(ty::ValTree<'tcx>),
-
-    /// A placeholder for a const which could not be computed; this is
-    /// propagated to avoid useless error messages.
-    #[from(ignore)]
-    Error(ErrorGuaranteed),
-
-    /// Expr which contains an expression which has partially evaluated items.
-    Expr(Expr<'tcx>),
-}
-
-impl<'tcx> From<ty::ConstVid<'tcx>> for ConstKind<'tcx> {
-    fn from(const_vid: ty::ConstVid<'tcx>) -> Self {
-        InferConst::Var(const_vid).into()
-    }
-}
-
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
 pub enum Expr<'tcx> {
@@ -93,39 +48,7 @@ pub enum Expr<'tcx> {
 static_assert_size!(Expr<'_>, 24);
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(ConstKind<'_>, 32);
-
-impl<'tcx> ConstKind<'tcx> {
-    #[inline]
-    pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
-        if let ConstKind::Value(val) = self { Some(val) } else { None }
-    }
-
-    #[inline]
-    pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
-        self.try_to_value()?.try_to_scalar()
-    }
-
-    #[inline]
-    pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
-        self.try_to_value()?.try_to_scalar_int()
-    }
-
-    #[inline]
-    pub fn try_to_bits(self, size: Size) -> Option<u128> {
-        self.try_to_scalar_int()?.to_bits(size).ok()
-    }
-
-    #[inline]
-    pub fn try_to_bool(self) -> Option<bool> {
-        self.try_to_scalar_int()?.try_into().ok()
-    }
-
-    #[inline]
-    pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
-        self.try_to_value()?.try_to_target_usize(tcx)
-    }
-}
+static_assert_size!(super::ConstKind<'_>, 32);
 
 /// An inference variable for a const, for use in const generics.
 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
@@ -144,124 +67,3 @@ impl<CTX> HashStable<CTX> for InferConst<'_> {
         }
     }
 }
-
-enum EvalMode {
-    Typeck,
-    Mir,
-}
-
-enum EvalResult<'tcx> {
-    ValTree(ty::ValTree<'tcx>),
-    ConstVal(ConstValue<'tcx>),
-}
-
-impl<'tcx> ConstKind<'tcx> {
-    #[inline]
-    /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
-    /// unevaluated constant.
-    pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
-        self.try_eval_for_typeck(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
-    }
-
-    #[inline]
-    /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
-    /// return `None`.
-    // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
-    pub fn try_eval_for_mir(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-    ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
-        match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
-            Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
-            Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
-            Some(Err(e)) => Some(Err(e)),
-            None => None,
-        }
-    }
-
-    #[inline]
-    /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
-    /// return `None`.
-    // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
-    pub fn try_eval_for_typeck(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-    ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
-        match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
-            Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
-            Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
-            Some(Err(e)) => Some(Err(e)),
-            None => None,
-        }
-    }
-
-    #[inline]
-    fn try_eval_inner(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-        eval_mode: EvalMode,
-    ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
-        assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
-        if let ConstKind::Unevaluated(unevaluated) = self {
-            use crate::mir::interpret::ErrorHandled;
-
-            // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
-            // also does later, but we want to do it before checking for
-            // inference variables.
-            // Note that we erase regions *before* calling `with_reveal_all_normalized`,
-            // so that we don't try to invoke this query with
-            // any region variables.
-
-            // HACK(eddyb) when the query key would contain inference variables,
-            // attempt using identity substs and `ParamEnv` instead, that will succeed
-            // when the expression doesn't depend on any parameters.
-            // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
-            // we can call `infcx.const_eval_resolve` which handles inference variables.
-            let param_env_and = if (param_env, unevaluated).has_non_region_infer() {
-                tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst {
-                    def: unevaluated.def,
-                    substs: InternalSubsts::identity_for_item(tcx, unevaluated.def),
-                })
-            } else {
-                tcx.erase_regions(param_env)
-                    .with_reveal_all_normalized(tcx)
-                    .and(tcx.erase_regions(unevaluated))
-            };
-
-            // FIXME(eddyb) maybe the `const_eval_*` methods should take
-            // `ty::ParamEnvAnd` instead of having them separate.
-            let (param_env, unevaluated) = param_env_and.into_parts();
-            // try to resolve e.g. associated constants to their definition on an impl, and then
-            // evaluate the const.
-            match eval_mode {
-                EvalMode::Typeck => {
-                    match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
-                        // NOTE(eddyb) `val` contains no lifetimes/types/consts,
-                        // and we use the original type, so nothing from `substs`
-                        // (which may be identity substs, see above),
-                        // can leak through `val` into the const we return.
-                        Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
-                        Err(ErrorHandled::TooGeneric) => None,
-                        Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
-                    }
-                }
-                EvalMode::Mir => {
-                    match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) {
-                        // NOTE(eddyb) `val` contains no lifetimes/types/consts,
-                        // and we use the original type, so nothing from `substs`
-                        // (which may be identity substs, see above),
-                        // can leak through `val` into the const we return.
-                        Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
-                        Err(ErrorHandled::TooGeneric) => None,
-                        Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
-                    }
-                }
-            }
-        } else {
-            None
-        }
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index e50331bc461..83e0c849c55 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -108,6 +108,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type PredicateKind = ty::PredicateKind<'tcx>;
     type AllocId = crate::mir::interpret::AllocId;
 
+    type InferConst = ty::InferConst<'tcx>;
+    type AliasConst = ty::UnevaluatedConst<'tcx>;
+    type ParamConst = ty::ParamConst;
+    type BoundConst = ty::BoundVar;
+    type PlaceholderConst = ty::PlaceholderConst<'tcx>;
+    type ValueConst = ty::ValTree<'tcx>;
+    type ExprConst = ty::Expr<'tcx>;
+
     type EarlyBoundRegion = ty::EarlyBoundRegion;
     type BoundRegion = ty::BoundRegion;
     type FreeRegion = ty::FreeRegion;
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
index 018fa227154..295cb146461 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
@@ -170,7 +170,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
         match self {
             Self::ConstIsZero(c) => {
                 let c = ty::EarlyBinder::bind(c).subst(tcx, substs);
-                let pred = match c.kind().try_to_target_usize(tcx) {
+                let pred = match c.try_to_target_usize(tcx) {
                     Some(0) => Self::True,
                     Some(1..) => Self::False,
                     None => Self::ConstIsZero(c),
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 4223502848e..b92d84152b4 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -197,7 +197,7 @@ fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedP
 
         // If we can evaluate the array length before having a `ParamEnv`, then
         // we can simplify the predicate. This is an optimization.
-        Array(ty, len) => match len.kind().try_to_target_usize(tcx) {
+        Array(ty, len) => match len.try_to_target_usize(tcx) {
             Some(0) => InhabitedPredicate::True,
             Some(1..) => ty.inhabited_predicate(tcx),
             None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 48388be2f46..c100c45b61a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -66,6 +66,10 @@ use std::{fmt, str};
 
 pub use crate::ty::diagnostics::*;
 pub use rustc_type_ir::AliasKind::*;
+pub use rustc_type_ir::ConstKind::{
+    Bound as BoundCt, Error as ErrorCt, Expr as ExprCt, Infer as InferCt, Param as ParamCt,
+    Placeholder as PlaceholderCt, Unevaluated, Value,
+};
 pub use rustc_type_ir::DynKind::*;
 pub use rustc_type_ir::InferTy::*;
 pub use rustc_type_ir::RegionKind::*;
@@ -81,7 +85,7 @@ pub use self::closure::{
     CAPTURE_STRUCT_LOCAL,
 };
 pub use self::consts::{
-    Const, ConstData, ConstInt, ConstKind, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree,
+    Const, ConstData, ConstInt, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree,
 };
 pub use self::context::{
     tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed,
@@ -93,7 +97,7 @@ pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::BoundRegionKind::*;
 pub use self::sty::{
     AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
-    BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid,
+    BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstKind, ConstVid,
     EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
     FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts,
     InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialPredicate,
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 15fb94fe090..4a639a2a0fe 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -11,6 +11,7 @@ use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 use rustc_hir::def::Namespace;
 use rustc_index::{Idx, IndexVec};
 use rustc_target::abi::TyAndLayout;
+use rustc_type_ir::ConstKind;
 
 use std::fmt;
 use std::ops::ControlFlow;
@@ -241,24 +242,6 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ConstKind<'tcx> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        use ty::ConstKind::*;
-        match self {
-            Param(param) => write!(f, "{param:?}"),
-            Infer(var) => write!(f, "{var:?}"),
-            Bound(debruijn, var) => rustc_type_ir::debug_bound_var(f, *debruijn, *var),
-            Placeholder(placeholder) => write!(f, "{placeholder:?}"),
-            Unevaluated(uv) => {
-                f.debug_tuple("Unevaluated").field(&uv.substs).field(&uv.def).finish()
-            }
-            Value(valtree) => write!(f, "{valtree:?}"),
-            Error(_) => write!(f, "{{const error}}"),
-            Expr(expr) => write!(f, "{expr:?}"),
-        }
-    }
-}
-
 impl fmt::Debug for ty::BoundTy {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.kind {
@@ -728,7 +711,18 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
         folder: &mut F,
     ) -> Result<Self, F::Error> {
         let ty = self.ty().try_fold_with(folder)?;
-        let kind = self.kind().try_fold_with(folder)?;
+        let kind = match self.kind() {
+            ConstKind::Param(p) => ConstKind::Param(p.try_fold_with(folder)?),
+            ConstKind::Infer(i) => ConstKind::Infer(i.try_fold_with(folder)?),
+            ConstKind::Bound(d, b) => {
+                ConstKind::Bound(d.try_fold_with(folder)?, b.try_fold_with(folder)?)
+            }
+            ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?),
+            ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?),
+            ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?),
+            ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?),
+            ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?),
+        };
         if ty != self.ty() || kind != self.kind() {
             Ok(folder.interner().mk_ct_from_kind(kind, ty))
         } else {
@@ -743,7 +737,19 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
         visitor: &mut V,
     ) -> ControlFlow<V::BreakTy> {
         self.ty().visit_with(visitor)?;
-        self.kind().visit_with(visitor)
+        match self.kind() {
+            ConstKind::Param(p) => p.visit_with(visitor),
+            ConstKind::Infer(i) => i.visit_with(visitor),
+            ConstKind::Bound(d, b) => {
+                d.visit_with(visitor)?;
+                b.visit_with(visitor)
+            }
+            ConstKind::Placeholder(p) => p.visit_with(visitor),
+            ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
+            ConstKind::Value(v) => v.visit_with(visitor),
+            ConstKind::Error(e) => e.visit_with(visitor),
+            ConstKind::Expr(e) => e.visit_with(visitor),
+        }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index bb6d49e1773..9046570699e 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -33,6 +33,7 @@ use std::ops::{ControlFlow, Deref, Range};
 use ty::util::IntTypeExt;
 
 use rustc_type_ir::sty::TyKind::*;
+use rustc_type_ir::ConstKind as IrConstKind;
 use rustc_type_ir::RegionKind as IrRegionKind;
 use rustc_type_ir::TyKind as IrTyKind;
 
@@ -40,6 +41,7 @@ use rustc_type_ir::TyKind as IrTyKind;
 #[rustc_diagnostic_item = "TyKind"]
 pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
 pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
+pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index bb08deff294..46430125106 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1306,7 +1306,7 @@ pub fn needs_drop_components<'tcx>(
         ty::Array(elem_ty, size) => {
             match needs_drop_components(*elem_ty, target_layout) {
                 Ok(v) if v.is_empty() => Ok(v),
-                res => match size.kind().try_to_bits(target_layout.pointer_size) {
+                res => match size.try_to_bits(target_layout.pointer_size) {
                     // Arrays of size zero don't need drop, even if their element
                     // type does.
                     Some(0) => Ok(SmallVec::new()),
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 254ede4e6a0..ec7032cd3bf 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -230,7 +230,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
                 self.write_str("[")?;
                 self = self.print_type(ty)?;
                 self.write_str("; ")?;
-                if let Some(size) = size.kind().try_to_bits(self.tcx().data_layout.pointer_size) {
+                if let Some(size) = size.try_to_bits(self.tcx().data_layout.pointer_size) {
                     write!(self, "{size}")?
                 } else if let ty::ConstKind::Param(param) = size.kind() {
                     self = param.print(self)?
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 85825513ce9..2f978102ff2 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -112,7 +112,7 @@ fn encode_const<'tcx>(
         let _ = write!(s, "{value}");
     }
 
-    if let Some(scalar_int) = c.kind().try_to_scalar_int() {
+    if let Some(scalar_int) = c.try_to_scalar_int() {
         let signed = c.ty().is_signed();
         match scalar_int.size().bits() {
             8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0),
@@ -504,8 +504,7 @@ fn encode_ty<'tcx>(
             let _ = write!(
                 s,
                 "{}",
-                &len.kind()
-                    .try_to_scalar()
+                &len.try_to_scalar()
                     .unwrap()
                     .to_u64()
                     .unwrap_or_else(|_| panic!("failed to convert length to u64"))
@@ -815,7 +814,6 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
 
         ty::Array(ty0, len) => {
             let len = len
-                .kind()
                 .try_to_scalar()
                 .unwrap()
                 .to_u64()
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index c52ae4dc8e9..d1d5af48957 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -651,7 +651,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
                             .builtin_deref(true)
                             .expect("tried to dereference on non-ptr type")
                             .ty;
-                        // FIXME: add an assert that we only do this for valtrees.
+                        // FIXME(const_generics): add an assert that we only do this for valtrees.
                         let dereferenced_const = self.tcx.mk_ct_from_kind(ct.kind(), pointee_ty);
                         self = dereferenced_const.print(self)?;
                     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 10bd027b684..1e4d30f48b2 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -278,7 +278,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
             if let ty::Array(aty, len) = self_ty.kind() {
                 flags.push((sym::_Self, Some("[]".to_string())));
-                let len = len.kind().try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
+                let len = len.try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
                 flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
                 if let Some(n) = len {
                     flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 3d96c422256..2d8c260126d 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -528,7 +528,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         debug!("equating consts:\nc1= {:?}\nc2= {:?}", c1, c2);
 
                         use rustc_hir::def::DefKind;
-                        use ty::ConstKind::Unevaluated;
+                        use ty::Unevaluated;
                         match (c1.kind(), c2.kind()) {
                             (Unevaluated(a), Unevaluated(b))
                                 if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst =>
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 8f40aac58ad..26ed1481228 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -873,7 +873,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         );
 
                         use rustc_hir::def::DefKind;
-                        use ty::ConstKind::Unevaluated;
+                        use ty::Unevaluated;
                         match (c1.kind(), c2.kind()) {
                             (Unevaluated(a), Unevaluated(b))
                                 if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst =>
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index ae16fbb162e..878a6b784ed 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -57,11 +57,19 @@ pub trait Interner: Sized {
     type ParamTy: Clone + Debug + Hash + Ord;
     type BoundTy: Clone + Debug + Hash + Ord;
     type PlaceholderType: Clone + Debug + Hash + Ord;
-    type InferTy: Clone + Debug + Hash + Ord;
     type ErrorGuaranteed: Clone + Debug + Hash + Ord;
     type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
     type AllocId: Clone + Debug + Hash + Ord;
 
+    type InferConst: Clone + Debug + Hash + Ord;
+    type AliasConst: Clone + Debug + Hash + Ord;
+    type PlaceholderConst: Clone + Debug + Hash + Ord;
+    type ParamConst: Clone + Debug + Hash + Ord;
+    type BoundConst: Clone + Debug + Hash + Ord;
+    type InferTy: Clone + Debug + Hash + Ord;
+    type ValueConst: Clone + Debug + Hash + Ord;
+    type ExprConst: Clone + Debug + Hash + Ord;
+
     type EarlyBoundRegion: Clone + Debug + Hash + Ord;
     type BoundRegion: Clone + Debug + Hash + Ord;
     type FreeRegion: Clone + Debug + Hash + Ord;
diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs
index 553d7f31b2d..1e42175f6e3 100644
--- a/compiler/rustc_type_ir/src/structural_impls.rs
+++ b/compiler/rustc_type_ir/src/structural_impls.rs
@@ -4,7 +4,7 @@
 
 use crate::fold::{FallibleTypeFolder, TypeFoldable};
 use crate::visit::{TypeVisitable, TypeVisitor};
-use crate::{FloatTy, IntTy, Interner, UintTy};
+use crate::{ConstKind, FloatTy, IntTy, Interner, UintTy};
 use rustc_data_structures::functor::IdFunctor;
 use rustc_data_structures::sync::Lrc;
 use rustc_index::{Idx, IndexVec};
@@ -182,3 +182,21 @@ impl fmt::Debug for FloatTy {
         write!(f, "{}", self.name_str())
     }
 }
+
+impl<I: Interner> fmt::Debug for ConstKind<I> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        use ConstKind::*;
+        match self {
+            Param(param) => write!(f, "{param:?}"),
+            Infer(var) => write!(f, "{var:?}"),
+            Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()),
+            Placeholder(placeholder) => write!(f, "{placeholder:?}"),
+            Unevaluated(uv) => {
+                write!(f, "{uv:?}")
+            }
+            Value(valtree) => write!(f, "{valtree:?}"),
+            Error(_) => write!(f, "{{const error}}"),
+            Expr(expr) => write!(f, "{expr:?}"),
+        }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index f621673f1d6..b696f9b9b59 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -876,6 +876,224 @@ where
     }
 }
 
+/// Represents a constant in Rust.
+// #[derive(derive_more::From)]
+pub enum ConstKind<I: Interner> {
+    /// A const generic parameter.
+    Param(I::ParamConst),
+
+    /// Infer the value of the const.
+    Infer(I::InferConst),
+
+    /// Bound const variable, used only when preparing a trait query.
+    Bound(DebruijnIndex, I::BoundConst),
+
+    /// A placeholder const - universally quantified higher-ranked const.
+    Placeholder(I::PlaceholderConst),
+
+    /// An unnormalized const item such as an anon const or assoc const or free const item.
+    /// Right now anything other than anon consts does not actually work properly but this
+    /// should
+    Unevaluated(I::AliasConst),
+
+    /// Used to hold computed value.
+    Value(I::ValueConst),
+
+    /// A placeholder for a const which could not be computed; this is
+    /// propagated to avoid useless error messages.
+    Error(I::ErrorGuaranteed),
+
+    /// Unevaluated non-const-item, used by `feature(generic_const_exprs)` to represent
+    /// const arguments such as `N + 1` or `foo(N)`
+    Expr(I::ExprConst),
+}
+
+const fn const_kind_discriminant<I: Interner>(value: &ConstKind<I>) -> usize {
+    match value {
+        ConstKind::Param(_) => 0,
+        ConstKind::Infer(_) => 1,
+        ConstKind::Bound(_, _) => 2,
+        ConstKind::Placeholder(_) => 3,
+        ConstKind::Unevaluated(_) => 4,
+        ConstKind::Value(_) => 5,
+        ConstKind::Error(_) => 6,
+        ConstKind::Expr(_) => 7,
+    }
+}
+
+impl<I: Interner> hash::Hash for ConstKind<I> {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        const_kind_discriminant(self).hash(state);
+        match self {
+            ConstKind::Param(p) => p.hash(state),
+            ConstKind::Infer(i) => i.hash(state),
+            ConstKind::Bound(d, b) => {
+                d.hash(state);
+                b.hash(state);
+            }
+            ConstKind::Placeholder(p) => p.hash(state),
+            ConstKind::Unevaluated(u) => u.hash(state),
+            ConstKind::Value(v) => v.hash(state),
+            ConstKind::Error(e) => e.hash(state),
+            ConstKind::Expr(e) => e.hash(state),
+        }
+    }
+}
+
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ConstKind<I>
+where
+    I::ParamConst: HashStable<CTX>,
+    I::InferConst: HashStable<CTX>,
+    I::BoundConst: HashStable<CTX>,
+    I::PlaceholderConst: HashStable<CTX>,
+    I::AliasConst: HashStable<CTX>,
+    I::ValueConst: HashStable<CTX>,
+    I::ErrorGuaranteed: HashStable<CTX>,
+    I::ExprConst: HashStable<CTX>,
+{
+    fn hash_stable(
+        &self,
+        hcx: &mut CTX,
+        hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
+    ) {
+        const_kind_discriminant(self).hash_stable(hcx, hasher);
+        match self {
+            ConstKind::Param(p) => p.hash_stable(hcx, hasher),
+            ConstKind::Infer(i) => i.hash_stable(hcx, hasher),
+            ConstKind::Bound(d, b) => {
+                d.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher);
+            }
+            ConstKind::Placeholder(p) => p.hash_stable(hcx, hasher),
+            ConstKind::Unevaluated(u) => u.hash_stable(hcx, hasher),
+            ConstKind::Value(v) => v.hash_stable(hcx, hasher),
+            ConstKind::Error(e) => e.hash_stable(hcx, hasher),
+            ConstKind::Expr(e) => e.hash_stable(hcx, hasher),
+        }
+    }
+}
+
+impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for ConstKind<I>
+where
+    I::ParamConst: Decodable<D>,
+    I::InferConst: Decodable<D>,
+    I::BoundConst: Decodable<D>,
+    I::PlaceholderConst: Decodable<D>,
+    I::AliasConst: Decodable<D>,
+    I::ValueConst: Decodable<D>,
+    I::ErrorGuaranteed: Decodable<D>,
+    I::ExprConst: Decodable<D>,
+{
+    fn decode(d: &mut D) -> Self {
+        match Decoder::read_usize(d) {
+            0 => ConstKind::Param(Decodable::decode(d)),
+            1 => ConstKind::Infer(Decodable::decode(d)),
+            2 => ConstKind::Bound(Decodable::decode(d), Decodable::decode(d)),
+            3 => ConstKind::Placeholder(Decodable::decode(d)),
+            4 => ConstKind::Unevaluated(Decodable::decode(d)),
+            5 => ConstKind::Value(Decodable::decode(d)),
+            6 => ConstKind::Error(Decodable::decode(d)),
+            7 => ConstKind::Expr(Decodable::decode(d)),
+            _ => panic!(
+                "{}",
+                format!(
+                    "invalid enum variant tag while decoding `{}`, expected 0..{}",
+                    "ConstKind", 8,
+                )
+            ),
+        }
+    }
+}
+
+impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for ConstKind<I>
+where
+    I::ParamConst: Encodable<E>,
+    I::InferConst: Encodable<E>,
+    I::BoundConst: Encodable<E>,
+    I::PlaceholderConst: Encodable<E>,
+    I::AliasConst: Encodable<E>,
+    I::ValueConst: Encodable<E>,
+    I::ErrorGuaranteed: Encodable<E>,
+    I::ExprConst: Encodable<E>,
+{
+    fn encode(&self, e: &mut E) {
+        let disc = const_kind_discriminant(self);
+        match self {
+            ConstKind::Param(p) => e.emit_enum_variant(disc, |e| p.encode(e)),
+            ConstKind::Infer(i) => e.emit_enum_variant(disc, |e| i.encode(e)),
+            ConstKind::Bound(d, b) => e.emit_enum_variant(disc, |e| {
+                d.encode(e);
+                b.encode(e);
+            }),
+            ConstKind::Placeholder(p) => e.emit_enum_variant(disc, |e| p.encode(e)),
+            ConstKind::Unevaluated(u) => e.emit_enum_variant(disc, |e| u.encode(e)),
+            ConstKind::Value(v) => e.emit_enum_variant(disc, |e| v.encode(e)),
+            ConstKind::Error(er) => e.emit_enum_variant(disc, |e| er.encode(e)),
+            ConstKind::Expr(ex) => e.emit_enum_variant(disc, |e| ex.encode(e)),
+        }
+    }
+}
+
+impl<I: Interner> PartialOrd for ConstKind<I> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl<I: Interner> Ord for ConstKind<I> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        const_kind_discriminant(self)
+            .cmp(&const_kind_discriminant(other))
+            .then_with(|| match (self, other) {
+                (ConstKind::Param(p1), ConstKind::Param(p2)) => p1.cmp(p2),
+                (ConstKind::Infer(i1), ConstKind::Infer(i2)) => i1.cmp(i2),
+                (ConstKind::Bound(d1, b1), ConstKind::Bound(d2, b2)) => d1.cmp(d2).then_with(|| b1.cmp(b2)),
+                (ConstKind::Placeholder(p1), ConstKind::Placeholder(p2)) => p1.cmp(p2),
+                (ConstKind::Unevaluated(u1), ConstKind::Unevaluated(u2)) => u1.cmp(u2),
+                (ConstKind::Value(v1), ConstKind::Value(v2)) => v1.cmp(v2),
+                (ConstKind::Error(e1), ConstKind::Error(e2)) => e1.cmp(e2),
+                (ConstKind::Expr(e1), ConstKind::Expr(e2)) => e1.cmp(e2),
+                _ => {
+                    debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}");
+                    Ordering::Equal
+                }
+            })
+    }
+}
+
+impl<I: Interner> PartialEq for ConstKind<I> {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (Self::Param(l0), Self::Param(r0)) => l0 == r0,
+            (Self::Infer(l0), Self::Infer(r0)) => l0 == r0,
+            (Self::Bound(l0, l1), Self::Bound(r0, r1)) => l0 == r0 && l1 == r1,
+            (Self::Placeholder(l0), Self::Placeholder(r0)) => l0 == r0,
+            (Self::Unevaluated(l0), Self::Unevaluated(r0)) => l0 == r0,
+            (Self::Value(l0), Self::Value(r0)) => l0 == r0,
+            (Self::Error(l0), Self::Error(r0)) => l0 == r0,
+            (Self::Expr(l0), Self::Expr(r0)) => l0 == r0,
+            _ => false,
+        }
+    }
+}
+
+impl<I: Interner> Eq for ConstKind<I> {}
+
+impl<I: Interner> Clone for ConstKind<I> {
+    fn clone(&self) -> Self {
+        match self {
+            Self::Param(arg0) => Self::Param(arg0.clone()),
+            Self::Infer(arg0) => Self::Infer(arg0.clone()),
+            Self::Bound(arg0, arg1) => Self::Bound(arg0.clone(), arg1.clone()),
+            Self::Placeholder(arg0) => Self::Placeholder(arg0.clone()),
+            Self::Unevaluated(arg0) => Self::Unevaluated(arg0.clone()),
+            Self::Value(arg0) => Self::Value(arg0.clone()),
+            Self::Error(arg0) => Self::Error(arg0.clone()),
+            Self::Expr(arg0) => Self::Expr(arg0.clone()),
+        }
+    }
+}
+
 /// Representation of regions. Note that the NLL checker uses a distinct
 /// representation of regions. For this reason, it internally replaces all the
 /// regions with inference variables -- the index of the variable is then used
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index dd3cda8ec52..1e1bb2a1d96 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -689,7 +689,7 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t
         mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() {
             ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
             ty::Array(sub_type, len) => match sub_type.kind() {
-                ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(lcx.tcx) {
+                ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) {
                     Some(len) => alloc
                         .inner()
                         .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
@@ -700,7 +700,7 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t
                         .map(Constant::Vec),
                     _ => None,
                 },
-                ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(lcx.tcx) {
+                ty::Float(FloatTy::F64) => match len.try_to_target_usize(lcx.tcx) {
                     Some(len) => alloc
                         .inner()
                         .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap()))
diff --git a/tests/mir-opt/issue_99325.main.built.after.mir b/tests/mir-opt/issue_99325.main.built.after.mir
index d8a88a0635c..0fe66d3fb70 100644
--- a/tests/mir-opt/issue_99325.main.built.after.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.mir
@@ -2,7 +2,7 @@
 
 | User Type Annotations
 | 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated([], DefId(0:8 ~ issue_99325[22bb]::main::{constant#1})) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), substs: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
 |
 fn main() -> () {
     let mut _0: ();