about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2023-09-12 23:28:25 +0200
committerRalf Jung <post@ralfj.de>2023-09-13 07:29:34 +0200
commit6e4779ab1775d0901408c08d64dc12c735069701 (patch)
treec9b26f901b489aa15840a10b12556ea3a7b87b7a
parente5fedceabf4e0564231db592b6d1f35e1ca27908 (diff)
make the eval() functions on our const types return the resulting value
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs30
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs52
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs97
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs187
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs8
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_transmute/src/lib.rs11
-rw-r--r--src/librustdoc/clean/mod.rs4
16 files changed, 169 insertions, 247 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 9159bc36987..54f82dcc8ae 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -723,11 +723,8 @@ fn codegen_stmt<'tcx>(
                 }
                 Rvalue::Repeat(ref operand, times) => {
                     let operand = codegen_operand(fx, operand);
-                    let times = fx
-                        .monomorphize(times)
-                        .eval(fx.tcx, ParamEnv::reveal_all())
-                        .try_to_bits(fx.tcx.data_layout.pointer_size)
-                        .unwrap();
+                    let times =
+                        fx.monomorphize(times).eval_target_usize(fx.tcx, ParamEnv::reveal_all());
                     if operand.layout().size.bytes() == 0 {
                         // Do nothing for ZST's
                     } else if fx.clif_type(operand.layout().ty) == Some(types::I8) {
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index a934b0767f1..b9d4bc9ff29 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -77,31 +77,9 @@ pub(crate) fn eval_mir_constant<'tcx>(
     fx: &FunctionCx<'_, '_, 'tcx>,
     constant: &Constant<'tcx>,
 ) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> {
-    let constant_kind = fx.monomorphize(constant.literal);
-    let uv = match constant_kind {
-        ConstantKind::Ty(const_) => match const_.kind() {
-            ty::ConstKind::Unevaluated(uv) => uv.expand(),
-            ty::ConstKind::Value(val) => {
-                return Some((fx.tcx.valtree_to_const_val((const_.ty(), val)), const_.ty()));
-            }
-            err => span_bug!(
-                constant.span,
-                "encountered bad ConstKind after monomorphizing: {:?}",
-                err
-            ),
-        },
-        ConstantKind::Unevaluated(mir::UnevaluatedConst { def, .. }, _)
-            if fx.tcx.is_static(def) =>
-        {
-            span_bug!(constant.span, "MIR constant refers to static");
-        }
-        ConstantKind::Unevaluated(uv, _) => uv,
-        ConstantKind::Val(val, _) => return Some((val, constant_kind.ty())),
-    };
-
-    let val = fx
-        .tcx
-        .const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None)
+    let cv = fx.monomorphize(constant.literal);
+    let val = cv
+        .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
         .map_err(|err| match err {
             ErrorHandled::Reported(_) => {
                 fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
@@ -111,7 +89,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
             }
         })
         .ok();
-    val.map(|val| (val, constant_kind.ty()))
+    val.map(|val| (val, cv.ty()))
 }
 
 pub(crate) fn codegen_constant_operand<'tcx>(
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 067c824aba0..02f022b9454 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -670,10 +670,8 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
                 // avoiding collisions and will make the emitted type names shorter.
                 let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
                     let mut hasher = StableHasher::new();
-                    let ct = ct.eval(tcx, ty::ParamEnv::reveal_all());
-                    hcx.while_hashing_spans(false, |hcx| {
-                        ct.to_valtree().hash_stable(hcx, &mut hasher)
-                    });
+                    let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), None).unwrap();
+                    hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher));
                     hasher.finish::<Hash64>()
                 });
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index babcf9bee24..4d7bd60ceca 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -24,43 +24,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         &self,
         constant: &mir::Constant<'tcx>,
     ) -> Result<ConstValue<'tcx>, ErrorHandled> {
