Skip to content

Commit 5380d56

Browse files
authored
Unrolled build for rust-lang#132927
Rollup merge of rust-lang#132927 - BoxyUwU:consolidate_type_system_const_eval, r=compiler-errors Consolidate type system const evaluation under `traits::evaluate_const` Part of rust-lang#130704 Fixes rust-lang#128232 Fixes rust-lang#118545 Removes `ty::Const::{normalize_internal, eval_valtree}` and `InferCtxt::(try_)const_eval_resolve`, consolidating the associated logic into `evaluate_const` in `rustc_trait_selection`. This results in an API for `ty::Const` that is free of any normalization/evaluation functions that would be incorrect to use under `min_generic_const_args`/`associated_const_equality`/`generic_const_exprs` or, more generally, that would be incorrect to use in the presence of generic type system constants. Moving this logic to `rustc_trait_selection` and out of `rustc_middle` is also a pre-requisite for ensuring that we do not evaluate constants whose where clauses do not hold. From this point it should be relatively simple (hah) to implement more complex normalization of type system constants such as: checking wf'ness before invoking CTFE machinery, or being able to normalize const aliases that still refer to generic parameters. r? `@compiler-errors`
2 parents 9a9dadd + bea0148 commit 5380d56

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
@@ -1477,7 +1477,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14771477
}
14781478
}
14791479
} else if self.tcx.features().generic_const_exprs() {
1480-
ct.normalize_internal(self.tcx, self.param_env)
1480+
rustc_trait_selection::traits::evaluate_const(&self.infcx, ct, self.param_env)
14811481
} else {
14821482
ct
14831483
}

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)