1
Fork 0

Auto merge of #125958 - BoxyUwU:remove_const_ty, r=lcnr

Remove the `ty` field from type system `Const`s

Fixes #125556
Fixes #122908

Part of the work on `adt_const_params`/`generic_const_param_types`/`min_generic_const_exprs`/generally making the compiler nicer. cc rust-lang/project-const-generics#44

Please review commit-by-commit otherwise I wasted a lot of time not just squashing this into a giant mess (and also it'll be SO much nicer because theres a lot of fluff changes mixed in with other more careful changes if looking via File Changes

---

Why do this?
- The `ty` field keeps causing ICEs and weird behaviour due to it either being treated as "part of the const" or it being forgotten about leading to ICEs.
- As we move forward with `adt_const_params` and a potential `min_generic_const_exprs` it's going to become more complex to actually lower the correct `Ty<'tcx>`
- It muddles the idea behind how we check `Const` arguments have the correct type. By having the `ty` field it may seem like we ought to be relating it when we relate two types, or that its generally important information about the `Const`.
- Brings the compiler more in line with `a-mir-formality` as that also tracks the type of type system `Const`s via `ConstArgHasType` bounds in the env instead of on the `Const` itself.
- A lot of stuff is a lot nicer when you dont have to pass around the type of a const lol. Everywhere we construct `Const` is now significantly nicer 😅

See #125671's description for some more information about the `ty` field

---

General summary of changes in this PR:

- Add `Ty` to `ConstKind::Value` as otherwise there is no way to implement `ConstArgHasType` to ensure that const arguments are correctly typed for the parameter when we stop creating anon consts for all const args. It's also just incredibly difficult/annoying to thread the correct `Ty` around to a bunch of ctfe functions otherwise.
-  Fully implement `ConstArgHasType` in both the old and new solver. Since it now has no reliance on the `ty` field it serves its originally intended purpose of being able to act as a double check that trait vs impls have correctly typed const parameters. It also will now be able to be responsible for checking types of const arguments to parameters under `min_generic_const_exprs`.
- Add `Ty` to `mir::Const::Ty`. I dont have a great understanding of why mir constants are setup like this to be honest. Regardless they need to be able to determine the type of the const and the easiest way to make this happen was to simply store the `Ty` along side the `ty::Const`. Maybe we can do better here in the future but I'd have to spend way more time looking at everywhere we use `mir::Const`.
- rustdoc has its own `Const` which also has a `ty` field. It was relatively easy to remove this.

---

r? `@lcnr` `@compiler-errors`
This commit is contained in:
bors 2024-06-06 03:41:23 +00:00
commit 003a902792
149 changed files with 1159 additions and 1228 deletions

View file

@ -204,7 +204,9 @@ pub enum Const<'tcx> {
/// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`;
/// this ensures that we consistently produce "clean" values without data in the padding or
/// anything like that.
Ty(ty::Const<'tcx>),
///
/// FIXME(BoxyUwU): We should remove this `Ty` and look up the type for params via `ParamEnv`
Ty(Ty<'tcx>, ty::Const<'tcx>),
/// An unevaluated mir constant which is not part of the type system.
///
@ -237,7 +239,15 @@ impl<'tcx> Const<'tcx> {
#[inline(always)]
pub fn ty(&self) -> Ty<'tcx> {
match self {
Const::Ty(c) => c.ty(),
Const::Ty(ty, ct) => {
match ct.kind() {
// Dont use the outter ty as on invalid code we can wind up with them not being the same.
// this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir
// was originally `({N: usize} + 1_usize)` under `generic_const_exprs`.
ty::ConstKind::Value(ty, _) => ty,
_ => *ty,
}
}
Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty,
}
}
@ -247,8 +257,8 @@ impl<'tcx> Const<'tcx> {
#[inline]
pub fn is_required_const(&self) -> bool {
match self {
Const::Ty(c) => match c.kind() {
ty::ConstKind::Value(_) => false, // already a value, cannot error
Const::Ty(_, c) => match c.kind() {
ty::ConstKind::Value(_, _) => false, // already a value, cannot error
_ => true,
},
Const::Val(..) => false, // already a value, cannot error
@ -259,8 +269,8 @@ impl<'tcx> Const<'tcx> {
#[inline]
pub fn try_to_scalar(self) -> Option<Scalar> {
match self {
Const::Ty(c) => match c.kind() {
ty::ConstKind::Value(valtree) if c.ty().is_primitive() => {
Const::Ty(_, c) => match c.kind() {
ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => {
// A valtree of a type where leaves directly represent the scalar const value.
// Just checking whether it is a leaf is insufficient as e.g. references are leafs
// but the leaf value is the value they point to, not the reference itself!
@ -278,8 +288,8 @@ impl<'tcx> Const<'tcx> {
// This is equivalent to `self.try_to_scalar()?.try_to_int().ok()`, but measurably faster.
match self {
Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x),
Const::Ty(c) => match c.kind() {
ty::ConstKind::Value(valtree) if c.ty().is_primitive() => {
Const::Ty(_, c) => match c.kind() {
ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => {
Some(valtree.unwrap_leaf())
}
_ => None,
@ -306,11 +316,11 @@ impl<'tcx> Const<'tcx> {
span: Span,
) -> Result<ConstValue<'tcx>, ErrorHandled> {
match self {
Const::Ty(c) => {
Const::Ty(_, c) => {
// We want to consistently have a "clean" value for type system constants (i.e., no
// data hidden in the padding), so we always go through a valtree here.
let val = c.eval(tcx, param_env, span)?;
Ok(tcx.valtree_to_const_val((self.ty(), val)))
let (ty, val) = c.eval(tcx, param_env, span)?;
Ok(tcx.valtree_to_const_val((ty, val)))
}
Const::Unevaluated(uneval, _) => {
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
@ -326,7 +336,7 @@ impl<'tcx> Const<'tcx> {
match self.eval(tcx, param_env, DUMMY_SP) {
Ok(val) => Self::Val(val, self.ty()),
Err(ErrorHandled::Reported(guar, _span)) => {
Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
Self::Ty(Ty::new_error(tcx, guar.into()), ty::Const::new_error(tcx, guar.into()))
}
Err(ErrorHandled::TooGeneric(_span)) => self,
}
@ -338,15 +348,16 @@ impl<'tcx> Const<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Option<Scalar> {
match self {
Const::Ty(c) if c.ty().is_primitive() => {
// Avoid the `valtree_to_const_val` query. Can only be done on primitive types that
// are valtree leaves, and *not* on references. (References should return the
// pointer here, which valtrees don't represent.)
let val = c.eval(tcx, param_env, DUMMY_SP).ok()?;
Some(val.unwrap_leaf().into())
}
_ => self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar(),
if let Const::Ty(_, c) = self
&& let ty::ConstKind::Value(ty, val) = c.kind()
&& ty.is_primitive()
{
// Avoid the `valtree_to_const_val` query. Can only be done on primitive types that
// are valtree leaves, and *not* on references. (References should return the
// pointer here, which valtrees don't represent.)
Some(val.unwrap_leaf().into())
} else {
self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar()
}
}
@ -439,14 +450,14 @@ impl<'tcx> Const<'tcx> {
Self::Val(val, ty)
}
pub fn from_ty_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
pub fn from_ty_const(c: ty::Const<'tcx>, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
match c.kind() {
ty::ConstKind::Value(valtree) => {
ty::ConstKind::Value(ty, valtree) => {
// Make sure that if `c` is normalized, then the return value is normalized.
let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
Self::Val(const_val, c.ty())
let const_val = tcx.valtree_to_const_val((ty, valtree));
Self::Val(const_val, ty)
}
_ => Self::Ty(c),
_ => Self::Ty(ty, c),
}
}
@ -458,12 +469,12 @@ impl<'tcx> Const<'tcx> {
// - valtrees purposefully generate new allocations
// - ConstValue::Slice also generate new allocations
match self {
Const::Ty(c) => match c.kind() {
Const::Ty(_, c) => match c.kind() {
ty::ConstKind::Param(..) => true,
// A valtree may be a reference. Valtree references correspond to a
// different allocation each time they are evaluated. Valtrees for primitive
// types are fine though.
ty::ConstKind::Value(_) => c.ty().is_primitive(),
ty::ConstKind::Value(ty, _) => ty.is_primitive(),
ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false,
// This can happen if evaluation of a constant failed. The result does not matter
// much since compilation is doomed.
@ -517,7 +528,7 @@ impl<'tcx> UnevaluatedConst<'tcx> {
impl<'tcx> Display for Const<'tcx> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match *self {
Const::Ty(c) => pretty_print_const(c, fmt, true),
Const::Ty(_, c) => pretty_print_const(c, fmt, true),
Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
// FIXME(valtrees): Correctly print mir constants.
Const::Unevaluated(c, _ty) => {

View file

@ -1313,12 +1313,12 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
};
let val = match const_ {
Const::Ty(ct) => match ct.kind() {
Const::Ty(_, ct) => match ct.kind() {
ty::ConstKind::Param(p) => format!("ty::Param({p})"),
ty::ConstKind::Unevaluated(uv) => {
format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
}
ty::ConstKind::Value(val) => format!("ty::Valtree({})", fmt_valtree(&val)),
ty::ConstKind::Value(_, val) => format!("ty::Valtree({})", fmt_valtree(&val)),
// No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`.
ty::ConstKind::Error(_) => "Error".to_string(),
// These variants shouldn't exist in the MIR.
@ -1417,7 +1417,7 @@ pub fn write_allocations<'tcx>(
impl<'tcx> Visitor<'tcx> for CollectAllocIds {
fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) {
match c.const_ {
Const::Ty(_) | Const::Unevaluated(..) => {}
Const::Ty(_, _) | Const::Unevaluated(..) => {}
Const::Val(val, _) => {
self.0.extend(alloc_ids_from_const_val(val));
}

View file

@ -895,7 +895,7 @@ macro_rules! make_mir_visitor {
self.visit_span($(& $mutability)? *span);
match const_ {
Const::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location),
Const::Ty(_, ct) => self.visit_ty_const($(&$mutability)? *ct, location),
Const::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
Const::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
}

View file

@ -616,6 +616,8 @@ pub enum SelectionError<'tcx> {
/// We can thus not know whether the hidden type implements an auto trait, so
/// we should not presume anything about it.
OpaqueTypeAutoTraitLeakageUnknown(DefId),
/// Error for a `ConstArgHasType` goal
ConstArgHasWrongType { ct: ty::Const<'tcx>, ct_ty: Ty<'tcx>, expected_ty: Ty<'tcx> },
}
#[derive(Clone, Debug, TypeVisitable)]

View file

@ -53,7 +53,7 @@ impl<'tcx> TyCtxt<'tcx> {
fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> {
let ct = match c.kind() {
ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) {
Err(e) => ty::Const::new_error(self.tcx, e, c.ty()),
Err(e) => ty::Const::new_error(self.tcx, e),
Ok(Some(bac)) => {
let args = self.tcx.erase_regions(uv.args);
let bac = bac.instantiate(self.tcx, args);

View file

@ -350,8 +350,8 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> {
fn decode(decoder: &mut D) -> Self {
let consts: ty::ConstData<'tcx> = Decodable::decode(decoder);
decoder.interner().mk_ct_from_kind(consts.kind, consts.ty)
let kind: ty::ConstKind<'tcx> = Decodable::decode(decoder);
decoder.interner().mk_ct_from_kind(kind)
}
}

View file

@ -6,7 +6,7 @@ use rustc_error_messages::MultiSpan;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::LocalDefId;
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
use rustc_macros::HashStable;
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
use tracing::{debug, instrument};
@ -24,12 +24,11 @@ pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>;
#[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(ConstKind<'_>, 24);
rustc_data_structures::static_assert_size!(ConstKind<'_>, 32);
/// Use this rather than `ConstData`, whenever possible.
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
#[rustc_pass_by_value]
pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>);
pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstKind<'tcx>>>);
impl<'tcx> rustc_type_ir::inherent::IntoKind for Const<'tcx> {
type Kind = ConstKind<'tcx>;
@ -49,26 +48,11 @@ impl<'tcx> rustc_type_ir::visit::Flags for Const<'tcx> {
}
}
/// Typed constant value.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[derive(HashStable, TyEncodable, TyDecodable)]
pub struct ConstData<'tcx> {
pub ty: Ty<'tcx>,
pub kind: ConstKind<'tcx>,
}
#[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(ConstData<'_>, 32);
impl<'tcx> Const<'tcx> {
#[inline]
pub fn ty(self) -> Ty<'tcx> {
self.0.ty
}
#[inline]
pub fn kind(self) -> ConstKind<'tcx> {
self.0.kind
let a: &ConstKind<'tcx> = self.0.0;
*a
}
// FIXME(compiler-errors): Think about removing this.
@ -84,28 +68,28 @@ impl<'tcx> Const<'tcx> {
}
#[inline]
pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
tcx.mk_ct_from_kind(kind, ty)
pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>) -> Const<'tcx> {
tcx.mk_ct_from_kind(kind)
}
#[inline]
pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst, ty: Ty<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Param(param), ty)
pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Param(param))
}
#[inline]
pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid, ty: Ty<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty)
pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)))
}
#[inline]
pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32, ty: Ty<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh)), ty)
pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh)))
}
#[inline]
pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Infer(infer), ty)
pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Infer(infer))
}
#[inline]
@ -113,50 +97,40 @@ impl<'tcx> Const<'tcx> {
tcx: TyCtxt<'tcx>,
debruijn: ty::DebruijnIndex,
var: ty::BoundVar,
ty: Ty<'tcx>,
) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Bound(debruijn, var), ty)
Const::new(tcx, ty::ConstKind::Bound(debruijn, var))
}
#[inline]
pub fn new_placeholder(
tcx: TyCtxt<'tcx>,
placeholder: ty::PlaceholderConst,
ty: Ty<'tcx>,
) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Placeholder(placeholder), ty)
pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Placeholder(placeholder))
}
#[inline]
pub fn new_unevaluated(
tcx: TyCtxt<'tcx>,
uv: ty::UnevaluatedConst<'tcx>,
ty: Ty<'tcx>,
) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Unevaluated(uv), ty)
pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Unevaluated(uv))
}
#[inline]
pub fn new_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Value(val), ty)
Const::new(tcx, ty::ConstKind::Value(ty, val))
}
#[inline]
pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Expr(expr), ty)
pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Expr(expr))
}
#[inline]
pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed, ty: Ty<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Error(e), ty)
pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Error(e))
}
/// Like [Ty::new_error] but for constants.
#[track_caller]
pub fn new_misc_error(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
pub fn new_misc_error(tcx: TyCtxt<'tcx>) -> Const<'tcx> {
Const::new_error_with_message(
tcx,
ty,
DUMMY_SP,
"ty::ConstKind::Error constructed but no error reported",
)
@ -166,52 +140,33 @@ impl<'tcx> Const<'tcx> {
#[track_caller]
pub fn new_error_with_message<S: Into<MultiSpan>>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
span: S,
msg: &'static str,
) -> Const<'tcx> {
let reported = tcx.dcx().span_delayed_bug(span, msg);
Const::new_error(tcx, reported, ty)
Const::new_error(tcx, reported)
}
}
impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Self {
Const::new_infer(tcx, infer, ty)
fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self {
Const::new_infer(tcx, infer)
}
fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid, ty: Ty<'tcx>) -> Self {
Const::new_var(tcx, vid, ty)
fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid) -> Self {
Const::new_var(tcx, vid)
}
fn new_bound(
interner: TyCtxt<'tcx>,
debruijn: ty::DebruijnIndex,
var: ty::BoundVar,
ty: Ty<'tcx>,
) -> Self {
Const::new_bound(interner, debruijn, var, ty)
fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
Const::new_bound(interner, debruijn, var)
}
fn new_anon_bound(
tcx: TyCtxt<'tcx>,
debruijn: ty::DebruijnIndex,
var: ty::BoundVar,
ty: Ty<'tcx>,
) -> Self {
Const::new_bound(tcx, debruijn, var, ty)
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
Const::new_bound(tcx, debruijn, var)
}
fn new_unevaluated(
interner: TyCtxt<'tcx>,
uv: ty::UnevaluatedConst<'tcx>,
ty: Ty<'tcx>,
) -> Self {
Const::new_unevaluated(interner, uv, ty)
}
fn ty(self) -> Ty<'tcx> {
self.ty()
fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self {
Const::new_unevaluated(interner, uv)
}
}
@ -241,7 +196,6 @@ impl<'tcx> Const<'tcx> {
def: def.to_def_id(),
args: GenericArgs::identity_for_item(tcx, def.to_def_id()),
},
ty,
),
}
}
@ -293,9 +247,6 @@ impl<'tcx> Const<'tcx> {
_,
&hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. },
)) => {
// Use the type from the param's definition, since we can resolve it,
// not the expected parameter type from WithOptConstParam.
let param_ty = tcx.type_of(def_id).instantiate_identity();
match tcx.named_bound_var(expr.hir_id) {
Some(rbv::ResolvedArg::EarlyBound(_)) => {
// Find the name and index of the const parameter by indexing the generics of
@ -304,19 +255,12 @@ impl<'tcx> Const<'tcx> {
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.item_name(def_id);
Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty))
Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name)))
}
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
Some(ty::Const::new_bound(
tcx,
debruijn,
ty::BoundVar::from_u32(index),
param_ty,
))
}
Some(rbv::ResolvedArg::Error(guar)) => {
Some(ty::Const::new_error(tcx, guar, param_ty))
Some(ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)))
}
Some(rbv::ResolvedArg::Error(guar)) => Some(ty::Const::new_error(tcx, guar)),
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id),
}
}
@ -363,7 +307,7 @@ impl<'tcx> Const<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
span: Span,
) -> Result<ValTree<'tcx>, ErrorHandled> {
) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> {
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
match self.kind() {
ConstKind::Unevaluated(unevaluated) => {
@ -381,9 +325,9 @@ impl<'tcx> Const<'tcx> {
);
return Err(e.into());
};
Ok(c)
Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c))
}
ConstKind::Value(val) => Ok(val),
ConstKind::Value(ty, val) => Ok((ty, val)),
ConstKind::Error(g) => Err(g.into()),
ConstKind::Param(_)
| ConstKind::Infer(_)
@ -397,8 +341,8 @@ impl<'tcx> Const<'tcx> {
#[inline]
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
match self.eval(tcx, param_env, DUMMY_SP) {
Ok(val) => Self::new_value(tcx, val, self.ty()),
Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()),
Ok((ty, val)) => Self::new_value(tcx, val, ty),
Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into()),
Err(ErrorHandled::TooGeneric(_span)) => self,
}
}
@ -408,8 +352,10 @@ impl<'tcx> Const<'tcx> {
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Option<Scalar> {
self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar()
) -> Option<(Ty<'tcx>, Scalar)> {
let (ty, val) = self.eval(tcx, param_env, DUMMY_SP).ok()?;
let val = val.try_to_scalar()?;
Some((ty, val))
}
#[inline]
@ -420,8 +366,10 @@ impl<'tcx> Const<'tcx> {
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<ScalarInt> {
self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
) -> Option<(Ty<'tcx>, ScalarInt)> {
let (ty, scalar) = self.try_eval_scalar(tcx, param_env)?;
let val = scalar.try_to_int().ok()?;
Some((ty, val))
}
#[inline]
@ -429,18 +377,17 @@ impl<'tcx> Const<'tcx> {
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
/// contains const generic parameters or pointers).
pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> {
let int = self.try_eval_scalar_int(tcx, param_env)?;
let size =
tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size;
let (ty, scalar) = self.try_eval_scalar_int(tcx, param_env)?;
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
// if `ty` does not depend on generic parameters, use an empty param_env
int.try_to_bits(size).ok()
scalar.try_to_bits(size).ok()
}
#[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: ParamEnv<'tcx>) -> u128 {
self.try_eval_bits(tcx, param_env)
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
.unwrap_or_else(|| bug!("failed to evalate {:#?} to bits", self))
}
#[inline]
@ -449,12 +396,14 @@ impl<'tcx> Const<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<u64> {
self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?;
scalar.try_to_target_usize(tcx).ok()
}
#[inline]
pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?;
scalar.try_into().ok()
}
#[inline]
@ -467,7 +416,7 @@ impl<'tcx> Const<'tcx> {
/// Panics if self.kind != ty::ConstKind::Value
pub fn to_valtree(self) -> ty::ValTree<'tcx> {
match self.kind() {
ty::ConstKind::Value(valtree) => valtree,
ty::ConstKind::Value(_, valtree) => valtree,
_ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
}
}
@ -475,7 +424,7 @@ impl<'tcx> Const<'tcx> {
/// Attempts to convert to a `ValTree`
pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> {
match self.kind() {
ty::ConstKind::Value(valtree) => Some(valtree),
ty::ConstKind::Value(_, valtree) => Some(valtree),
_ => None,
}
}

View file

@ -104,10 +104,12 @@ impl<'tcx> Expr<'tcx> {
tcx: TyCtxt<'tcx>,
func_ty: Ty<'tcx>,
func_expr: Const<'tcx>,
arguments: impl Iterator<Item = Const<'tcx>>,
arguments: impl IntoIterator<Item = Const<'tcx>>,
) -> Self {
let args = tcx.mk_args_from_iter::<_, ty::GenericArg<'tcx>>(
[func_ty.into(), func_expr.into()].into_iter().chain(arguments.map(|ct| ct.into())),
[func_ty.into(), func_expr.into()]
.into_iter()
.chain(arguments.into_iter().map(|ct| ct.into())),
);
Self { kind: ExprKind::FunctionCall, args }
@ -155,7 +157,7 @@ impl<'tcx> Expr<'tcx> {
Self { kind, args }
}
pub fn args(&self) -> ty::GenericArgsRef<'tcx> {
pub fn args(self) -> ty::GenericArgsRef<'tcx> {
self.args
}
}

