summaryrefslogtreecommitdiffstats
path: root/compiler/stable_mir/src/ty.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/stable_mir/src/ty.rs
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/stable_mir/src/ty.rs')
-rw-r--r--compiler/stable_mir/src/ty.rs761
1 files changed, 722 insertions, 39 deletions
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 5dfaa0fd8..1d4d7b6d3 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -1,10 +1,15 @@
use super::{
mir::Safety,
mir::{Body, Mutability},
- with, AllocId, DefId, Symbol,
+ with, DefId, Error, Symbol,
};
+use crate::abi::Layout;
+use crate::crate_def::CrateDef;
+use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
+use crate::target::MachineInfo;
use crate::{Filename, Opaque};
-use std::fmt::{self, Debug, Formatter};
+use std::fmt::{self, Debug, Display, Formatter};
+use std::ops::Range;
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Ty(pub usize);
@@ -15,6 +20,79 @@ impl Debug for Ty {
}
}
+/// Constructors for `Ty`.
+impl Ty {
+ /// Create a new type from a given kind.
+ pub fn from_rigid_kind(kind: RigidTy) -> Ty {
+ with(|cx| cx.new_rigid_ty(kind))
+ }
+
+ /// Create a new array type.
+ pub fn try_new_array(elem_ty: Ty, size: u64) -> Result<Ty, Error> {
+ Ok(Ty::from_rigid_kind(RigidTy::Array(elem_ty, Const::try_from_target_usize(size)?)))
+ }
+
+ /// Create a new array type from Const length.
+ pub fn new_array_with_const_len(elem_ty: Ty, len: Const) -> Ty {
+ Ty::from_rigid_kind(RigidTy::Array(elem_ty, len))
+ }
+
+ /// Create a new pointer type.
+ pub fn new_ptr(pointee_ty: Ty, mutability: Mutability) -> Ty {
+ Ty::from_rigid_kind(RigidTy::RawPtr(pointee_ty, mutability))
+ }
+
+ /// Create a new reference type.
+ pub fn new_ref(reg: Region, pointee_ty: Ty, mutability: Mutability) -> Ty {
+ Ty::from_rigid_kind(RigidTy::Ref(reg, pointee_ty, mutability))
+ }
+
+ /// Create a new pointer type.
+ pub fn new_tuple(tys: &[Ty]) -> Ty {
+ Ty::from_rigid_kind(RigidTy::Tuple(Vec::from(tys)))
+ }
+
+ /// Create a new closure type.
+ pub fn new_closure(def: ClosureDef, args: GenericArgs) -> Ty {
+ Ty::from_rigid_kind(RigidTy::Closure(def, args))
+ }
+
+ /// Create a new coroutine type.
+ pub fn new_coroutine(def: CoroutineDef, args: GenericArgs, mov: Movability) -> Ty {
+ Ty::from_rigid_kind(RigidTy::Coroutine(def, args, mov))
+ }
+
+ /// Create a new box type that represents `Box<T>`, for the given inner type `T`.
+ pub fn new_box(inner_ty: Ty) -> Ty {
+ with(|cx| cx.new_box_ty(inner_ty))
+ }
+
+ /// Create a type representing `usize`.
+ pub fn usize_ty() -> Ty {
+ Ty::from_rigid_kind(RigidTy::Uint(UintTy::Usize))
+ }
+
+ /// Create a type representing `bool`.
+ pub fn bool_ty() -> Ty {
+ Ty::from_rigid_kind(RigidTy::Bool)
+ }
+
+ /// Create a type representing a signed integer.
+ pub fn signed_ty(inner: IntTy) -> Ty {
+ Ty::from_rigid_kind(RigidTy::Int(inner))
+ }
+
+ /// Create a type representing an unsigned integer.
+ pub fn unsigned_ty(inner: UintTy) -> Ty {
+ Ty::from_rigid_kind(RigidTy::Uint(inner))
+ }
+
+ /// Get a type layout.
+ pub fn layout(self) -> Result<Layout, Error> {
+ with(|cx| cx.ty_layout(self))
+ }
+}
+
impl Ty {
pub fn kind(&self) -> TyKind {
with(|context| context.ty_kind(*self))
@@ -47,6 +125,16 @@ impl Const {
pub fn ty(&self) -> Ty {
self.ty
}
+
+ /// Creates an interned usize constant.
+ fn try_from_target_usize(val: u64) -> Result<Self, Error> {
+ with(|cx| cx.usize_to_const(val))
+ }
+
+ /// Try to evaluate to a target `usize`.
+ pub fn eval_target_usize(&self) -> Result<u64, Error> {
+ with(|cx| cx.eval_target_usize(self))
+ }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -61,8 +149,8 @@ pub struct Region {
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RegionKind {
- ReEarlyBound(EarlyBoundRegion),
- ReLateBound(DebruijnIndex, BoundRegion),
+ ReEarlyParam(EarlyParamRegion),
+ ReBound(DebruijnIndex, BoundRegion),
ReStatic,
RePlaceholder(Placeholder<BoundRegion>),
ReErased,
@@ -71,7 +159,7 @@ pub enum RegionKind {
pub(crate) type DebruijnIndex = u32;
#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct EarlyBoundRegion {
+pub struct EarlyParamRegion {
pub def_id: RegionDef,
pub index: u32,
pub name: Symbol,
@@ -113,7 +201,7 @@ impl Span {
/// Return lines that corespond to this `Span`
pub fn get_lines(&self) -> LineInfo {
- with(|c| c.get_lines(&self))
+ with(|c| c.get_lines(self))
}
}
@@ -135,6 +223,226 @@ pub enum TyKind {
Bound(usize, BoundTy),
}
+impl TyKind {
+ pub fn rigid(&self) -> Option<&RigidTy> {
+ if let TyKind::RigidTy(inner) = self { Some(inner) } else { None }
+ }
+
+ #[inline]
+ pub fn is_unit(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Tuple(data)) if data.is_empty())
+ }
+
+ #[inline]
+ pub fn is_bool(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Bool))
+ }
+
+ #[inline]
+ pub fn is_char(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Char))
+ }
+
+ #[inline]
+ pub fn is_trait(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Dynamic(_, _, DynKind::Dyn)))
+ }
+
+ #[inline]
+ pub fn is_enum(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Enum)
+ }
+
+ #[inline]
+ pub fn is_struct(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Struct)
+ }
+
+ #[inline]
+ pub fn is_union(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Union)
+ }
+
+ #[inline]
+ pub fn is_adt(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Adt(..)))
+ }
+
+ #[inline]
+ pub fn is_ref(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Ref(..)))
+ }
+
+ #[inline]
+ pub fn is_fn(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::FnDef(..)))
+ }
+
+ #[inline]
+ pub fn is_fn_ptr(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::FnPtr(..)))
+ }
+
+ #[inline]
+ pub fn is_primitive(&self) -> bool {
+ matches!(
+ self,
+ TyKind::RigidTy(
+ RigidTy::Bool
+ | RigidTy::Char
+ | RigidTy::Int(_)
+ | RigidTy::Uint(_)
+ | RigidTy::Float(_)
+ )
+ )
+ }
+
+ #[inline]
+ pub fn is_float(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Float(_)))
+ }
+
+ #[inline]
+ pub fn is_integral(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Int(_) | RigidTy::Uint(_)))
+ }
+
+ #[inline]
+ pub fn is_numeric(&self) -> bool {
+ self.is_integral() || self.is_float()
+ }
+
+ #[inline]
+ pub fn is_signed(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Int(_)))
+ }
+
+ #[inline]
+ pub fn is_str(&self) -> bool {
+ *self == TyKind::RigidTy(RigidTy::Str)
+ }
+
+ #[inline]
+ pub fn is_cstr(&self) -> bool {
+ let TyKind::RigidTy(RigidTy::Adt(def, _)) = self else { return false };
+ with(|cx| cx.adt_is_cstr(*def))
+ }
+
+ #[inline]
+ pub fn is_slice(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Slice(_)))
+ }
+
+ #[inline]
+ pub fn is_array(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Array(..)))
+ }
+
+ #[inline]
+ pub fn is_mutable_ptr(&self) -> bool {
+ matches!(
+ self,
+ TyKind::RigidTy(RigidTy::RawPtr(_, Mutability::Mut))
+ | TyKind::RigidTy(RigidTy::Ref(_, _, Mutability::Mut))
+ )
+ }
+
+ #[inline]
+ pub fn is_raw_ptr(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::RawPtr(..)))
+ }
+
+ /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
+ #[inline]
+ pub fn is_any_ptr(&self) -> bool {
+ self.is_ref() || self.is_raw_ptr() || self.is_fn_ptr()
+ }
+
+ #[inline]
+ pub fn is_coroutine(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Coroutine(..)))
+ }
+
+ #[inline]
+ pub fn is_closure(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Closure(..)))
+ }
+
+ #[inline]
+ pub fn is_box(&self) -> bool {
+ match self {
+ TyKind::RigidTy(RigidTy::Adt(def, _)) => def.is_box(),
+ _ => false,
+ }
+ }
+
+ #[inline]
+ pub fn is_simd(&self) -> bool {
+ matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.is_simd())
+ }
+
+ pub fn trait_principal(&self) -> Option<Binder<ExistentialTraitRef>> {
+ if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _, _)) = self {
+ if let Some(Binder { value: ExistentialPredicate::Trait(trait_ref), bound_vars }) =
+ predicates.first()
+ {
+ Some(Binder { value: trait_ref.clone(), bound_vars: bound_vars.clone() })
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+
+ /// Returns the type of `ty[i]` for builtin types.
+ pub fn builtin_index(&self) -> Option<Ty> {
+ match self.rigid()? {
+ RigidTy::Array(ty, _) | RigidTy::Slice(ty) => Some(*ty),
+ _ => None,
+ }
+ }
+
+ /// Returns the type and mutability of `*ty` for builtin types.
+ ///
+ /// The parameter `explicit` indicates if this is an *explicit* dereference.
+ /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly.
+ pub fn builtin_deref(&self, explicit: bool) -> Option<TypeAndMut> {
+ match self.rigid()? {
+ RigidTy::Adt(def, args) if def.is_box() => {
+ Some(TypeAndMut { ty: *args.0.first()?.ty()?, mutability: Mutability::Not })
+ }
+ RigidTy::Ref(_, ty, mutability) => {
+ Some(TypeAndMut { ty: *ty, mutability: *mutability })
+ }
+ RigidTy::RawPtr(ty, mutability) if explicit => {
+ Some(TypeAndMut { ty: *ty, mutability: *mutability })
+ }
+ _ => None,
+ }
+ }
+
+ /// Get the function signature for function like types (Fn, FnPtr, and Closure)
+ pub fn fn_sig(&self) -> Option<PolyFnSig> {
+ match self {
+ TyKind::RigidTy(RigidTy::FnDef(def, args)) => Some(with(|cx| cx.fn_sig(*def, args))),
+ TyKind::RigidTy(RigidTy::FnPtr(sig)) => Some(sig.clone()),
+ TyKind::RigidTy(RigidTy::Closure(_def, args)) => Some(with(|cx| cx.closure_sig(args))),
+ _ => None,
+ }
+ }
+
+ /// Get the discriminant type for this type.
+ pub fn discriminant_ty(&self) -> Option<Ty> {
+ self.rigid().map(|ty| with(|cx| cx.rigid_ty_discriminant_ty(ty)))
+ }
+}
+
+pub struct TypeAndMut {
+ pub ty: Ty,
+ pub mutability: Mutability,
+}
+
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RigidTy {
Bool,
@@ -156,6 +464,20 @@ pub enum RigidTy {
Dynamic(Vec<Binder<ExistentialPredicate>>, Region, DynKind),
Never,
Tuple(Vec<Ty>),
+ CoroutineWitness(CoroutineWitnessDef, GenericArgs),
+}
+
+impl RigidTy {
+ /// Get the discriminant type for this type.
+ pub fn discriminant_ty(&self) -> Ty {
+ with(|cx| cx.rigid_ty_discriminant_ty(self))
+ }
+}
+
+impl From<RigidTy> for TyKind {
+ fn from(value: RigidTy) -> Self {
+ TyKind::RigidTy(value)
+ }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -168,6 +490,19 @@ pub enum IntTy {
I128,
}
+impl IntTy {
+ pub fn num_bytes(self) -> usize {
+ match self {
+ IntTy::Isize => crate::target::MachineInfo::target_pointer_width().bytes().into(),
+ IntTy::I8 => 1,
+ IntTy::I16 => 2,
+ IntTy::I32 => 4,
+ IntTy::I64 => 8,
+ IntTy::I128 => 16,
+ }
+ }
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum UintTy {
Usize,
@@ -178,6 +513,19 @@ pub enum UintTy {
U128,
}
+impl UintTy {
+ pub fn num_bytes(self) -> usize {
+ match self {
+ UintTy::Usize => crate::target::MachineInfo::target_pointer_width().bytes().into(),
+ UintTy::U8 => 1,
+ UintTy::U16 => 2,
+ UintTy::U32 => 4,
+ UintTy::U64 => 8,
+ UintTy::U128 => 16,
+ }
+ }
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FloatTy {
F32,
@@ -190,50 +538,203 @@ pub enum Movability {
Movable,
}
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct ForeignDef(pub DefId);
+crate_def! {
+ /// Hold information about a ForeignItem in a crate.
+ pub ForeignDef;
+}
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct FnDef(pub DefId);
+crate_def! {
+ /// Hold information about a function definition in a crate.
+ pub FnDef;
+}
impl FnDef {
- pub fn body(&self) -> Body {
- with(|ctx| ctx.mir_body(self.0))
+ // Get the function body if available.
+ pub fn body(&self) -> Option<Body> {
+ with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0)))
}
}
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct ClosureDef(pub DefId);
+crate_def! {
+ pub ClosureDef;
+}
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct CoroutineDef(pub DefId);
+crate_def! {
+ pub CoroutineDef;
+}
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct ParamDef(pub DefId);
+crate_def! {
+ pub ParamDef;
+}
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct BrNamedDef(pub DefId);
+crate_def! {
+ pub BrNamedDef;
+}
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct AdtDef(pub DefId);
+crate_def! {
+ pub AdtDef;
+}
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct AliasDef(pub DefId);
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
+pub enum AdtKind {
+ Enum,
+ Union,
+ Struct,
+}
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct TraitDef(pub DefId);
+impl AdtDef {
+ pub fn kind(&self) -> AdtKind {
+ with(|cx| cx.adt_kind(*self))
+ }
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct GenericDef(pub DefId);
+ /// Retrieve the type of this Adt.
+ pub fn ty(&self) -> Ty {
+ with(|cx| cx.def_ty(self.0))
+ }
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct ConstDef(pub DefId);
+ /// Retrieve the type of this Adt instantiating the type with the given arguments.
+ ///
+ /// This will assume the type can be instantiated with these arguments.
+ pub fn ty_with_args(&self, args: &GenericArgs) -> Ty {
+ with(|cx| cx.def_ty_with_args(self.0, args))
+ }
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct ImplDef(pub DefId);
+ pub fn is_box(&self) -> bool {
+ with(|cx| cx.adt_is_box(*self))
+ }
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct RegionDef(pub DefId);
+ pub fn is_simd(&self) -> bool {
+ with(|cx| cx.adt_is_simd(*self))
+ }
+
+ /// The number of variants in this ADT.
+ pub fn num_variants(&self) -> usize {
+ with(|cx| cx.adt_variants_len(*self))
+ }
+
+ /// Retrieve the variants in this ADT.
+ pub fn variants(&self) -> Vec<VariantDef> {
+ self.variants_iter().collect()
+ }
+
+ /// Iterate over the variants in this ADT.
+ pub fn variants_iter(&self) -> impl Iterator<Item = VariantDef> + '_ {
+ (0..self.num_variants())
+ .map(|idx| VariantDef { idx: VariantIdx::to_val(idx), adt_def: *self })
+ }
+
+ pub fn variant(&self, idx: VariantIdx) -> Option<VariantDef> {
+ (idx.to_index() < self.num_variants()).then_some(VariantDef { idx, adt_def: *self })
+ }
+}
+
+/// Definition of a variant, which can be either a struct / union field or an enum variant.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct VariantDef {
+ /// The variant index.
+ ///
+ /// ## Warning
+ /// Do not access this field directly!
+ pub idx: VariantIdx,
+ /// The data type where this variant comes from.
+ /// For now, we use this to retrieve information about the variant itself so we don't need to
+ /// cache more information.
+ ///
+ /// ## Warning
+ /// Do not access this field directly!
+ pub adt_def: AdtDef,
+}
+
+impl VariantDef {
+ pub fn name(&self) -> Symbol {
+ with(|cx| cx.variant_name(*self))
+ }
+
+ /// Retrieve all the fields in this variant.
+ // We expect user to cache this and use it directly since today it is expensive to generate all
+ // fields name.
+ pub fn fields(&self) -> Vec<FieldDef> {
+ with(|cx| cx.variant_fields(*self))
+ }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct FieldDef {
+ /// The field definition.
+ ///
+ /// ## Warning
+ /// Do not access this field directly! This is public for the compiler to have access to it.
+ pub def: DefId,
+
+ /// The field name.
+ pub name: Symbol,
+}
+
+impl FieldDef {
+ /// Retrieve the type of this field instantiating the type with the given arguments.
+ ///
+ /// This will assume the type can be instantiated with these arguments.
+ pub fn ty_with_args(&self, args: &GenericArgs) -> Ty {
+ with(|cx| cx.def_ty_with_args(self.def, args))
+ }
+
+ /// Retrieve the type of this field.
+ pub fn ty(&self) -> Ty {
+ with(|cx| cx.def_ty(self.def))
+ }
+}
+
+impl Display for AdtKind {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ f.write_str(match self {
+ AdtKind::Enum => "enum",
+ AdtKind::Union => "union",
+ AdtKind::Struct => "struct",
+ })
+ }
+}
+
+impl AdtKind {
+ pub fn is_enum(&self) -> bool {
+ matches!(self, AdtKind::Enum)
+ }
+
+ pub fn is_struct(&self) -> bool {
+ matches!(self, AdtKind::Struct)
+ }
+
+ pub fn is_union(&self) -> bool {
+ matches!(self, AdtKind::Union)
+ }
+}
+
+crate_def! {
+ pub AliasDef;
+}
+
+crate_def! {
+ pub TraitDef;
+}
+
+crate_def! {
+ pub GenericDef;
+}
+
+crate_def! {
+ pub ConstDef;
+}
+
+crate_def! {
+ pub ImplDef;
+}
+
+crate_def! {
+ pub RegionDef;
+}
+
+crate_def! {
+ pub CoroutineWitnessDef;
+}
/// A list of generic arguments.
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -282,6 +783,14 @@ impl GenericArgKind {
_ => panic!("{self:?}"),
}
}
+
+ /// Return the generic argument type if applicable, otherwise return `None`.
+ pub fn ty(&self) -> Option<&Ty> {
+ match self {
+ GenericArgKind::Type(ty) => Some(ty),
+ _ => None,
+ }
+ }
}
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -314,6 +823,16 @@ pub struct FnSig {
pub abi: Abi,
}
+impl FnSig {
+ pub fn output(&self) -> Ty {
+ self.inputs_and_output[self.inputs_and_output.len() - 1]
+ }
+
+ pub fn inputs(&self) -> &[Ty] {
+ &self.inputs_and_output[..self.inputs_and_output.len() - 1]
+ }
+}
+
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Abi {
Rust,
@@ -345,12 +864,47 @@ pub enum Abi {
RiscvInterruptS,
}
+/// A binder represents a possibly generic type and its bound vars.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Binder<T> {
pub value: T,
pub bound_vars: Vec<BoundVariableKind>,
}
+impl<T> Binder<T> {
+ /// Create a new binder with the given bound vars.
+ pub fn bind_with_vars(value: T, bound_vars: Vec<BoundVariableKind>) -> Self {
+ Binder { value, bound_vars }
+ }
+
+ /// Create a new binder with no bounded variable.
+ pub fn dummy(value: T) -> Self {
+ Binder { value, bound_vars: vec![] }
+ }
+
+ pub fn skip_binder(self) -> T {
+ self.value
+ }
+
+ pub fn map_bound_ref<F, U>(&self, f: F) -> Binder<U>
+ where
+ F: FnOnce(&T) -> U,
+ {
+ let Binder { value, bound_vars } = self;
+ let new_value = f(value);
+ Binder { value: new_value, bound_vars: bound_vars.clone() }
+ }
+
+ pub fn map_bound<F, U>(self, f: F) -> Binder<U>
+ where
+ F: FnOnce(T) -> U,
+ {
+ let Binder { value, bound_vars } = self;
+ let new_value = f(value);
+ Binder { value: new_value, bound_vars }
+ }
+}
+
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EarlyBinder<T> {
pub value: T,
@@ -389,12 +943,27 @@ pub enum ExistentialPredicate {
AutoTrait(TraitDef),
}
+/// An existential reference to a trait where `Self` is not included.
+///
+/// The `generic_args` will include any other known argument.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExistentialTraitRef {
pub def_id: TraitDef,
pub generic_args: GenericArgs,
}
+impl Binder<ExistentialTraitRef> {
+ pub fn with_self_ty(&self, self_ty: Ty) -> Binder<TraitRef> {
+ self.map_bound_ref(|trait_ref| trait_ref.with_self_ty(self_ty))
+ }
+}
+
+impl ExistentialTraitRef {
+ pub fn with_self_ty(&self, self_ty: Ty) -> TraitRef {
+ TraitRef::new(self.def_id, self_ty, &self.generic_args)
+ }
+}
+
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExistentialProjection {
pub def_id: TraitDef,
@@ -417,21 +986,21 @@ pub struct BoundTy {
pub type Bytes = Vec<Option<u8>>;
pub type Size = usize;
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct Prov(pub AllocId);
pub type Align = u64;
pub type Promoted = u32;
pub type InitMaskMaterialized = Vec<u64>;
/// Stores the provenance information of pointers stored in memory.
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ProvenanceMap {
/// Provenance in this map applies from the given offset for an entire pointer-size worth of
/// bytes. Two entries in this map are always at least a pointer size apart.
pub ptrs: Vec<(Size, Prov)>,
}
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Allocation {
pub bytes: Bytes,
pub provenance: ProvenanceMap,
@@ -439,6 +1008,74 @@ pub struct Allocation {
pub mutability: Mutability,
}
+impl Allocation {
+ /// Get a vector of bytes for an Allocation that has been fully initialized
+ pub fn raw_bytes(&self) -> Result<Vec<u8>, Error> {
+ self.bytes
+ .iter()
+ .copied()
+ .collect::<Option<Vec<_>>>()
+ .ok_or_else(|| error!("Found uninitialized bytes: `{:?}`", self.bytes))
+ }
+
+ /// Read a uint value from the specified range.
+ pub fn read_partial_uint(&self, range: Range<usize>) -> Result<u128, Error> {
+ if range.end - range.start > 16 {
+ return Err(error!("Allocation is bigger than largest integer"));
+ }
+ if range.end > self.bytes.len() {
+ return Err(error!(
+ "Range is out of bounds. Allocation length is `{}`, but requested range `{:?}`",
+ self.bytes.len(),
+ range
+ ));
+ }
+ let raw = self.bytes[range]
+ .iter()
+ .copied()
+ .collect::<Option<Vec<_>>>()
+ .ok_or_else(|| error!("Found uninitialized bytes: `{:?}`", self.bytes))?;
+ read_target_uint(&raw)
+ }
+
+ /// Read this allocation and try to convert it to an unassigned integer.
+ pub fn read_uint(&self) -> Result<u128, Error> {
+ if self.bytes.len() > 16 {
+ return Err(error!("Allocation is bigger than largest integer"));
+ }
+ let raw = self.raw_bytes()?;
+ read_target_uint(&raw)
+ }
+
+ /// Read this allocation and try to convert it to a signed integer.
+ pub fn read_int(&self) -> Result<i128, Error> {
+ if self.bytes.len() > 16 {
+ return Err(error!("Allocation is bigger than largest integer"));
+ }
+ let raw = self.raw_bytes()?;
+ read_target_int(&raw)
+ }
+
+ /// Read this allocation and try to convert it to a boolean.
+ pub fn read_bool(&self) -> Result<bool, Error> {
+ match self.read_int()? {
+ 0 => Ok(false),
+ 1 => Ok(true),
+ val @ _ => Err(error!("Unexpected value for bool: `{val}`")),
+ }
+ }
+
+ /// Read this allocation as a pointer and return whether it represents a `null` pointer.
+ pub fn is_null(&self) -> Result<bool, Error> {
+ let len = self.bytes.len();
+ let ptr_len = MachineInfo::target_pointer_width().bytes();
+ if len != ptr_len {
+ return Err(error!("Expected width of pointer (`{ptr_len}`), but found: `{len}`"));
+ }
+ Ok(self.read_uint()? == 0 && self.provenance.ptrs.is_empty())
+ }
+}
+
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ConstantKind {
Allocated(Allocation),
@@ -500,10 +1137,39 @@ impl TraitDecl {
pub type ImplTrait = EarlyBinder<TraitRef>;
+/// A complete reference to a trait, i.e., one where `Self` is known.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TraitRef {
pub def_id: TraitDef,
- pub args: GenericArgs,
+ /// The generic arguments for this definition.
+ /// The first element must always be type, and it represents `Self`.
+ args: GenericArgs,
+}
+
+impl TraitRef {
+ pub fn new(def_id: TraitDef, self_ty: Ty, gen_args: &GenericArgs) -> TraitRef {
+ let mut args = vec![GenericArgKind::Type(self_ty)];
+ args.extend_from_slice(&gen_args.0);
+ TraitRef { def_id, args: GenericArgs(args) }
+ }
+
+ pub fn try_new(def_id: TraitDef, args: GenericArgs) -> Result<TraitRef, ()> {
+ match &args.0[..] {
+ [GenericArgKind::Type(_), ..] => Ok(TraitRef { def_id, args }),
+ _ => Err(()),
+ }
+ }
+
+ pub fn args(&self) -> &GenericArgs {
+ &self.args
+ }
+
+ pub fn self_ty(&self) -> Ty {
+ let GenericArgKind::Type(self_ty) = self.args.0[0] else {
+ panic!("Self must be a type, but found: {:?}", self.args.0[0])
+ };
+ self_ty
+ }
}
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -542,7 +1208,6 @@ pub struct GenericPredicates {
pub enum PredicateKind {
Clause(ClauseKind),
ObjectSafe(TraitDef),
- ClosureKind(ClosureDef, GenericArgs, ClosureKind),
SubType(SubtypePredicate),
Coerce(CoercePredicate),
ConstEquate(Const, Const),
@@ -633,3 +1298,21 @@ macro_rules! index_impl {
index_impl!(ConstId);
index_impl!(Ty);
index_impl!(Span);
+
+/// The source-order index of a variant in a type.
+///
+/// For example, in the following types,
+/// ```ignore(illustrative)
+/// enum Demo1 {
+/// Variant0 { a: bool, b: i32 },
+/// Variant1 { c: u8, d: u64 },
+/// }
+/// struct Demo2 { e: u8, f: u16, g: u8 }
+/// ```
+/// `a` is in the variant with the `VariantIdx` of `0`,
+/// `c` is in the variant with the `VariantIdx` of `1`, and
+/// `g` is in the variant with the `VariantIdx` of `0`.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct VariantIdx(usize);
+
+index_impl!(VariantIdx);