-        let ct = self.monomorphize(constant.literal);
-        let uv = match ct {
-            mir::ConstantKind::Ty(ct) => match ct.kind() {
-                ty::ConstKind::Unevaluated(uv) => uv.expand(),
-                ty::ConstKind::Value(val) => {
-                    return Ok(self.cx.tcx().valtree_to_const_val((ct.ty(), val)));
+        self.monomorphize(constant.literal)
+            .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
+            .map_err(|err| {
+                match err {
+                    ErrorHandled::Reported(_) => {
+                        self.cx
+                            .tcx()
+                            .sess
+                            .emit_err(errors::ErroneousConstant { span: constant.span });
+                    }
+                    ErrorHandled::TooGeneric => {
+                        self.cx.tcx().sess.diagnostic().emit_bug(
+                            errors::PolymorphicConstantTooGeneric { span: constant.span },
+                        );
+                    }
                 }
-                err => span_bug!(
-                    constant.span,
-                    "encountered bad ConstKind after monomorphizing: {:?}",
-                    err
-                ),
-            },
-            mir::ConstantKind::Unevaluated(uv, _) => uv,
-            mir::ConstantKind::Val(val, _) => return Ok(val),
-        };
-
-        self.cx.tcx().const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).map_err(|err| {
-            match err {
-                ErrorHandled::Reported(_) => {
-                    self.cx.tcx().sess.emit_err(errors::ErroneousConstant { span: constant.span });
-                }
-                ErrorHandled::TooGeneric => {
-                    self.cx
-                        .tcx()
-                        .sess
-                        .diagnostic()
-                        .emit_bug(errors::PolymorphicConstantTooGeneric { span: constant.span });
-                }
-            }
-            err
-        })
+                err
+            })
     }
 
     /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
     /// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to
     /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
+    ///
+    /// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees!
     pub fn eval_unevaluated_mir_constant_to_valtree(
         &self,
         constant: &mir::Constant<'tcx>,
@@ -80,7 +68,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             // `simd_shuffle` call without wrapping the constant argument in a `const {}` block, but
             // the user pass through arbitrary expressions.
             // FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a real
-            // const generic.
+            // const generic, and get rid of this entire function.
             other => span_bug!(constant.span, "{other:#?}"),
         };
         let uv = self.monomorphize(uv);
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 76ac2b2ac60..7e3be0b5d5f 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -71,6 +71,8 @@ TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
 
 pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
 pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
+/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed.
+/// This is needed in `thir::pattern::lower_inline_const`.
 pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
 
 pub fn struct_error<'tcx>(
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 3d45b4bdc33..570676ec4e3 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2342,29 +2342,39 @@ impl<'tcx> ConstantKind<'tcx> {
     }
 
     #[inline]
-    pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
-        match self {
-            Self::Ty(c) => {
-                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())),
-                    }
+    pub fn eval(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        span: Option<Span>,
+    ) -> Result<interpret::ConstValue<'tcx>, ErrorHandled> {
+        let uneval = match self {
+            ConstantKind::Ty(c) => {
+                if let ty::ConstKind::Unevaluated(uv) = c.kind() {
+                    // Avoid the round-trip via valtree, evaluate directly to ConstValue.
+                    uv.expand()
                 } else {
-                    self
+                    // It's already a valtree, or an error.
+                    let val = c.eval(tcx, param_env, span)?;
+                    return Ok(tcx.valtree_to_const_val((self.ty(), val)));
                 }
             }
-            Self::Val(_, _) => self,
-            Self::Unevaluated(uneval, ty) => {
-                // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
-                match tcx.const_eval_resolve(param_env, uneval, None) {
-                    Ok(val) => Self::Val(val, ty),
-                    Err(ErrorHandled::TooGeneric) => self,
-                    Err(ErrorHandled::Reported(guar)) => {
-                        Self::Ty(ty::Const::new_error(tcx, guar.into(), ty))
-                    }
-                }
+            ConstantKind::Unevaluated(uneval, _) => uneval,
+            ConstantKind::Val(val, _) => return Ok(val),
+        };
+        // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
+        tcx.const_eval_resolve(param_env, uneval, span)
+    }
+
+    /// Normalizes the constant to a value or an error if possible.
+    #[inline]
+    pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+        match self.eval(tcx, param_env, None) {
+            Ok(val) => Self::Val(val, self.ty()),
+            Err(ErrorHandled::Reported(guar)) => {
+                Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
             }
+            Err(ErrorHandled::TooGeneric) => self,
         }
     }
 
@@ -2406,35 +2416,35 @@ impl<'tcx> ConstantKind<'tcx> {
     }
 
     #[inline]