View file

@ -28,10 +28,10 @@ use crate::traits::solve::{
};
use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
use crate::ty::{
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData,
GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern,
PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity,
Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility,
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericParamDefKind,
ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, PatternKind,
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region,
RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility,
};
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
use rustc_ast::{self as ast, attr};
@ -268,7 +268,7 @@ pub struct CtxtInterners<'tcx> {
clauses: InternedSet<'tcx, ListWithCachedTypeInfo<Clause<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>,
const_: InternedSet<'tcx, WithCachedTypeInfo<ty::ConstKind<'tcx>>>,
pat: InternedSet<'tcx, PatternKind<'tcx>>,
const_allocation: InternedSet<'tcx, Allocation>,
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
@ -338,18 +338,18 @@ impl<'tcx> CtxtInterners<'tcx> {
#[inline(never)]
fn intern_const(
&self,
data: ty::ConstData<'tcx>,
kind: ty::ConstKind<'tcx>,
sess: &Session,
untracked: &Untracked,
) -> Const<'tcx> {
Const(Interned::new_unchecked(
self.const_
.intern(data, |data: ConstData<'_>| {
let flags = super::flags::FlagComputation::for_const(&data.kind, data.ty);
let stable_hash = self.stable_hash(&flags, sess, untracked, &data);
.intern(kind, |kind: ty::ConstKind<'_>| {
let flags = super::flags::FlagComputation::for_const_kind(&kind);
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
internee: data,
internee: kind,
stable_hash,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
@ -601,18 +601,15 @@ impl<'tcx> CommonConsts<'tcx> {
};
CommonConsts {
unit: mk_const(ty::ConstData {
kind: ty::ConstKind::Value(ty::ValTree::zst()),
ty: types.unit,
}),
true_: mk_const(ty::ConstData {
kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::TRUE)),
ty: types.bool,
}),
false_: mk_const(ty::ConstData {
kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::FALSE)),
ty: types.bool,
}),
unit: mk_const(ty::ConstKind::Value(types.unit, ty::ValTree::zst())),
true_: mk_const(ty::ConstKind::Value(
types.bool,
ty::ValTree::Leaf(ty::ScalarInt::TRUE),
)),
false_: mk_const(ty::ConstKind::Value(
types.bool,
ty::ValTree::Leaf(ty::ScalarInt::FALSE),
)),
}
}
}
@ -2225,9 +2222,9 @@ impl<'tcx> TyCtxt<'tcx> {
}
#[inline]
pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>) -> Const<'tcx> {
self.interners.intern_const(
ty::ConstData { kind, ty },
kind,
self.sess,
// This is only used to create a stable hashing context.
&self.untracked,
@ -2252,14 +2249,10 @@ impl<'tcx> TyCtxt<'tcx> {
ty::Region::new_early_param(self, param.to_early_bound_region_data()).into()
}
GenericParamDefKind::Type { .. } => Ty::new_param(self, param.index, param.name).into(),
GenericParamDefKind::Const { .. } => ty::Const::new_param(
self,
ParamConst { index: param.index, name: param.name },
self.type_of(param.def_id)
.no_bound_vars()
.expect("const parameter types cannot be generic"),
)
.into(),
GenericParamDefKind::Const { .. } => {
ty::Const::new_param(self, ParamConst { index: param.index, name: param.name })
.into()
}
}
}

