From 9918693037dce8aa4bb6f08741b6812923486c18 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 11:26:03 +0200 Subject: Merging upstream version 1.76.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/stable_mir/src/ty.rs | 761 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 722 insertions(+), 39 deletions(-) (limited to 'compiler/stable_mir/src/ty.rs') 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 { + 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`, 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 { + 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 { + with(|cx| cx.usize_to_const(val)) + } + + /// Try to evaluate to a target `usize`. + pub fn eval_target_usize(&self) -> Result { + 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), 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> { + 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 { + 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 { + 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 { + 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 { + 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>, Region, DynKind), Never, Tuple(Vec), + 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 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 { + 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 { + self.variants_iter().collect() + } + + /// Iterate over the variants in this ADT. + pub fn variants_iter(&self) -> impl Iterator + '_ { + (0..self.num_variants()) + .map(|idx| VariantDef { idx: VariantIdx::to_val(idx), adt_def: *self }) + } + + pub fn variant(&self, idx: VariantIdx) -> Option { + (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 { + 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 { pub value: T, pub bound_vars: Vec, } +impl Binder { + /// Create a new binder with the given bound vars. + pub fn bind_with_vars(value: T, bound_vars: Vec) -> 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(&self, f: F) -> Binder + 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(self, f: F) -> Binder + 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 { 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 { + pub fn with_self_ty(&self, self_ty: Ty) -> Binder { + 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>; 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; /// 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, Error> { + self.bytes + .iter() + .copied() + .collect::>>() + .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) -> Result { + 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::>>() + .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 { + 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 { + 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 { + 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 { + 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; +/// 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 { + 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); -- cgit v1.2.3