1
Fork 0

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`
This commit is contained in:
bors 2021-04-02 10:28:12 +00:00
commit 0978a9eb99
41 changed files with 183 additions and 55 deletions

View file

@ -2392,7 +2392,8 @@ pub struct Constant<'tcx> {
pub literal: ConstantKind<'tcx>,
}
#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
#[derive(Lift)]
pub enum ConstantKind<'tcx> {
/// This constant came from the type system
Ty(&'tcx ty::Const<'tcx>),
@ -2691,7 +2692,13 @@ impl<'tcx> Display for Constant<'tcx> {
ty::FnDef(..) => {}
_ => write!(fmt, "const ")?,
}
match self.literal {
Display::fmt(&self.literal, fmt)
}
}
impl<'tcx> Display for ConstantKind<'tcx> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match *self {
ConstantKind::Ty(c) => pretty_print_const(c, fmt, true),
ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true),
}

View file

@ -348,6 +348,11 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
#[inline(always)]
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
folder.fold_mir_const(self)
}
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
match self {
ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)),

View file

@ -1486,6 +1486,13 @@ rustc_queries! {
desc { "normalizing `{}`", goal.value }
}
/// Do not call this query directly: invoke `normalize_erasing_regions` instead.
query normalize_mir_const_after_erasing_regions(
goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> mir::ConstantKind<'tcx> {
desc { "normalizing `{}`", goal.value }
}
query implied_outlives_bounds(
goal: CanonicalTyGoal<'tcx>
) -> Result<

View file

@ -1,3 +1,4 @@
use crate::mir;
use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::{self, Ty, TyCtxt, TypeFlags};
@ -65,4 +66,8 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
_ => self.tcx.lifetimes.re_erased,
}
}
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
c.super_fold_with(self)
}
}

View file

@ -30,6 +30,7 @@
//!
//! These methods return true to indicate that the visitor has found what it is
//! looking for, and does not need to visit anything else.
use crate::mir;
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@ -180,6 +181,10 @@ pub trait TypeFolder<'tcx>: Sized {
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
c.super_fold_with(self)
}
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
bug!("most type folders should not be folding MIR datastructures: {:?}", c)
}
}
pub trait TypeVisitor<'tcx>: Sized {

View file

@ -483,6 +483,7 @@ impl<'tcx> Instance<'tcx> {
if let Some(substs) = self.substs_for_mir_body() { v.subst(tcx, substs) } else { *v }
}
#[inline(always)]
pub fn subst_mir_and_normalize_erasing_regions<T>(
&self,
tcx: TyCtxt<'tcx>,

View file

@ -7,6 +7,7 @@
//! `normalize_generic_arg_after_erasing_regions` query for each type
//! or constant found within. (This underlying query is what is cached.)
use crate::mir;
use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{self, Ty, TyCtxt};
@ -101,4 +102,10 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
let arg = self.param_env.and(c.into());
self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_const()
}
#[inline]
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
let arg = self.param_env.and(c);
self.tcx.normalize_mir_const_after_erasing_regions(arg)
}
}

View file

@ -1,5 +1,6 @@
// Type substitutions.
use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
@ -506,6 +507,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
c.super_fold_with(self)
}
}
#[inline]
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
c.super_fold_with(self)
}
}
impl<'a, 'tcx> SubstFolder<'a, 'tcx> {