View file

@ -337,7 +337,7 @@ impl DeepRejectCtxt {
| ty::ConstKind::Error(_) => {
return true;
}
ty::ConstKind::Value(impl_val) => impl_val,
ty::ConstKind::Value(_, impl_val) => impl_val,
ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
bug!("unexpected impl arg: {:?}", impl_ct)
}
@ -357,7 +357,7 @@ impl DeepRejectCtxt {
ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => {
true
}
ty::ConstKind::Value(obl_val) => obl_val == impl_val,
ty::ConstKind::Value(_, obl_val) => obl_val == impl_val,
ty::ConstKind::Infer(_) => true,

View file

@ -28,10 +28,9 @@ impl FlagComputation {
result
}
pub fn for_const(c: &ty::ConstKind<'_>, t: Ty<'_>) -> FlagComputation {
pub fn for_const_kind(kind: &ty::ConstKind<'_>) -> FlagComputation {
let mut result = FlagComputation::new();
result.add_const_kind(c);
result.add_ty(t);
result.add_const_kind(kind);
result
}
@ -373,7 +372,7 @@ impl FlagComputation {
self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::ConstKind::Value(_) => {}
ty::ConstKind::Value(ty, _) => self.add_ty(ty),
ty::ConstKind::Expr(e) => self.add_args(e.args()),
ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
}

View file

@ -134,13 +134,13 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
pub trait BoundVarReplacerDelegate<'tcx> {
fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>;
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>;
fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx>;
fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx>;
}
pub struct FnMutDelegate<'a, 'tcx> {
pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
pub consts: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a),
pub consts: &'a mut (dyn FnMut(ty::BoundVar) -> ty::Const<'tcx> + 'a),
}
impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> {
@ -150,8 +150,8 @@ impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> {
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
(self.types)(bt)
}
fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
(self.consts)(bv, ty)
fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> {
(self.consts)(bv)
}
}
@ -224,7 +224,7 @@ where
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match ct.kind() {
ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
let ct = self.delegate.replace_const(bound_const, ct.ty());
let ct = self.delegate.replace_const(bound_const);
debug_assert!(!ct.has_vars_bound_above(ty::INNERMOST));
ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32())
}
@ -282,7 +282,7 @@ impl<'tcx> TyCtxt<'tcx> {
let delegate = FnMutDelegate {
regions: &mut replace_regions,
types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"),
consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"),
consts: &mut |b| bug!("unexpected bound ct in binder: {b:?}"),
};
let mut replacer = BoundVarReplacer::new(self, delegate);
value.fold_with(&mut replacer)
@ -353,9 +353,7 @@ impl<'tcx> TyCtxt<'tcx> {
ty::BoundTy { var: shift_bv(t.var), kind: t.kind },
)
},
consts: &mut |c, ty: Ty<'tcx>| {
ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c), ty)
},
consts: &mut |c| ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c)),
},
)
}
@ -398,12 +396,12 @@ impl<'tcx> TyCtxt<'tcx> {
.expect_ty();
Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind })
}
fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> {
let entry = self.map.entry(bv);
let index = entry.index();
let var = ty::BoundVar::from_usize(index);
let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const();
ty::Const::new_bound(self.tcx, ty::INNERMOST, var, ty)
ty::Const::new_bound(self.tcx, ty::INNERMOST, var)
}
}

