Consolidate type system const evaluation under traits::evaluate_const
mew
This commit is contained in:
parent
81eef2d362
commit
bea0148ac6
31 changed files with 434 additions and 569 deletions
|
@ -1,17 +1,17 @@
|
|||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
|
||||
use either::Either;
|
||||
use rustc_abi::{HasDataLayout, Size};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
|
||||
use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range};
|
||||
use crate::mir::{Promoted, pretty_print_const_value};
|
||||
use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
|
||||
use crate::ty::{self, GenericArgsRef, ScalarInt, Ty, TyCtxt};
|
||||
use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Evaluated Constants
|
||||
|
@ -319,15 +319,13 @@ impl<'tcx> Const<'tcx> {
|
|||
) -> Result<ConstValue<'tcx>, ErrorHandled> {
|
||||
match self {
|
||||
Const::Ty(_, c) => {
|
||||
// We want to consistently have a "clean" value for type system constants (i.e., no
|
||||
// data hidden in the padding), so we always go through a valtree here.
|
||||
match c.eval_valtree(tcx, param_env, span) {
|
||||
Ok((ty, val)) => Ok(tcx.valtree_to_const_val((ty, val))),
|
||||
Err(Either::Left(_bad_ty)) => Err(tcx
|
||||
.dcx()
|
||||
.delayed_bug("`mir::Const::eval` called on a non-valtree-compatible type")
|
||||
.into()),
|
||||
Err(Either::Right(e)) => Err(e),
|
||||
if c.has_non_region_param() {
|
||||
return Err(ErrorHandled::TooGeneric(span));
|
||||
}
|
||||
|
||||
match c.kind() {
|
||||
ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))),
|
||||
_ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()),
|
||||
}
|
||||
}
|
||||
Const::Unevaluated(uneval, _) => {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use either::Either;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_error_messages::MultiSpan;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
@ -9,7 +8,7 @@ use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::middle::resolve_bound_vars as rbv;
|
||||
use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
|
||||
use crate::mir::interpret::{LitToConstInput, Scalar};
|
||||
use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||
|
||||
mod int;
|
||||
|
@ -18,7 +17,7 @@ mod valtree;
|
|||
|
||||
pub use int::*;
|
||||
pub use kind::*;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed};
|
||||
pub use valtree::*;
|
||||
|
||||
pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
|
||||
|
@ -363,60 +362,6 @@ impl<'tcx> Const<'tcx> {
|
|||
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
|
||||
}
|
||||
|
||||
/// Returns the evaluated constant as a valtree;
|
||||
/// if that fails due to a valtree-incompatible type, indicate which type that is
|
||||
/// by returning `Err(Left(bad_type))`.
|
||||
#[inline]
|
||||
pub fn eval_valtree(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<(Ty<'tcx>, ValTree<'tcx>), Either<Ty<'tcx>, ErrorHandled>> {
|
||||
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
|
||||
match self.kind() {
|
||||
ConstKind::Unevaluated(unevaluated) => {
|
||||
// FIXME(eddyb) maybe the `const_eval_*` methods should take
|
||||
// `ty::ParamEnvAnd` instead of having them separate.
|
||||
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.
|
||||
match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span) {
|
||||
Ok(Ok(c)) => {
|
||||
Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c))
|
||||
}
|
||||
Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)),
|
||||
Err(err) => Err(Either::Right(err)),
|
||||
}
|
||||
}
|
||||
ConstKind::Value(ty, val) => Ok((ty, val)),
|
||||
ConstKind::Error(g) => Err(Either::Right(g.into())),
|
||||
ConstKind::Param(_)
|
||||
| ConstKind::Infer(_)
|
||||
| ConstKind::Bound(_, _)
|
||||
| ConstKind::Placeholder(_)
|
||||
| ConstKind::Expr(_) => Err(Either::Right(ErrorHandled::TooGeneric(span))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Normalizes the constant to a value or an error if possible.
|
||||
#[inline]
|
||||
pub fn normalize_internal(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
|
||||
match self.eval_valtree(tcx, param_env, DUMMY_SP) {
|
||||
Ok((ty, val)) => Self::new_value(tcx, val, ty),
|
||||
Err(Either::Left(_bad_ty)) => {
|
||||
// This can happen when we run on ill-typed code.
|
||||
Self::new_error(
|
||||
tcx,
|
||||
tcx.dcx()
|
||||
.delayed_bug("`ty::Const::eval` called on a non-valtree-compatible type"),
|
||||
)
|
||||
}
|
||||
Err(Either::Right(ErrorHandled::Reported(r, _span))) => Self::new_error(tcx, r.into()),
|
||||
Err(Either::Right(ErrorHandled::TooGeneric(_span))) => self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Panics if self.kind != ty::ConstKind::Value
|
||||
pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) {
|
||||
match self.kind() {
|
||||
|
|
|
@ -1,46 +1,12 @@
|
|||
use std::assert_matches::assert_matches;
|
||||
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
|
||||
use super::Const;
|
||||
use crate::mir;
|
||||
use crate::ty::abstract_const::CastKind;
|
||||
use crate::ty::visit::TypeVisitableExt as _;
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
|
||||
#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)]
|
||||
impl<'tcx> ty::UnevaluatedConst<'tcx> {
|
||||
/// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
|
||||
/// hurts performance.
|
||||
#[inline]
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
|
||||
pub enum ExprKind {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue