Skip to content

Commit 0978a9e

Browse files
committed
Auto merge of #83207 - oli-obk:valtree2, r=lcnr
normalize mir::Constant differently from ty::Const in preparation for valtrees Valtrees are unable to represent many kind of constant values (this is on purpose). For constants that are used at runtime, we do not need a valtree representation and can thus use a different form of evaluation. In order to make this explicit and less fragile, I added a `fold_constant` method to `TypeFolder` and implemented it for normalization. Normalization can now, when it wants to eagerly evaluate a constant, normalize `mir::Constant` directly into a `mir::ConstantKind::Val` instead of relying on the `ty::Const` evaluation. In the future we can get rid of the `ty::Const` in there entirely and add our own `Unevaluated` variant to `mir::ConstantKind`. This would allow us to remove the `promoted` field from `ty::ConstKind::Unevaluated`, as promoteds can never occur in the type system. cc `@rust-lang/wg-const-eval` r? `@lcnr`
2 parents 5662d93 + c6676db commit 0978a9e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+183
-55
lines changed

compiler/rustc_infer/src/infer/resolve.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
22
use super::{FixupError, FixupResult, InferCtxt, Span};
3+
use rustc_middle::mir;
34
use rustc_middle::ty::fold::{TypeFolder, TypeVisitor};
45
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
56

@@ -46,6 +47,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
4647
ct.super_fold_with(self)
4748
}
4849
}
50+
51+
fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
52+
constant.super_fold_with(self)
53+
}
4954
}
5055

5156
/// The opportunistic region resolver opportunistically resolves regions

compiler/rustc_middle/src/mir/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -2392,7 +2392,8 @@ pub struct Constant<'tcx> {
23922392
pub literal: ConstantKind<'tcx>,
23932393
}
23942394

2395-
#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
2395+
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
2396+
#[derive(Lift)]
23962397
pub enum ConstantKind<'tcx> {
23972398
/// This constant came from the type system
23982399
Ty(&'tcx ty::Const<'tcx>),
@@ -2691,7 +2692,13 @@ impl<'tcx> Display for Constant<'tcx> {
26912692
ty::FnDef(..) => {}
26922693
_ => write!(fmt, "const ")?,
26932694
}
2694-
match self.literal {
2695+
Display::fmt(&self.literal, fmt)
2696+
}
2697+
}
2698+
2699+
impl<'tcx> Display for ConstantKind<'tcx> {
2700+
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
2701+
match *self {
26952702
ConstantKind::Ty(c) => pretty_print_const(c, fmt, true),
26962703
ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true),
26972704
}

compiler/rustc_middle/src/mir/type_foldable.rs

+5
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,11 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
348348
}
349349

350350
impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
351+
#[inline(always)]
352+
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
353+
folder.fold_mir_const(self)
354+
}
355+
351356
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
352357
match self {
353358
ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)),

compiler/rustc_middle/src/query/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,13 @@ rustc_queries! {
14861486
desc { "normalizing `{}`", goal.value }
14871487
}
14881488

1489+
/// Do not call this query directly: invoke `normalize_erasing_regions` instead.
1490+
query normalize_mir_const_after_erasing_regions(
1491+
goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
1492+
) -> mir::ConstantKind<'tcx> {
1493+
desc { "normalizing `{}`", goal.value }
1494+
}
1495+
14891496
query implied_outlives_bounds(
14901497
goal: CanonicalTyGoal<'tcx>
14911498
) -> Result<

compiler/rustc_middle/src/ty/erase_regions.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::mir;
12
use crate::ty::fold::{TypeFoldable, TypeFolder};
23
use crate::ty::{self, Ty, TyCtxt, TypeFlags};
34

@@ -65,4 +66,8 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
6566
_ => self.tcx.lifetimes.re_erased,
6667
}
6768
}
69+
70+
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
71+
c.super_fold_with(self)
72+
}
6873
}

compiler/rustc_middle/src/ty/fold.rs

+5
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
//!
3131
//! These methods return true to indicate that the visitor has found what it is
3232
//! looking for, and does not need to visit anything else.
33+
use crate::mir;
3334
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
3435
use rustc_hir as hir;
3536
use rustc_hir::def_id::DefId;
@@ -180,6 +181,10 @@ pub trait TypeFolder<'tcx>: Sized {
180181
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
181182
c.super_fold_with(self)
182183
}
184+
185+
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
186+
bug!("most type folders should not be folding MIR datastructures: {:?}", c)
187+
}
183188
}
184189

185190
pub trait TypeVisitor<'tcx>: Sized {

compiler/rustc_middle/src/ty/instance.rs

+1
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ impl<'tcx> Instance<'tcx> {
483483
if let Some(substs) = self.substs_for_mir_body() { v.subst(tcx, substs) } else { *v }
484484
}
485485

486+
#[inline(always)]
486487
pub fn subst_mir_and_normalize_erasing_regions<T>(
487488
&self,
488489
tcx: TyCtxt<'tcx>,

compiler/rustc_middle/src/ty/normalize_erasing_regions.rs

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//! `normalize_generic_arg_after_erasing_regions` query for each type
88
//! or constant found within. (This underlying query is what is cached.)
99
10+
use crate::mir;
1011
use crate::ty::fold::{TypeFoldable, TypeFolder};
1112
use crate::ty::subst::{Subst, SubstsRef};
1213
use crate::ty::{self, Ty, TyCtxt};
@@ -101,4 +102,10 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
101102
let arg = self.param_env.and(c.into());
102103
self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_const()
103104
}
105+
106+
#[inline]
107+
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
108+
let arg = self.param_env.and(c);
109+
self.tcx.normalize_mir_const_after_erasing_regions(arg)
110+
}
104111
}

compiler/rustc_middle/src/ty/subst.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Type substitutions.
22

3+
use crate::mir;
34
use crate::ty::codec::{TyDecoder, TyEncoder};
45
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
56
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
@@ -506,6 +507,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
506507
c.super_fold_with(self)
507508
}
508509
}
510+
511+
#[inline]
512+
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
513+
c.super_fold_with(self)
514+
}
509515
}
510516

511517
impl<'a, 'tcx> SubstFolder<'a, 'tcx> {

compiler/rustc_mir/src/const_eval/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ fn const_to_valtree_inner<'tcx>(
110110

111111
let variant = ecx.read_discriminant(&place.into()).unwrap().1;
112112

113-
branches(def.variants[variant].fields.len(), Some(variant))
113+
branches(def.variants[variant].fields.len(), def.is_enum().then_some(variant))
114114
}
115115

116116
ty::Never

compiler/rustc_mir/src/interpret/eval_context.rs

+1
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
524524
}
525525
}
526526

527+
#[inline(always)]
527528
pub fn layout_of_local(
528529
&self,
529530
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,

compiler/rustc_mir/src/interpret/intrinsics.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
171171
};
172172
let val =
173173
self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
174-
let const_ = ty::Const { val: ty::ConstKind::Value(val), ty };
175-
let val = self.const_to_op(&const_, None)?;
174+
let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
176175
self.copy_op(&val, dest)?;
177176
}
178177

compiler/rustc_mir/src/interpret/operand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
570570
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
571571
match val {
572572
mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout),
573-
mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, None),
573+
mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, layout),
574574
}
575575
}
576576

compiler/rustc_mir/src/monomorphize/collector.rs

+37-2
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
184184
use rustc_hir::itemlikevisit::ItemLikeVisitor;
185185
use rustc_hir::lang_items::LangItem;
186186
use rustc_index::bit_set::GrowableBitSet;
187-
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
188187
use rustc_middle::mir::interpret::{AllocId, ConstValue};
189188
use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar};
190189
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
@@ -193,6 +192,7 @@ use rustc_middle::mir::{self, Local, Location};
193192
use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
194193
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
195194
use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
195+
use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
196196
use rustc_session::config::EntryFnType;
197197
use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
198198
use smallvec::SmallVec;
@@ -638,6 +638,35 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
638638
self.super_rvalue(rvalue, location);
639639
}
640640

641+
/// This does not walk the constant, as it has been handled entirely here and trying
642+
/// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily
643+
/// work, as some constants cannot be represented in the type system.
644+
fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
645+
let literal = self.monomorphize(constant.literal);
646+
let val = match literal {
647+
mir::ConstantKind::Val(val, _) => val,
648+
mir::ConstantKind::Ty(ct) => match ct.val {
649+
ty::ConstKind::Value(val) => val,
650+
ty::ConstKind::Unevaluated(ct) => {
651+
let param_env = ty::ParamEnv::reveal_all();
652+
match self.tcx.const_eval_resolve(param_env, ct, None) {
653+
// The `monomorphize` call should have evaluated that constant already.
654+
Ok(val) => val,
655+
Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => return,
656+
Err(ErrorHandled::TooGeneric) => span_bug!(
657+
self.body.source_info(location).span,
658+
"collection encountered polymorphic constant: {:?}",
659+
literal
660+
),
661+
}
662+
}
663+
_ => return,
664+
},
665+
};
666+
collect_const_value(self.tcx, val, self.output);
667+
self.visit_ty(literal.ty(), TyContext::Location(location));
668+
}
669+
641670
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
642671
debug!("visiting const {:?} @ {:?}", *constant, location);
643672

@@ -648,7 +677,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
648677
ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output),
649678
ty::ConstKind::Unevaluated(unevaluated) => {
650679
match self.tcx.const_eval_resolve(param_env, unevaluated, None) {
651-
Ok(val) => collect_const_value(self.tcx, val, self.output),
680+
// The `monomorphize` call should have evaluated that constant already.
681+
Ok(val) => span_bug!(
682+
self.body.source_info(location).span,
683+
"collection encountered the unevaluated constant {} which evaluated to {:?}",
684+
substituted_constant,
685+
val
686+
),
652687
Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {}
653688
Err(ErrorHandled::TooGeneric) => span_bug!(
654689
self.body.source_info(location).span,

compiler/rustc_mir/src/util/pretty.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,11 @@ impl Visitor<'tcx> for ExtraComments<'tcx> {
452452
match literal {
453453
ConstantKind::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)),
454454
ConstantKind::Val(val, ty) => {
455-
self.push(&format!("+ literal: {:?}, {}", val, ty))
455+
// To keep the diffs small, we render this almost like we render ty::Const
456+
self.push(&format!(
457+
"+ literal: Const {{ ty: {}, val: Value({:?}) }}",
458+
ty, val
459+
))
456460
}
457461
}
458462
}
@@ -465,7 +469,21 @@ impl Visitor<'tcx> for ExtraComments<'tcx> {
465469
if use_verbose(ty) {
466470
self.push("ty::Const");
467471
self.push(&format!("+ ty: {:?}", ty));
468-
self.push(&format!("+ val: {:?}", val));
472+
let val = match val {
473+
ty::ConstKind::Param(p) => format!("Param({})", p),
474+
ty::ConstKind::Infer(infer) => format!("Infer({:?})", infer),
475+
ty::ConstKind::Bound(idx, var) => format!("Bound({:?}, {:?})", idx, var),
476+
ty::ConstKind::Placeholder(ph) => format!("PlaceHolder({:?})", ph),
477+
ty::ConstKind::Unevaluated(uv) => format!(
478+
"Unevaluated({}, {:?}, {:?})",
479+
self.tcx.def_path_str(uv.def.did),
480+
uv.substs,
481+
uv.promoted
482+
),
483+
ty::ConstKind::Value(val) => format!("Value({:?})", val),
484+
ty::ConstKind::Error(_) => format!("Error"),
485+
};
486+
self.push(&format!("+ val: {}", val));
469487
}
470488
}
471489

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,18 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
246246
})
247247
}
248248

249+
fn field_pats(
250+
&self,
251+
vals: impl Iterator<Item = &'tcx ty::Const<'tcx>>,
252+
) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
253+
vals.enumerate()
254+
.map(|(idx, val)| {
255+
let field = Field::new(idx);
256+
Ok(FieldPat { field, pattern: self.recur(val, false)? })
257+
})
258+
.collect()
259+
}
260+
249261
// Recursive helper for `to_pat`; invoke that (instead of calling this directly).
250262
fn recur(
251263
&self,
@@ -257,16 +269,6 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
257269
let tcx = self.tcx();
258270
let param_env = self.param_env;
259271

260-
let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| -> Result<_, _> {
261-
vals.iter()
262-
.enumerate()
263-
.map(|(idx, val)| {
264-
let field = Field::new(idx);
265-
Ok(FieldPat { field, pattern: self.recur(val, false)? })
266-
})
267-
.collect()
268-
};
269-
270272
let kind = match cv.ty.kind() {
271273
ty::Float(_) => {
272274
tcx.struct_span_lint_hir(
@@ -361,12 +363,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
361363
variant_index: destructured
362364
.variant
363365
.expect("destructed const of adt without variant id"),
364-
subpatterns: field_pats(destructured.fields)?,
366+
subpatterns: self.field_pats(destructured.fields.iter().copied())?,
365367
}
366368
}
367369
ty::Tuple(_) | ty::Adt(_, _) => {
368370
let destructured = tcx.destructure_const(param_env.and(cv));
369-
PatKind::Leaf { subpatterns: field_pats(destructured.fields)? }
371+
PatKind::Leaf { subpatterns: self.field_pats(destructured.fields.iter().copied())? }
370372
}
371373
ty::Array(..) => PatKind::Array {
372374
prefix: tcx

compiler/rustc_query_impl/src/keys.rs

+9
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,15 @@ impl<'tcx> Key for GenericArg<'tcx> {
255255
}
256256
}
257257

258+
impl<'tcx> Key for mir::ConstantKind<'tcx> {
259+
fn query_crate(&self) -> CrateNum {
260+
LOCAL_CRATE
261+
}
262+
fn default_span(&self, _: TyCtxt<'_>) -> Span {
263+
DUMMY_SP
264+
}
265+
}
266+
258267
impl<'tcx> Key for &'tcx ty::Const<'tcx> {
259268
fn query_crate(&self) -> CrateNum {
260269
LOCAL_CRATE

compiler/rustc_trait_selection/src/traits/query/normalize.rs

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
1010
use rustc_data_structures::sso::SsoHashMap;
1111
use rustc_data_structures::stack::ensure_sufficient_stack;
1212
use rustc_infer::traits::Normalized;
13+
use rustc_middle::mir;
1314
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
1415
use rustc_middle::ty::subst::Subst;
1516
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -214,4 +215,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
214215
let constant = constant.super_fold_with(self);
215216
constant.eval(self.infcx.tcx, self.param_env)
216217
}
218+
219+
fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
220+
constant.super_fold_with(self)
221+
}
217222
}

0 commit comments

Comments
 (0)