Skip to content

Commit bea0148

Browse files
committed
Consolidate type system const evaluation under traits::evaluate_const
mew
1 parent 81eef2d commit bea0148

File tree

31 files changed

+434
-569
lines changed

31 files changed

+434
-569
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1491,7 +1491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14911491
}
14921492
}
14931493
} else if self.tcx.features().generic_const_exprs() {
1494-
ct.normalize_internal(self.tcx, self.param_env)
1494+
rustc_trait_selection::traits::evaluate_const(&self.infcx, ct, self.param_env)
14951495
} else {
14961496
ct
14971497
}

compiler/rustc_infer/src/infer/mod.rs

+1-135
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ use rustc_hir as hir;
2525
use rustc_hir::def_id::{DefId, LocalDefId};
2626
use rustc_macros::extension;
2727
pub use rustc_macros::{TypeFoldable, TypeVisitable};
28+
use rustc_middle::bug;
2829
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
2930
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
3031
use rustc_middle::mir::ConstraintCategory;
31-
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
3232
use rustc_middle::traits::select;
3333
pub use rustc_middle::ty::IntVarValue;
3434
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -40,7 +40,6 @@ use rustc_middle::ty::{
4040
self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
4141
GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode,
4242
};
43-
use rustc_middle::{bug, span_bug};
4443
use rustc_span::Span;
4544
use rustc_span::symbol::Symbol;
4645
use rustc_type_ir::solve::Reveal;
@@ -1279,84 +1278,6 @@ impl<'tcx> InferCtxt<'tcx> {
12791278
u
12801279
}
12811280

1282-
pub fn try_const_eval_resolve(
1283-
&self,
1284-
param_env: ty::ParamEnv<'tcx>,
1285-
unevaluated: ty::UnevaluatedConst<'tcx>,
1286-
span: Span,
1287-
) -> Result<ty::Const<'tcx>, ErrorHandled> {
1288-
match self.const_eval_resolve(param_env, unevaluated, span) {
1289-
Ok(Ok(val)) => Ok(ty::Const::new_value(
1290-
self.tcx,
1291-
val,
1292-
self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
1293-
)),
1294-
Ok(Err(bad_ty)) => {
1295-
let tcx = self.tcx;
1296-
let def_id = unevaluated.def;
1297-
span_bug!(
1298-
tcx.def_span(def_id),
1299-
"unable to construct a valtree for the unevaluated constant {:?}: type {bad_ty} is not valtree-compatible",
1300-
unevaluated
1301-
);
1302-
}
1303-
Err(err) => Err(err),
1304-
}
1305-
}
1306-
1307-
/// Resolves and evaluates a constant.
1308-
///
1309-
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
1310-
/// generic parameters and environment are used to resolve the constant. Alternatively if the
1311-
/// constant has generic parameters in scope the instantiations are used to evaluate the value
1312-
/// of the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
1313-
/// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is
1314-
/// still too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
1315-
/// returned.
1316-
///
1317-
/// This handles inferences variables within both `param_env` and `args` by
1318-
/// performing the operation on their respective canonical forms.
1319-
#[instrument(skip(self), level = "debug")]
1320-
pub fn const_eval_resolve(
1321-
&self,
1322-
mut param_env: ty::ParamEnv<'tcx>,
1323-
unevaluated: ty::UnevaluatedConst<'tcx>,
1324-
span: Span,
1325-
) -> EvalToValTreeResult<'tcx> {
1326-
let mut args = self.resolve_vars_if_possible(unevaluated.args);
1327-
debug!(?args);
1328-
1329-
// Postpone the evaluation of constants whose args depend on inference
1330-
// variables
1331-
let tcx = self.tcx;
1332-
if args.has_non_region_infer() {
1333-
if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
1334-
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args));
1335-
if let Err(e) = ct.error_reported() {
1336-
return Err(ErrorHandled::Reported(e.into(), span));
1337-
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
1338-
return Err(ErrorHandled::TooGeneric(span));
1339-
} else {
1340-
args = replace_param_and_infer_args_with_placeholder(tcx, args);
1341-
}
1342-
} else {
1343-
args = GenericArgs::identity_for_item(tcx, unevaluated.def);
1344-
param_env = tcx.param_env(unevaluated.def);
1345-
}
1346-
}
1347-
1348-
let param_env_erased = tcx.erase_regions(param_env);
1349-
let args_erased = tcx.erase_regions(args);
1350-
debug!(?param_env_erased);
1351-
debug!(?args_erased);
1352-
1353-
let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, args: args_erased };
1354-
1355-
// The return value is the evaluated value which doesn't contain any reference to inference
1356-
// variables, thus we don't need to instantiate back the original values.
1357-
tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
1358-
}
1359-
13601281
/// The returned function is used in a fast path. If it returns `true` the variable is
13611282
/// unchanged, `false` indicates that the status is unknown.
13621283
#[inline]
@@ -1622,61 +1543,6 @@ impl RegionVariableOrigin {
16221543
}
16231544
}
16241545

