Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use ValTree in all type level constants #83234

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions compiler/rustc_codegen_ssa/src/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) -> (Bx::Value, Ty<'tcx>) {
constant
.map(|val| {
let field_ty = ty.builtin_index().unwrap();
let c = ty::Const::from_value(bx.tcx(), val, ty);
let values: Vec<_> = bx
.tcx()
.destructure_const(ty::ParamEnv::reveal_all().and(&c))
.destructure_const(ty::ParamEnv::reveal_all().and((val, ty)))
.fields
.iter()
.map(|field| {
if let Some(prim) = field.val.try_to_scalar() {
.map(|(field, field_ty)| {
if let Some(prim) = field.try_to_scalar() {
let layout = bx.layout_of(field_ty);
let scalar = match layout.abi {
Abi::Scalar(ref x) => x,
Expand All @@ -78,7 +76,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
})
.collect();
let llval = bx.const_struct(&values, false);
(llval, c.ty)
(llval, ty)
})
.unwrap_or_else(|_| {
bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Item, ItemKind, Node};
use rustc_middle::dep_graph::DepContext;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{
self,
Expand Down Expand Up @@ -524,6 +525,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Err(NonTrivialPath)
}

fn print_const_value(
self,
_value: ConstValue<'tcx>,
_ty: Ty<'tcx>,
) -> Result<Self::Const, Self::Error> {
Err(NonTrivialPath)
}

fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
Ok(vec![self.tcx.crate_name(cnum).to_string()])
}
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_lint/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::middle::stability;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
Expand Down Expand Up @@ -943,6 +944,14 @@ impl<'tcx> LateContext<'tcx> {
Ok(())
}

fn print_const_value(
self,
_val: ConstValue<'tcx>,
_ty: Ty<'tcx>,
) -> Result<Self::Const, Self::Error> {
Ok(())
}

fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
Ok(vec![self.tcx.crate_name(cnum)])
}
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2543,6 +2543,27 @@ impl ConstantKind<'tcx> {
}
}

#[inline]
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
pub fn eval_bits(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> u128 {
match self {
Self::Ty(ct) => ct.eval_bits(tcx, param_env, ty),
Self::Val(val, t) => {
assert_eq!(*t, ty);
let size = tcx
.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty))
.expect("could not normalize type")
.size;
val.try_to_scalar_int().unwrap().assert_bits(size)
}
}
}

#[inline]
pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
match self {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use smallvec::SmallVec;
use std::cell::Cell;
use std::fmt::{self, Debug};

use super::{Field, SourceInfo};
use super::{interpret::ConstValue, Field, SourceInfo};

#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationKind {
Expand Down Expand Up @@ -379,7 +379,7 @@ pub enum ClosureOutlivesSubject<'tcx> {
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConst<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [&'tcx ty::Const<'tcx>],
pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)],
}

/// Coverage information summarized from a MIR if instrumented for source code coverage (see
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_middle/src/mir/type_foldable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,13 @@ impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
}
}
}

impl<'tcx> TypeFoldable<'tcx> for interpret::ConstValue<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
self
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
}
}
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -828,16 +828,16 @@ rustc_queries! {
/// Destructure a constant ADT or array into its variant index and its
/// field values.
query destructure_const(
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
key: ty::ParamEnvAnd<'tcx, (ConstValue<'tcx>, Ty<'tcx>)>
) -> mir::DestructuredConst<'tcx> {
desc { "destructure constant" }
}

/// Dereference a constant reference or raw pointer and turn the result into a constant
/// again.
query deref_const(
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
) -> &'tcx ty::Const<'tcx> {
key: ty::ParamEnvAnd<'tcx, (ConstValue<'tcx>, Ty<'tcx>)>
) -> (ConstValue<'tcx>, Ty<'tcx>) {
desc { "deref constant" }
}

Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType};
use rustc_middle::ty::{
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
};
use rustc_middle::ty::{ConstInt, ScalarInt};
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_target::asm::InlineAsmRegOrRegClass;
Expand Down Expand Up @@ -668,8 +669,9 @@ pub enum PatKind<'tcx> {