-    pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
-        match self {
-            Self::Ty(ct) => ct.try_eval_bool(tcx, param_env),
-            Self::Val(val, _) => val.try_to_bool(),
-            Self::Unevaluated(uneval, _) => {
-                match tcx.const_eval_resolve(param_env, *uneval, None) {
-                    Ok(val) => val.try_to_bool(),
-                    Err(_) => None,
-                }
-            }
-        }
+    pub fn try_eval_scalar(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Option<Scalar> {
+        self.eval(tcx, param_env, None).ok()?.try_to_scalar()
+    }
+
+    #[inline]
+    pub fn try_eval_scalar_int(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Option<ScalarInt> {
+        self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
+    }
+
+    #[inline]
+    pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
+        self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
     }
 
     #[inline]
     pub fn try_eval_target_usize(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Option<u64> {
-        match self {
-            Self::Ty(ct) => ct.try_eval_target_usize(tcx, param_env),
-            Self::Val(val, _) => val.try_to_target_usize(tcx),
-            Self::Unevaluated(uneval, _) => {
-                match tcx.const_eval_resolve(param_env, *uneval, None) {
-                    Ok(val) => val.try_to_target_usize(tcx),
-                    Err(_) => None,
-                }
-            }
-        }
+        self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
     }
 
     #[inline]
@@ -2610,6 +2620,11 @@ impl<'tcx> UnevaluatedConst<'tcx> {
     pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
         UnevaluatedConst { def, args, promoted: Default::default() }
     }
+
+    #[inline]
+    pub fn from_instance(instance: ty::Instance<'tcx>) -> Self {
+        UnevaluatedConst::new(instance.def_id(), instance.args)
+    }
 }
 
 /// A collection of projections into user types.
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index cce10417e1b..61e9000273f 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,5 +1,5 @@
 use crate::middle::resolve_bound_vars as rbv;
-use crate::mir::interpret::{AllocId, ConstValue, LitToConstInput, Scalar};
+use crate::mir::interpret::{AllocId, ErrorHandled, LitToConstInput, Scalar};
 use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 use rustc_data_structures::intern::Interned;
 use rustc_error_messages::MultiSpan;
@@ -14,7 +14,7 @@ mod valtree;
 
 pub use int::*;
 pub use kind::*;
-use rustc_span::ErrorGuaranteed;
+use rustc_span::Span;
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::Size;
 pub use valtree::*;
@@ -36,16 +36,6 @@ 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> {
@@ -306,21 +296,34 @@ impl<'tcx> Const<'tcx> {
     /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
     /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
     /// contains const generic parameters or pointers).
+    pub fn try_eval_scalar_int(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+    ) -> Option<ScalarInt> {
+        self.eval(tcx, param_env, None).ok()?.try_to_scalar_int()
+    }
+
+    #[inline]
+    /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
+    /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
+    /// contains const generic parameters or pointers).
     pub fn try_eval_bits(
         self,
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
         ty: Ty<'tcx>,
     ) -> Option<u128> {
+        let int = self.try_eval_scalar_int(tcx, param_env)?;
         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.eval(tcx, param_env).try_to_bits(size)
+        int.to_bits(size).ok()
     }
 
     #[inline]
     pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
-        self.eval(tcx, param_env).try_to_bool()
+        self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
     }
 
     #[inline]
@@ -329,21 +332,16 @@ impl<'tcx> Const<'tcx> {
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
     ) -> Option<u64> {
-        self.eval(tcx, param_env).try_to_target_usize(tcx)
+        self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
     }
 
+    /// Normalizes the constant to a value or an error if possible.
     #[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.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()),
-            }
-        } else {
-            // Either the constant isn't evaluatable or ValTree creation failed.
-            self
+    pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
+        match self.eval(tcx, param_env, None) {
+            Ok(val) => Self::new_value(tcx, val, self.ty()),
+            Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()),
+            Err(ErrorHandled::TooGeneric) => self,
         }
     }
 
@@ -361,105 +359,54 @@ 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(
+    /// Returns the evaluated constant
+    pub fn eval(
         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>> {
+        span: Option<Span>,
+    ) -> Result<ValTree<'tcx>, ErrorHandled> {
         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 args 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,
-                    args: GenericArgs::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 `args`
-                        // (which may be identity args, 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 `args`
-                        // (which may be identity args, 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())),
-                    }
-                }
+        match self.kind() {
+            ConstKind::Unevaluated(unevaluated) => {
+                // 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 args 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,
+                        args: GenericArgs::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.
+                let c = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?;
+                Ok(c.expect("`ty::Const::eval` called on a non-valtree-compatible type"))
             }
-        } else {
-            None
+            ConstKind::Value(val) => Ok(val),
+            ConstKind::Error(g) => Err(g.into()),
+            ConstKind::Param(_)
+            | ConstKind::Infer(_)
+            | ConstKind::Bound(_, _)
+            | ConstKind::Placeholder(_)
+            | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric),
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 7736183027f..c184154eacf 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -626,6 +626,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args: args };
         // First try using a valtree in order to destructure the constant into a pattern.
+        // FIXME: replace "try to do a thing, then fall back to another thing"
+        // but something more principled, like a trait query checking whether this can be turned into a valtree.
         if let Ok(Some(valtree)) =
             self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
         {
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 13550672ecc..11da9612f2f 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -209,7 +209,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     && let operand_ty = operand.ty(self.local_decls, self.tcx)
                     && let Some(operand_ty) = operand_ty.builtin_deref(true)
                     && let ty::Array(_, len) = operand_ty.ty.kind()
-                    && let Some(len) = ConstantKind::Ty(*len).eval(self.tcx, self.param_env).try_to_scalar_int()
+                    && let Some(len) = ConstantKind::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env)
                 {
                     state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map());
                 }