1625-
/// Replaces args that reference param or infer variables with suitable
1626-
/// placeholders. This function is meant to remove these param and infer
1627-
/// args when they're not actually needed to evaluate a constant.
1628-
fn replace_param_and_infer_args_with_placeholder<'tcx>(
1629-
tcx: TyCtxt<'tcx>,
1630-
args: GenericArgsRef<'tcx>,
1631-
) -> GenericArgsRef<'tcx> {
1632-
struct ReplaceParamAndInferWithPlaceholder<'tcx> {
1633-
tcx: TyCtxt<'tcx>,
1634-
idx: u32,
1635-
}
1636-
1637-
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceParamAndInferWithPlaceholder<'tcx> {
1638-
fn cx(&self) -> TyCtxt<'tcx> {
1639-
self.tcx
1640-
}
1641-
1642-
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
1643-
if let ty::Infer(_) = t.kind() {
1644-
let idx = {
1645-
let idx = self.idx;
1646-
self.idx += 1;
1647-
idx
1648-
};
1649-
Ty::new_placeholder(self.tcx, ty::PlaceholderType {
1650-
universe: ty::UniverseIndex::ROOT,
1651-
bound: ty::BoundTy {
1652-
var: ty::BoundVar::from_u32(idx),
1653-
kind: ty::BoundTyKind::Anon,
1654-
},
1655-
})
1656-
} else {
1657-
t.super_fold_with(self)
1658-
}
1659-
}
1660-
1661-
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
1662-
if let ty::ConstKind::Infer(_) = c.kind() {
1663-
ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst {
1664-
universe: ty::UniverseIndex::ROOT,
1665-
bound: ty::BoundVar::from_u32({
1666-
let idx = self.idx;
1667-
self.idx += 1;
1668-
idx
1669-
}),
1670-
})
1671-
} else {
1672-
c.super_fold_with(self)
1673-
}
1674-
}
1675-
}
1676-
1677-
args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
1678-
}
1679-
16801546
impl<'tcx> InferCtxt<'tcx> {
16811547
/// Given a [`hir::Block`], get the span of its last expression or
16821548
/// statement, peeling off any inner blocks.

compiler/rustc_middle/src/mir/consts.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
use std::fmt::{self, Debug, Display, Formatter};
22

3-
use either::Either;
43
use rustc_abi::{HasDataLayout, Size};
54
use rustc_hir::def_id::DefId;
65
use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
76
use rustc_session::RemapFileNameExt;
87
use rustc_session::config::RemapPathScopeComponents;
98
use rustc_span::{DUMMY_SP, Span};
9+
use rustc_type_ir::visit::TypeVisitableExt;
1010

1111
use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range};
1212
use crate::mir::{Promoted, pretty_print_const_value};
1313
use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
14-
use crate::ty::{self, GenericArgsRef, ScalarInt, Ty, TyCtxt};
14+
use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt};
1515

