about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs9
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs26
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs35
3 files changed, 41 insertions, 29 deletions
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index d56f2246c99..c5f0280e617 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2336,18 +2336,19 @@ impl<'tcx> ConstantKind<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         span: Option<Span>,
     ) -> Result<interpret::ConstValue<'tcx>, ErrorHandled> {
-        let uneval = match self {
+        let (uneval, param_env) = match self {
             ConstantKind::Ty(c) => {
-                if let ty::ConstKind::Unevaluated(uv) = c.kind() {
+                if let ty::ConstKind::Unevaluated(uneval) = c.kind() {
                     // Avoid the round-trip via valtree, evaluate directly to ConstValue.
-                    uv.expand()
+                    let (param_env, uneval) = uneval.prepare_for_eval(tcx, param_env);
+                    (uneval.expand(), param_env)
                 } else {
                     // 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)));
                 }
             }
-            ConstantKind::Unevaluated(uneval, _) => uneval,
+            ConstantKind::Unevaluated(uneval, _) => (uneval, param_env),
             ConstantKind::Val(val, _) => return Ok(val),
         };
         // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 86d1e463ed1..629f9f8cd7d 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -276,6 +276,7 @@ impl<'tcx> Const<'tcx> {
     }
 
     /// Returns the evaluated constant
+    #[inline]
     pub fn eval(
         self,
         tcx: TyCtxt<'tcx>,
@@ -285,32 +286,9 @@ impl<'tcx> Const<'tcx> {
         assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
         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();
+                let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
                 // 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)?;
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 17fbbd7c6b7..a0a7331a37e 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -2,7 +2,7 @@ use super::Const;
 use crate::mir;
 use crate::ty::abstract_const::CastKind;
 use crate::ty::GenericArgsRef;
-use crate::ty::{self, List, Ty};
+use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
@@ -26,6 +26,39 @@ impl<'tcx> UnevaluatedConst<'tcx> {
     pub fn expand(self) -> mir::UnevaluatedConst<'tcx> {
         mir::UnevaluatedConst { def: self.def, args: self.args, promoted: None }
     }
+
+    /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
+    /// hurts performance.
+    #[inline]
+    pub(crate) fn prepare_for_eval(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> (ty::ParamEnv<'tcx>, Self) {
+        // 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.
+        if (param_env, self).has_non_region_infer() {
+            (
+                tcx.param_env(self.def),
+                ty::UnevaluatedConst {
+                    def: self.def,
+                    args: ty::GenericArgs::identity_for_item(tcx, self.def),
+                },
+            )
+        } else {
+            (tcx.erase_regions(param_env).with_reveal_all_normalized(tcx), tcx.erase_regions(self))
+        }
+    }
 }
 
 impl<'tcx> UnevaluatedConst<'tcx> {