View file

@ -228,7 +228,7 @@ impl<'tcx> GenericArg<'tcx> {
ptr.cast::<WithCachedTypeInfo<ty::TyKind<'tcx>>>().as_ref(),
))),
CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
ptr.cast::<WithCachedTypeInfo<ty::ConstData<'tcx>>>().as_ref(),
ptr.cast::<WithCachedTypeInfo<ty::ConstKind<'tcx>>>().as_ref(),
))),
_ => intrinsics::unreachable(),
}
@ -454,11 +454,11 @@ impl<'tcx> GenericArgs<'tcx> {
def_id: DefId,
original_args: &[GenericArg<'tcx>],
) -> GenericArgsRef<'tcx> {
ty::GenericArgs::for_item(tcx, def_id, |def, args| {
ty::GenericArgs::for_item(tcx, def_id, |def, _| {
if let Some(arg) = original_args.get(def.index as usize) {
*arg
} else {
def.to_error(tcx, args)
def.to_error(tcx)
}
})
}

View file

@ -100,19 +100,11 @@ impl GenericParamDef {
}
}
pub fn to_error<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
preceding_args: &[ty::GenericArg<'tcx>],
) -> ty::GenericArg<'tcx> {
pub fn to_error<'tcx>(&self, tcx: TyCtxt<'tcx>) -> ty::GenericArg<'tcx> {
match &self.kind {
ty::GenericParamDefKind::Lifetime => ty::Region::new_error_misc(tcx).into(),
ty::GenericParamDefKind::Type { .. } => Ty::new_misc_error(tcx).into(),
ty::GenericParamDefKind::Const { .. } => ty::Const::new_misc_error(
tcx,
tcx.type_of(self.def_id).instantiate(tcx, preceding_args),
)
.into(),
ty::GenericParamDefKind::Const { .. } => ty::Const::new_misc_error(tcx).into(),
}
}
}