1616
///////////////////////////////////////////////////////////////////////////
1717
/// Evaluated Constants
@@ -319,15 +319,13 @@ impl<'tcx> Const<'tcx> {
319319
) -> Result<ConstValue<'tcx>, ErrorHandled> {
320320
match self {
321321
Const::Ty(_, c) => {
322-
// We want to consistently have a "clean" value for type system constants (i.e., no
323-
// data hidden in the padding), so we always go through a valtree here.
324-
match c.eval_valtree(tcx, param_env, span) {
325-
Ok((ty, val)) => Ok(tcx.valtree_to_const_val((ty, val))),
326-
Err(Either::Left(_bad_ty)) => Err(tcx
327-
.dcx()
328-
.delayed_bug("`mir::Const::eval` called on a non-valtree-compatible type")
329-
.into()),
330-
Err(Either::Right(e)) => Err(e),
322+
if c.has_non_region_param() {
323+
return Err(ErrorHandled::TooGeneric(span));
324+
}
325+
326+
match c.kind() {
327+
ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))),
328+
_ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()),
331329
}
332330
}
333331
Const::Unevaluated(uneval, _) => {

compiler/rustc_middle/src/ty/consts.rs

+2-57
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use either::Either;
21
use rustc_data_structures::intern::Interned;
32
use rustc_error_messages::MultiSpan;
43
use rustc_hir::def::{DefKind, Res};
@@ -9,7 +8,7 @@ use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
98
use tracing::{debug, instrument};
109

1110
use crate::middle::resolve_bound_vars as rbv;
12-
use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
11+
use crate::mir::interpret::{LitToConstInput, Scalar};
1312
use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
1413

1514
mod int;
@@ -18,7 +17,7 @@ mod valtree;
1817

1918
pub use int::*;
2019
pub use kind::*;
21-
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
20+
use rustc_span::{DUMMY_SP, ErrorGuaranteed};
2221
pub use valtree::*;
2322

2423
pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
@@ -363,60 +362,6 @@ impl<'tcx> Const<'tcx> {
363362
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
364363
}
365364

366-
/// Returns the evaluated constant as a valtree;
367-
/// if that fails due to a valtree-incompatible type, indicate which type that is
368-
/// by returning `Err(Left(bad_type))`.
369-
#[inline]
370-
pub fn eval_valtree(
371-
self,
372-
tcx: TyCtxt<'tcx>,
373-
param_env: ParamEnv<'tcx>,
374-
span: Span,
375-
) -> Result<(Ty<'tcx>, ValTree<'tcx>), Either<Ty<'tcx>, ErrorHandled>> {
376-
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
377-
match self.kind() {
378-
ConstKind::Unevaluated(unevaluated) => {
379-
// FIXME(eddyb) maybe the `const_eval_*` methods should take
380-
// `ty::ParamEnvAnd` instead of having them separate.
381-
let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
382-
// try to resolve e.g. associated constants to their definition on an impl, and then
383-
// evaluate the const.
384-
match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span) {
385-
Ok(Ok(c)) => {
386-
Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c))
387-
}
388-
Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)),
389-
Err(err) => Err(Either::Right(err)),
390-
}
391-
}
392-
ConstKind::Value(ty, val) => Ok((ty, val)),
393-
ConstKind::Error(g) => Err(Either::Right(g.into())),
394-
ConstKind::Param(_)
395-
| ConstKind::Infer(_)
396-
| ConstKind::Bound(_, _)
397-
| ConstKind::Placeholder(_)
398-
| ConstKind::Expr(_) => Err(Either::Right(ErrorHandled::TooGeneric(span))),
399-
}
400-
}
401-
402-
/// Normalizes the constant to a value or an error if possible.
403-
#[inline]
404-
pub fn normalize_internal(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
405-
match self.eval_valtree(tcx, param_env, DUMMY_SP) {
406-
Ok((ty, val)) => Self::new_value(tcx, val, ty),
407-
Err(Either::Left(_bad_ty)) => {
408-
// This can happen when we run on ill-typed code.
409-
Self::new_error(
410-
tcx,
411-
tcx.dcx()
412-
.delayed_bug("`ty::Const::eval` called on a non-valtree-compatible type"),
413-
)
414-
}
415-
Err(Either::Right(ErrorHandled::Reported(r, _span))) => Self::new_error(tcx, r.into()),
416-
Err(Either::Right(ErrorHandled::TooGeneric(_span))) => self,
417-
}
418-
}
419-
420365
/// Panics if self.kind != ty::ConstKind::Value
421366
pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) {
422367
match self.kind() {

compiler/rustc_middle/src/ty/consts/kind.rs

+1-35
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,12 @@
11
use std::assert_matches::assert_matches;
22

3-
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension};
3+
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
44

55
use super::Const;
66
use crate::mir;
77
use crate::ty::abstract_const::CastKind;
8-
use crate::ty::visit::TypeVisitableExt as _;
98
use crate::ty::{self, Ty, TyCtxt};
109

11-
#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)]
12-
impl<'tcx> ty::UnevaluatedConst<'tcx> {
13-
/// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
14-
/// hurts performance.
15-
#[inline]
16-
fn prepare_for_eval(
17-
self,
18-
tcx: TyCtxt<'tcx>,
19-
param_env: ty::ParamEnv<'tcx>,
20-
) -> (ty::ParamEnv<'tcx>, Self) {
21-
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
22-
// also does later, but we want to do it before checking for
23-
// inference variables.
24-
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
25-
// so that we don't try to invoke this query with
26-
// any region variables.
27-
28-
// HACK(eddyb) when the query key would contain inference variables,
29-
// attempt using identity args and `ParamEnv` instead, that will succeed
30-
// when the expression doesn't depend on any parameters.
31-
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
32-
// we can call `infcx.const_eval_resolve` which handles inference variables.
33-
if (param_env, self).has_non_region_infer() {
34-
(tcx.param_env(self.def), ty::UnevaluatedConst {
35-
def: self.def,
36-
args: ty::GenericArgs::identity_for_item(tcx, self.def),
37-
})
38-
} else {
39-
(tcx.erase_regions(param_env).with_reveal_all_normalized(tcx), tcx.erase_regions(self))
40-
}
41-
}
42-
}
43-
4410
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
4511
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
4612
pub enum ExprKind {

0 commit comments

Comments
 (0)