restore the old logic adjusting ty::UnevaluatedConst before evaluation
This commit is contained in:
parent
11a4a24d8e
commit
8ef6b7a417
@ -2336,18 +2336,19 @@ impl<'tcx> ConstantKind<'tcx> {
|
|||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
) -> Result<interpret::ConstValue<'tcx>, ErrorHandled> {
|
) -> Result<interpret::ConstValue<'tcx>, ErrorHandled> {
|
||||||
let uneval = match self {
|
let (uneval, param_env) = match self {
|
||||||
ConstantKind::Ty(c) => {
|
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.
|
// 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 {
|
} else {
|
||||||
// It's already a valtree, or an error.
|
// It's already a valtree, or an error.
|
||||||
let val = c.eval(tcx, param_env, span)?;
|
let val = c.eval(tcx, param_env, span)?;
|
||||||
return Ok(tcx.valtree_to_const_val((self.ty(), val)));
|
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),
|
ConstantKind::Val(val, _) => return Ok(val),
|
||||||
};
|
};
|
||||||
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
|
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
|
||||||
|
@ -276,6 +276,7 @@ impl<'tcx> Const<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the evaluated constant
|
/// Returns the evaluated constant
|
||||||
|
#[inline]
|
||||||
pub fn eval(
|
pub fn eval(
|
||||||
self,
|
self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
@ -285,32 +286,9 @@ impl<'tcx> Const<'tcx> {
|
|||||||
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
|
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
ConstKind::Unevaluated(unevaluated) => {
|
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
|
// FIXME(eddyb) maybe the `const_eval_*` methods should take
|
||||||
// `ty::ParamEnvAnd` instead of having them separate.
|
// `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
|
// try to resolve e.g. associated constants to their definition on an impl, and then
|
||||||
// evaluate the const.
|
// evaluate the const.
|
||||||
let c = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?;
|
let c = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?;
|
||||||
|
@ -2,7 +2,7 @@ use super::Const;
|
|||||||
use crate::mir;
|
use crate::mir;
|
||||||
use crate::ty::abstract_const::CastKind;
|
use crate::ty::abstract_const::CastKind;
|
||||||
use crate::ty::GenericArgsRef;
|
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_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
@ -26,6 +26,39 @@ impl<'tcx> UnevaluatedConst<'tcx> {
|
|||||||
pub fn expand(self) -> mir::UnevaluatedConst<'tcx> {
|
pub fn expand(self) -> mir::UnevaluatedConst<'tcx> {
|
||||||
mir::UnevaluatedConst { def: self.def, args: self.args, promoted: None }
|
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> {
|
impl<'tcx> UnevaluatedConst<'tcx> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user