View file

@ -385,9 +385,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
),
}
}
ty::Array(inner, len)
if len.ty() == tcx.types.usize && tcx.features().transmute_generic_consts =>
{
ty::Array(inner, len) if tcx.features().transmute_generic_consts => {
let len_eval = len.try_eval_target_usize(tcx, param_env);
if len_eval == Some(0) {
return Ok(SizeSkeleton::Known(Size::from_bytes(0)));

View file

@ -87,7 +87,7 @@ pub use self::closure::{
CAPTURE_STRUCT_LOCAL,
};
pub use self::consts::{
Const, ConstData, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree,
Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree,
};
pub use self::context::{
tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift,
@ -617,7 +617,7 @@ impl<'tcx> Term<'tcx> {
ptr.cast::<WithCachedTypeInfo<ty::TyKind<'tcx>>>().as_ref(),
))),
CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
ptr.cast::<WithCachedTypeInfo<ty::ConstData<'tcx>>>().as_ref(),
ptr.cast::<WithCachedTypeInfo<ty::ConstKind<'tcx>>>().as_ref(),
))),
_ => core::intrinsics::unreachable(),
}
@ -934,6 +934,30 @@ pub struct Placeholder<T> {
pub universe: UniverseIndex,
pub bound: T,
}
impl Placeholder<BoundVar> {
pub fn find_const_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> {
let mut candidates = env.caller_bounds().iter().filter_map(|clause| {
// `ConstArgHasType` are never desugared to be higher ranked.
match clause.kind().skip_binder() {
ty::ClauseKind::ConstArgHasType(placeholder_ct, ty) => {
assert!(!(placeholder_ct, ty).has_escaping_bound_vars());
match placeholder_ct.kind() {
ty::ConstKind::Placeholder(placeholder_ct) if placeholder_ct == self => {
Some(ty)
}
_ => None,
}
}
_ => None,
}
});
let ty = candidates.next().unwrap();
assert!(candidates.next().is_none());
ty
}
}
pub type PlaceholderRegion = Placeholder<BoundRegion>;