#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
pub struct PatRange<'tcx> {
pub lo: &'tcx ty::Const<'tcx>,
pub hi: &'tcx ty::Const<'tcx>,
pub lo: ScalarInt,
pub hi: ScalarInt,
pub ty: Ty<'tcx>,
pub end: RangeEnd,
}

Expand Down Expand Up @@ -788,10 +790,12 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
write!(f, "{}", subpattern)
}
PatKind::Constant { value } => write!(f, "{}", value),
PatKind::Range(PatRange { lo, hi, end }) => {
write!(f, "{}", lo)?;
PatKind::Range(PatRange { lo, hi, end, ty }) => {
let lo = ConstInt::new(lo, ty.is_signed(), ty.is_ptr_sized_integral());
let hi = ConstInt::new(hi, ty.is_signed(), ty.is_ptr_sized_integral());
write!(f, "{:?}", lo)?;
write!(f, "{}", end)?;
write!(f, "{}", hi)
write!(f, "{:?}", hi)
}
PatKind::Slice { ref prefix, ref slice, ref suffix }
| PatKind::Array { ref prefix, ref slice, ref suffix } => {
Expand Down
17 changes: 17 additions & 0 deletions compiler/rustc_middle/src/ty/consts/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,23 @@ impl ScalarInt {
Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size()).unwrap())
}

#[inline]
pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
let i = i.into();
Self::try_from_uint(i, size)
.unwrap_or_else(|| bug!("Unsigned value {:#x} does not fit in {} bits", i, size.bits()))
}

#[inline]
pub fn from_bool(b: bool) -> Self {
Self::from_uint(b as u8, Size::from_bytes(1))
}

#[inline]
pub fn from_char(c: char) -> Self {
Self::from_uint(c as u32, Size::from_bytes(4))
}

#[inline]
pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
let data = i.into();
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_middle/src/ty/print/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::mir::interpret::ConstValue;
use crate::ty::subst::{GenericArg, Subst};
use crate::ty::{self, DefIdTree, Ty, TyCtxt};

Expand Down Expand Up @@ -68,6 +69,12 @@ pub trait Printer<'tcx>: Sized {

fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error>;

fn print_const_value(
self,
val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> Result<Self::Const, Self::Error>;

fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error>;

fn path_qualified(
Expand Down Expand Up @@ -362,3 +369,11 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::Const<'tcx> {
cx.print_const(self)
}
}

impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for (ConstValue<'tcx>, Ty<'tcx>) {
type Output = P::Const;
type Error = P::Error;
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
cx.print_const_value(self.0, self.1)
}
}
14 changes: 10 additions & 4 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1200,10 +1200,8 @@ pub trait PrettyPrinter<'tcx>:
// FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
// correct `ty::ParamEnv` to allow printing *all* constant values.
(_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
let contents = self.tcx().destructure_const(
ty::ParamEnv::reveal_all()
.and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
);
let contents =
self.tcx().destructure_const(ty::ParamEnv::reveal_all().and((ct, ty)));
let fields = contents.fields.iter().copied();

match *ty.kind() {
Expand Down Expand Up @@ -1458,6 +1456,14 @@ impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> {
self.pretty_print_const(ct, true)
}

fn print_const_value(
self,
val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> Result<Self::Const, Self::Error> {
self.pretty_print_const_value(val, ty, true)
}

fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
self.empty_path = true;
if cnum == LOCAL_CRATE {
Expand Down
23 changes: 14 additions & 9 deletions compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index,
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
check_const_value_eq(relation, a_val, b_val, a, b)?
check_const_value_eq(relation, a_val, b_val, a.ty, b.ty)?
}

(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
Expand Down Expand Up @@ -585,10 +585,8 @@ fn check_const_value_eq<R: TypeRelation<'tcx>>(
relation: &mut R,
a_val: ConstValue<'tcx>,
b_val: ConstValue<'tcx>,
// FIXME(oli-obk): these arguments should go away with valtrees
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
// FIXME(oli-obk): this should just be `bool` with valtrees
a_ty: Ty<'tcx>,
b_ty: Ty<'tcx>,
) -> RelateResult<'tcx, bool> {
let tcx = relation.tcx();
Ok(match (a_val, b_val) {
Expand All @@ -610,13 +608,20 @@ fn check_const_value_eq<R: TypeRelation<'tcx>>(
}

(ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => {
let a_destructured = tcx.destructure_const(relation.param_env().and(a));
let b_destructured = tcx.destructure_const(relation.param_env().and(b));
let a_destructured = tcx.destructure_const(relation.param_env().and((a_val, a_ty)));
let b_destructured = tcx.destructure_const(relation.param_env().and((b_val, b_ty)));

// Both the variant and each field have to be equal.
if a_destructured.variant == b_destructured.variant {
for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) {
relation.consts(a_field, b_field)?;
for (&(a_val, a_ty), &(b_val, b_ty)) in
iter::zip(a_destructured.fields, b_destructured.fields)
{
let is_match = check_const_value_eq(relation, a_val, b_val, a_ty, b_ty)?;
if !is_match {
let a = ty::Const::from_value(relation.tcx(), a_val, a_ty);
let b = ty::Const::from_value(relation.tcx(), b_val, b_ty);
return Err(TypeError::ConstMismatch(expected_found(relation, a, b)));
}
}

true
Expand Down
32 changes: 16 additions & 16 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use rustc_target::abi::{Integer, Size, TargetDataLayout};
use smallvec::SmallVec;
use std::{fmt, iter};

use super::ScalarInt;

#[derive(Copy, Clone, Debug)]
pub struct Discr<'tcx> {
/// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`).
Expand Down Expand Up @@ -616,40 +618,38 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
impl<'tcx> ty::TyS<'tcx> {
/// Returns the maximum value for the given numeric type (including `char`s)
/// or returns `None` if the type is not numeric.
pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
let val = match self.kind() {
pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<ScalarInt> {
match self.kind() {
ty::Int(_) | ty::Uint(_) => {
let (size, signed) = int_size_and_signed(tcx, self);
let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) };
Some(val)
Some(ScalarInt::from_uint(val, size))
}
ty::Char => Some(std::char::MAX as u128),
ty::Char => Some(ScalarInt::from(std::char::MAX)),
ty::Float(fty) => Some(match fty {
ty::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
ty::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
ty::FloatTy::F32 => ScalarInt::from(rustc_apfloat::ieee::Single::INFINITY),
ty::FloatTy::F64 => ScalarInt::from(rustc_apfloat::ieee::Double::INFINITY),
}),
_ => None,
};
val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
}
}

/// Returns the minimum value for the given numeric type (including `char`s)
/// or returns `None` if the type is not numeric.
pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
let val = match self.kind() {
pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<ScalarInt> {
match self.kind() {
ty::Int(_) | ty::Uint(_) => {
let (size, signed) = int_size_and_signed(tcx, self);
let val = if signed { size.truncate(signed_min(size) as u128) } else { 0 };
Some(val)
Some(ScalarInt::from_uint(val, size))
}
ty::Char => Some(0),
ty::Char => Some(ScalarInt::from('\0')),
ty::Float(fty) => Some(match fty {
ty::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
ty::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
ty::FloatTy::F32 => ScalarInt::from(-::rustc_apfloat::ieee::Single::INFINITY),
ty::FloatTy::F64 => ScalarInt::from(-::rustc_apfloat::ieee::Double::INFINITY),
}),
_ => None,
};
val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
}
}

/// Checks whether values of this type `T` are *moved* or *copied*
Expand Down
Loading