@@ -228,8 +228,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 let place_ty = place.ty(self.local_decls, self.tcx);
                 if let ty::Array(_, len) = place_ty.ty.kind() {
                     ConstantKind::Ty(*len)
-                        .eval(self.tcx, self.param_env)
-                        .try_to_scalar()
+                        .try_eval_scalar(self.tcx, self.param_env)
                         .map_or(FlatSet::Top, FlatSet::Elem)
                 } else if let [ProjectionElem::Deref] = place.projection[..] {
                     state.get_len(place.local.into(), self.map())
@@ -304,8 +303,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
     ) -> Self::Value {
         constant
             .literal
-            .eval(self.tcx, self.param_env)
-            .try_to_scalar()
+            .try_eval_scalar(self.tcx, self.param_env)
             .map_or(FlatSet::Top, FlatSet::Elem)
     }
 
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index da19a3ba4fd..2550570af65 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -562,7 +562,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
 
     fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
         // We only mangle a typed value if the const can be evaluated.
-        let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all());
+        let ct = ct.normalize(self.tcx, ty::ParamEnv::reveal_all());
         match ct.kind() {
             ty::ConstKind::Value(_) => {}
 
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 e4f5c4003c9..135410691f1 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2054,7 +2054,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     tcx: self.tcx,
                     ty_op: |ty| ty,
                     lt_op: |lt| lt,
-                    ct_op: |ct| ct.eval(self.tcx, ty::ParamEnv::empty()),
+                    ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
                 });
                 cand
             })
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index d2210c6d5d9..956f8e047d7 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -288,7 +288,7 @@ pub fn normalize_param_env_or_error<'tcx>(
                     // should actually be okay since without `feature(generic_const_exprs)` the only
                     // const arguments that have a non-empty param env are array repeat counts. These
                     // do not appear in the type system though.
-                    c.eval(self.0, ty::ParamEnv::empty())
+                    c.normalize(self.0, ty::ParamEnv::empty())
                 }
             }
 
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index b31c0e655fb..6444c01a67b 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -761,7 +761,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
                 self.selcx.infcx,
                 &mut self.universes,
                 constant,
-                |constant| constant.eval(tcx, self.param_env),
+                |constant| constant.normalize(tcx, self.param_env),
             )
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 87beaddc6c2..f785211c548 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -358,7 +358,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
             self.infcx,
             &mut self.universes,
             constant,
-            |constant| constant.eval(self.infcx.tcx, self.param_env),
+            |constant| constant.normalize(self.infcx.tcx, self.param_env),
         ))
     }
 
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index af2ad547480..6c49e94dc31 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -129,19 +129,16 @@ mod rustc {
             c: Const<'tcx>,
         ) -> Option<Self> {
             use rustc_middle::ty::ScalarInt;
-            use rustc_middle::ty::TypeVisitableExt;
             use rustc_span::symbol::sym;
 
-            let c = c.eval(tcx, param_env);
-
-            if let Err(err) = c.error_reported() {
+            let Ok(cv) = c.eval(tcx, param_env, None) else {
                 return Some(Self {
                     alignment: true,
                     lifetimes: true,
                     safety: true,
                     validity: true,
                 });
-            }
+            };
 
             let adt_def = c.ty().ty_adt_def()?;
 
@@ -153,8 +150,8 @@ mod rustc {
             );
 
             let variant = adt_def.non_enum_variant();
-            let fields = match c.try_to_valtree() {
-                Some(ValTree::Branch(branch)) => branch,
+            let fields = match cv {
+                ValTree::Branch(branch) => branch,
                 _ => {
                     return Some(Self {
                         alignment: true,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f30384701cb..190b1b038b6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1863,7 +1863,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
                     // does nothing for `ConstKind::Param`.
                     let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id);
                     let param_env = cx.tcx.param_env(anon_const.def_id);
-                    print_const(cx, ct.eval(cx.tcx, param_env))
+                    print_const(cx, ct.normalize(cx.tcx, param_env))
                 }
             };
 
@@ -2082,7 +2082,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Str => Primitive(PrimitiveType::Str),
         ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))),
         ty::Array(ty, mut n) => {
-            n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
+            n = n.normalize(cx.tcx, ty::ParamEnv::reveal_all());
             let n = print_const(cx, n);
             Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into())
         }