View file

@ -216,7 +216,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
})
.emit_unless(self.ignore_errors);
ty::Const::new_error(self.tcx, guar, ct.ty())
ty::Const::new_error(self.tcx, guar)
}
}
}

View file

@ -1459,23 +1459,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
return Ok(());
}
macro_rules! print_underscore {
() => {{
if print_ty {
self.typed_value(
|this| {
write!(this, "_")?;
Ok(())
},
|this| this.print_type(ct.ty()),
": ",
)?;
} else {
write!(self, "_")?;
}
}};
}
match ct.kind() {
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
match self.tcx().def_kind(def) {
@ -1508,11 +1491,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
ty::InferConst::Var(ct_vid) if let Some(name) = self.const_infer_name(ct_vid) => {
p!(write("{}", name))
}
_ => print_underscore!(),
_ => write!(self, "_")?,
},
ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
ty::ConstKind::Value(value) => {
return self.pretty_print_const_valtree(value, ct.ty(), print_ty);
ty::ConstKind::Value(ty, value) => {
return self.pretty_print_const_valtree(value, ty, print_ty);
}
ty::ConstKind::Bound(debruijn, bound_var) => {
@ -1666,7 +1649,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
ty::Ref(_, inner, _) => {
if let ty::Array(elem, len) = inner.kind() {
if let ty::Uint(ty::UintTy::U8) = elem.kind() {
if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() {
if let ty::ConstKind::Value(_, ty::ValTree::Leaf(int)) = len.kind() {
match self.tcx().try_get_global_alloc(prov.alloc_id()) {
Some(GlobalAlloc::Memory(alloc)) => {
let len = int.assert_bits(self.tcx().data_layout.pointer_size);

View file

@ -646,24 +646,25 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
true
}
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
(ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val,
// While this is slightly incorrect, it shouldn't matter for `min_const_generics`
// and is the better alternative to waiting until `generic_const_exprs` can
// be stabilized.
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => {
assert_eq!(a.ty(), b.ty());
if cfg!(debug_assertions) {
let a_ty = tcx.type_of(au.def).instantiate(tcx, au.args);
let b_ty = tcx.type_of(bu.def).instantiate(tcx, bu.args);
assert_eq!(a_ty, b_ty);
}
let args = relation.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
au.args,
bu.args,
)?;
return Ok(ty::Const::new_unevaluated(
tcx,
ty::UnevaluatedConst { def: au.def, args },
a.ty(),
));
return Ok(ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: au.def, args }));
}
(ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => {
match (ae.kind, be.kind) {
@ -676,7 +677,7 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
}
let args = relation.relate(ae.args(), be.args())?;
return Ok(ty::Const::new_expr(tcx, ty::Expr::new(ae.kind, args), a.ty()));
return Ok(ty::Const::new_expr(tcx, ty::Expr::new(ae.kind, args)));
}
_ => false,
};

View file

@ -201,26 +201,21 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
// If this is a value, we spend some effort to make it look nice.
if let ConstKind::Value(_) = this.data.kind() {
if let ConstKind::Value(_, _) = this.data.kind() {
return ty::tls::with(move |tcx| {
// Somehow trying to lift the valtree results in lifetime errors, so we lift the
// entire constant.
let lifted = tcx.lift(*this.data).unwrap();
let ConstKind::Value(valtree) = lifted.kind() else {
let ConstKind::Value(ty, valtree) = lifted.kind() else {
bug!("we checked that this is a valtree")
};
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
cx.pretty_print_const_valtree(valtree, lifted.ty(), /*print_ty*/ true)?;
cx.pretty_print_const_valtree(valtree, ty, /*print_ty*/ true)?;
f.write_str(&cx.into_buffer())
});
}
// Fall back to something verbose.
write!(
f,
"{kind:?}: {ty:?}",
ty = &this.map(|data| data.ty()),
kind = &this.map(|data| data.kind())
)
write!(f, "{kind:?}", kind = &this.map(|data| data.kind()))
}
}
@ -647,7 +642,6 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
self,
folder: &mut F,
) -> Result<Self, F::Error> {
let ty = self.ty().try_fold_with(folder)?;
let kind = match self.kind() {
ConstKind::Param(p) => ConstKind::Param(p.try_fold_with(folder)?),
ConstKind::Infer(i) => ConstKind::Infer(i.try_fold_with(folder)?),
@ -656,21 +650,18 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
}
ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?),
ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?),
ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?),
ConstKind::Value(t, v) => {
ConstKind::Value(t.try_fold_with(folder)?, v.try_fold_with(folder)?)
}
ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?),
ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?),
};
if ty != self.ty() || kind != self.kind() {
Ok(folder.interner().mk_ct_from_kind(kind, ty))
} else {
Ok(self)
}
if kind != self.kind() { Ok(folder.interner().mk_ct_from_kind(kind)) } else { Ok(self) }
}
}
impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
try_visit!(self.ty().visit_with(visitor));
match self.kind() {
ConstKind::Param(p) => p.visit_with(visitor),
ConstKind::Infer(i) => i.visit_with(visitor),
@ -680,7 +671,10 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
}
ConstKind::Placeholder(p) => p.visit_with(visitor),
ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
ConstKind::Value(v) => v.visit_with(visitor),
ConstKind::Value(t, v) => {
try_visit!(t.visit_with(visitor));
v.visit_with(visitor)
}
ConstKind::Error(e) => e.visit_with(visitor),
ConstKind::Expr(e) => e.visit_with(visitor),
}

View file

@ -21,6 +21,7 @@ use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
use rustc_target::spec::abi;
use rustc_type_ir::visit::TypeVisitableExt;
use std::assert_matches::debug_assert_matches;
use std::borrow::Cow;
use std::iter;
@ -339,6 +340,27 @@ impl ParamConst {
pub fn for_def(def: &ty::GenericParamDef) -> ParamConst {
ParamConst::new(def.index, def.name)
}
pub fn find_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> {
let mut candidates = env.caller_bounds().iter().filter_map(|clause| {
// `ConstArgHasType` are never desugared to be higher ranked.
match clause.kind().skip_binder() {
ty::ClauseKind::ConstArgHasType(param_ct, ty) => {
assert!(!(param_ct, ty).has_escaping_bound_vars());
match param_ct.kind() {
ty::ConstKind::Param(param_ct) if param_ct.index == self.index => Some(ty),
_ => None,
}
}
_ => None,
}
});
let ty = candidates.next().unwrap();
assert!(candidates.next().is_none());
ty
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]

View file

@ -212,21 +212,19 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
}
},
GenericArgKind::Lifetime(_) => {}
GenericArgKind::Const(parent_ct) => {
stack.push(parent_ct.ty().into());
match parent_ct.kind() {
ty::ConstKind::Infer(_)
| ty::ConstKind::Param(_)
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Value(_)
| ty::ConstKind::Error(_) => {}
GenericArgKind::Const(parent_ct) => match parent_ct.kind() {
ty::ConstKind::Infer(_)
| ty::ConstKind::Param(_)
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Error(_) => {}
ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()),
ty::ConstKind::Unevaluated(ct) => {
stack.extend(ct.args.iter().rev());
}
ty::ConstKind::Value(ty, _) => stack.push(ty.into()),
ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()),
ty::ConstKind::Unevaluated(ct) => {
stack.extend(ct.args.iter().rev());
}
}
},
}
}