As part of this reorganization, some traits need to be moved from `rustc_smir::context::traits` to `stable_mir::unstable::internal_cx`. These traits are specifically designed for `InternalCx` to clarify the behavior of different functions that share the same name. This move is necessary to avoid orphan rule violations.
1656 lines
42 KiB
Rust
1656 lines
42 KiB
Rust
use std::fmt::{self, Debug, Display, Formatter};
|
|
use std::ops::Range;
|
|
|
|
use serde::Serialize;
|
|
|
|
use super::abi::ReprOptions;
|
|
use super::mir::{Body, Mutability, Safety};
|
|
use super::{DefId, Error, Symbol, with};
|
|
use crate::abi::{FnAbi, Layout};
|
|
use crate::crate_def::{CrateDef, CrateDefItems, CrateDefType};
|
|
use crate::mir::alloc::{AllocId, read_target_int, read_target_uint};
|
|
use crate::mir::mono::StaticDef;
|
|
use crate::target::MachineInfo;
|
|
use crate::{Filename, IndexedVal, Opaque};
|
|
|
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)]
|
|
pub struct Ty(usize);
|
|
|
|
impl Debug for Ty {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("Ty").field("id", &self.0).field("kind", &self.kind()).finish()
|
|
}
|
|
}
|
|
|
|
/// 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, TyConst::try_from_target_usize(size)?)))
|
|
}
|
|
|
|
/// Create a new array type from Const length.
|
|
pub fn new_array_with_const_len(elem_ty: Ty, len: TyConst) -> 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 closure type.
|
|
pub fn new_coroutine_closure(def: CoroutineClosureDef, args: GenericArgs) -> Ty {
|
|
Ty::from_rigid_kind(RigidTy::CoroutineClosure(def, args))
|
|
}
|
|
|
|
/// 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))
|
|
}
|
|
}
|
|
|
|
/// Represents a pattern in the type system
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum Pattern {
|
|
Range { start: Option<TyConst>, end: Option<TyConst>, include_end: bool },
|
|
}
|
|
|
|
/// Represents a constant in the type system
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct TyConst {
|
|
pub(crate) kind: TyConstKind,
|
|
pub id: TyConstId,
|
|
}
|
|
|
|
impl TyConst {
|
|
pub fn new(kind: TyConstKind, id: TyConstId) -> TyConst {
|
|
Self { kind, id }
|
|
}
|
|
|
|
/// Retrieve the constant kind.
|
|
pub fn kind(&self) -> &TyConstKind {
|
|
&self.kind
|
|
}
|
|
|
|
/// Creates an interned usize constant.
|
|
pub fn try_from_target_usize(val: u64) -> Result<Self, Error> {
|
|
with(|cx| cx.try_new_ty_const_uint(val.into(), UintTy::Usize))
|
|
}
|
|
|
|
/// Try to evaluate to a target `usize`.
|
|
pub fn eval_target_usize(&self) -> Result<u64, Error> {
|
|
with(|cx| cx.eval_target_usize_ty(self))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum TyConstKind {
|
|
Param(ParamConst),
|
|
Bound(DebruijnIndex, BoundVar),
|
|
Unevaluated(ConstDef, GenericArgs),
|
|
|
|
// FIXME: These should be a valtree
|
|
Value(Ty, Allocation),
|
|
ZSTValue(Ty),
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct TyConstId(usize);
|
|
|
|
/// Represents a constant in MIR
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct MirConst {
|
|
/// The constant kind.
|
|
pub(crate) kind: ConstantKind,
|
|
/// The constant type.
|
|
pub(crate) ty: Ty,
|
|
/// Used for internal tracking of the internal constant.
|
|
pub id: MirConstId,
|
|
}
|
|
|
|
impl MirConst {
|
|
/// Build a constant. Note that this should only be used by the compiler.
|
|
pub fn new(kind: ConstantKind, ty: Ty, id: MirConstId) -> MirConst {
|
|
MirConst { kind, ty, id }
|
|
}
|
|
|
|
/// Retrieve the constant kind.
|
|
pub fn kind(&self) -> &ConstantKind {
|
|
&self.kind
|
|
}
|
|
|
|
/// Get the constant type.
|
|
pub fn ty(&self) -> Ty {
|
|
self.ty
|
|
}
|
|
|
|
/// Try to evaluate to a target `usize`.
|
|
pub fn eval_target_usize(&self) -> Result<u64, Error> {
|
|
with(|cx| cx.eval_target_usize(self))
|
|
}
|
|
|
|
/// Create a constant that represents a new zero-sized constant of type T.
|
|
/// Fails if the type is not a ZST or if it doesn't have a known size.
|
|
pub fn try_new_zero_sized(ty: Ty) -> Result<MirConst, Error> {
|
|
with(|cx| cx.try_new_const_zst(ty))
|
|
}
|
|
|
|
/// Build a new constant that represents the given string.
|
|
///
|
|
/// Note that there is no guarantee today about duplication of the same constant.
|
|
/// I.e.: Calling this function multiple times with the same argument may or may not return
|
|
/// the same allocation.
|
|
pub fn from_str(value: &str) -> MirConst {
|
|
with(|cx| cx.new_const_str(value))
|
|
}
|
|
|
|
/// Build a new constant that represents the given boolean value.
|
|
pub fn from_bool(value: bool) -> MirConst {
|
|
with(|cx| cx.new_const_bool(value))
|
|
}
|
|
|
|
/// Build a new constant that represents the given unsigned integer.
|
|
pub fn try_from_uint(value: u128, uint_ty: UintTy) -> Result<MirConst, Error> {
|
|
with(|cx| cx.try_new_const_uint(value, uint_ty))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
|
|
pub struct MirConstId(usize);
|
|
|
|
type Ident = Opaque;
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct Region {
|
|
pub kind: RegionKind,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum RegionKind {
|
|
ReEarlyParam(EarlyParamRegion),
|
|
ReBound(DebruijnIndex, BoundRegion),
|
|
ReStatic,
|
|
RePlaceholder(Placeholder<BoundRegion>),
|
|
ReErased,
|
|
}
|
|
|
|
pub(crate) type DebruijnIndex = u32;
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct EarlyParamRegion {
|
|
pub index: u32,
|
|
pub name: Symbol,
|
|
}
|
|
|
|
pub(crate) type BoundVar = u32;
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct BoundRegion {
|
|
pub var: BoundVar,
|
|
pub kind: BoundRegionKind,
|
|
}
|
|
|
|
pub(crate) type UniverseIndex = u32;
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct Placeholder<T> {
|
|
pub universe: UniverseIndex,
|
|
pub bound: T,
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Serialize)]
|
|
pub struct Span(usize);
|
|
|
|
impl Debug for Span {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("Span")
|
|
.field("id", &self.0)
|
|
.field("repr", &with(|cx| cx.span_to_string(*self)))
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl Span {
|
|
/// Return filename for diagnostic purposes
|
|
pub fn get_filename(&self) -> Filename {
|
|
with(|c| c.get_filename(self))
|
|
}
|
|
|
|
/// Return lines that correspond to this `Span`
|
|
pub fn get_lines(&self) -> LineInfo {
|
|
with(|c| c.get_lines(self))
|
|
}
|
|
|
|
/// Return the span location to be printed in diagnostic messages.
|
|
///
|
|
/// This may leak local file paths and should not be used to build artifacts that may be
|
|
/// distributed.
|
|
pub fn diagnostic(&self) -> String {
|
|
with(|c| c.span_to_string(*self))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Serialize)]
|
|
/// Information you get from `Span` in a struct form.
|
|
/// Line and col start from 1.
|
|
pub struct LineInfo {
|
|
pub start_line: usize,
|
|
pub start_col: usize,
|
|
pub end_line: usize,
|
|
pub end_col: usize,
|
|
}
|
|
|
|
impl LineInfo {
|
|
pub fn from(lines: (usize, usize, usize, usize)) -> Self {
|
|
LineInfo { start_line: lines.0, start_col: lines.1, end_line: lines.2, end_col: lines.3 }
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum TyKind {
|
|
RigidTy(RigidTy),
|
|
Alias(AliasKind, AliasTy),
|
|
Param(ParamTy),
|
|
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 raw 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)))
|
|
}
|
|
|
|
/// Deconstruct a function type if this is one.
|
|
pub fn fn_def(&self) -> Option<(FnDef, &GenericArgs)> {
|
|
if let TyKind::RigidTy(RigidTy::FnDef(def, args)) = self {
|
|
Some((*def, args))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct TypeAndMut {
|
|
pub ty: Ty,
|
|
pub mutability: Mutability,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum RigidTy {
|
|
Bool,
|
|
Char,
|
|
Int(IntTy),
|
|
Uint(UintTy),
|
|
Float(FloatTy),
|
|
Adt(AdtDef, GenericArgs),
|
|
Foreign(ForeignDef),
|
|
Str,
|
|
Array(Ty, TyConst),
|
|
Pat(Ty, Pattern),
|
|
Slice(Ty),
|
|
RawPtr(Ty, Mutability),
|
|
Ref(Region, Ty, Mutability),
|
|
FnDef(FnDef, GenericArgs),
|
|
FnPtr(PolyFnSig),
|
|
Closure(ClosureDef, GenericArgs),
|
|
// FIXME(stable_mir): Movability here is redundant
|
|
Coroutine(CoroutineDef, GenericArgs, Movability),
|
|
CoroutineClosure(CoroutineClosureDef, GenericArgs),
|
|
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, Serialize)]
|
|
pub enum IntTy {
|
|
Isize,
|
|
I8,
|
|
I16,
|
|
I32,
|
|
I64,
|
|
I128,
|
|
}
|
|
|
|
impl IntTy {
|
|
pub fn num_bytes(self) -> usize {
|
|
match self {
|
|
IntTy::Isize => MachineInfo::target_pointer_width().bytes(),
|
|
IntTy::I8 => 1,
|
|
IntTy::I16 => 2,
|
|
IntTy::I32 => 4,
|
|
IntTy::I64 => 8,
|
|
IntTy::I128 => 16,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
|
|
pub enum UintTy {
|
|
Usize,
|
|
U8,
|
|
U16,
|
|
U32,
|
|
U64,
|
|
U128,
|
|
}
|
|
|
|
impl UintTy {
|
|
pub fn num_bytes(self) -> usize {
|
|
match self {
|
|
UintTy::Usize => MachineInfo::target_pointer_width().bytes(),
|
|
UintTy::U8 => 1,
|
|
UintTy::U16 => 2,
|
|
UintTy::U32 => 4,
|
|
UintTy::U64 => 8,
|
|
UintTy::U128 => 16,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
|
|
pub enum FloatTy {
|
|
F16,
|
|
F32,
|
|
F64,
|
|
F128,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
|
|
pub enum Movability {
|
|
Static,
|
|
Movable,
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub ForeignModuleDef;
|
|
}
|
|
|
|
impl ForeignModuleDef {
|
|
pub fn module(&self) -> ForeignModule {
|
|
with(|cx| cx.foreign_module(*self))
|
|
}
|
|
}
|
|
|
|
pub struct ForeignModule {
|
|
pub def_id: ForeignModuleDef,
|
|
pub abi: Abi,
|
|
}
|
|
|
|
impl ForeignModule {
|
|
pub fn items(&self) -> Vec<ForeignDef> {
|
|
with(|cx| cx.foreign_items(self.def_id))
|
|
}
|
|
}
|
|
|
|
crate_def_with_ty! {
|
|
/// Hold information about a ForeignItem in a crate.
|
|
#[derive(Serialize)]
|
|
pub ForeignDef;
|
|
}
|
|
|
|
impl ForeignDef {
|
|
pub fn kind(&self) -> ForeignItemKind {
|
|
with(|cx| cx.foreign_item_kind(*self))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
|
|
pub enum ForeignItemKind {
|
|
Fn(FnDef),
|
|
Static(StaticDef),
|
|
Type(Ty),
|
|
}
|
|
|
|
crate_def_with_ty! {
|
|
/// Hold information about a function definition in a crate.
|
|
#[derive(Serialize)]
|
|
pub FnDef;
|
|
}
|
|
|
|
impl FnDef {
|
|
// 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)))
|
|
}
|
|
|
|
// Check if the function body is available.
|
|
pub fn has_body(&self) -> bool {
|
|
with(|ctx| ctx.has_body(self.0))
|
|
}
|
|
|
|
/// Get the information of the intrinsic if this function is a definition of one.
|
|
pub fn as_intrinsic(&self) -> Option<IntrinsicDef> {
|
|
with(|cx| cx.intrinsic(self.def_id()))
|
|
}
|
|
|
|
/// Check if the function is an intrinsic.
|
|
#[inline]
|
|
pub fn is_intrinsic(&self) -> bool {
|
|
self.as_intrinsic().is_some()
|
|
}
|
|
|
|
/// Get the function signature for this function definition.
|
|
pub fn fn_sig(&self) -> PolyFnSig {
|
|
let kind = self.ty().kind();
|
|
kind.fn_sig().unwrap()
|
|
}
|
|
}
|
|
|
|
crate_def_with_ty! {
|
|
#[derive(Serialize)]
|
|
pub IntrinsicDef;
|
|
}
|
|
|
|
impl IntrinsicDef {
|
|
/// Returns the plain name of the intrinsic.
|
|
/// e.g., `transmute` for `core::intrinsics::transmute`.
|
|
pub fn fn_name(&self) -> Symbol {
|
|
with(|cx| cx.intrinsic_name(*self))
|
|
}
|
|
|
|
/// Returns whether the intrinsic has no meaningful body and all backends
|
|
/// need to shim all calls to it.
|
|
pub fn must_be_overridden(&self) -> bool {
|
|
with(|cx| !cx.has_body(self.0))
|
|
}
|
|
}
|
|
|
|
impl From<IntrinsicDef> for FnDef {
|
|
fn from(def: IntrinsicDef) -> Self {
|
|
FnDef(def.0)
|
|
}
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub ClosureDef;
|
|
}
|
|
|
|
impl ClosureDef {
|
|
/// Retrieves the body of the closure definition. Returns None if the body
|
|
/// isn't available.
|
|
pub fn body(&self) -> Option<Body> {
|
|
with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0)))
|
|
}
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub CoroutineDef;
|
|
}
|
|
|
|
impl CoroutineDef {
|
|
/// Retrieves the body of the coroutine definition. Returns None if the body
|
|
/// isn't available.
|
|
pub fn body(&self) -> Option<Body> {
|
|
with(|cx| cx.has_body(self.0).then(|| cx.mir_body(self.0)))
|
|
}
|
|
|
|
pub fn discriminant_for_variant(&self, args: &GenericArgs, idx: VariantIdx) -> Discr {
|
|
with(|cx| cx.coroutine_discr_for_variant(*self, args, idx))
|
|
}
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub CoroutineClosureDef;
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub ParamDef;
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub BrNamedDef;
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub AdtDef;
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
|
|
pub enum AdtKind {
|
|
Enum,
|
|
Union,
|
|
Struct,
|
|
}
|
|
|
|
impl AdtDef {
|
|
pub fn kind(&self) -> AdtKind {
|
|
with(|cx| cx.adt_kind(*self))
|
|
}
|
|
|
|
/// Retrieve the type of this Adt.
|
|
pub fn ty(&self) -> Ty {
|
|
with(|cx| cx.def_ty(self.0))
|
|
}
|
|
|
|
/// Retrieve the type of this Adt by instantiating and normalizing it 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))
|
|
}
|
|
|
|
pub fn is_box(&self) -> bool {
|
|
with(|cx| cx.adt_is_box(*self))
|
|
}
|
|
|
|
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 })
|
|
}
|
|
|
|
pub fn repr(&self) -> ReprOptions {
|
|
with(|cx| cx.adt_repr(*self))
|
|
}
|
|
|
|
pub fn discriminant_for_variant(&self, idx: VariantIdx) -> Discr {
|
|
with(|cx| cx.adt_discr_for_variant(*self, idx))
|
|
}
|
|
}
|
|
|
|
pub struct Discr {
|
|
pub val: u128,
|
|
pub ty: Ty,
|
|
}
|
|
|
|
/// Definition of a variant, which can be either a struct / union field or an enum variant.
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
|
|
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, Serialize)]
|
|
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 and normalizing it 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! {
|
|
#[derive(Serialize)]
|
|
pub AliasDef;
|
|
}
|
|
|
|
crate_def! {
|
|
/// A trait's definition.
|
|
#[derive(Serialize)]
|
|
pub TraitDef;
|
|
}
|
|
|
|
impl_crate_def_items! {
|
|
TraitDef;
|
|
}
|
|
|
|
impl TraitDef {
|
|
pub fn declaration(trait_def: &TraitDef) -> TraitDecl {
|
|
with(|cx| cx.trait_decl(trait_def))
|
|
}
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub GenericDef;
|
|
}
|
|
|
|
crate_def_with_ty! {
|
|
#[derive(Serialize)]
|
|
pub ConstDef;
|
|
}
|
|
|
|
crate_def! {
|
|
/// A trait impl definition.
|
|
#[derive(Serialize)]
|
|
pub ImplDef;
|
|
}
|
|
|
|
impl_crate_def_items! {
|
|
ImplDef;
|
|
}
|
|
|
|
impl ImplDef {
|
|
/// Retrieve information about this implementation.
|
|
pub fn trait_impl(&self) -> ImplTrait {
|
|
with(|cx| cx.trait_impl(self))
|
|
}
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub RegionDef;
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub CoroutineWitnessDef;
|
|
}
|
|
|
|
/// A list of generic arguments.
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct GenericArgs(pub Vec<GenericArgKind>);
|
|
|
|
impl std::ops::Index<ParamTy> for GenericArgs {
|
|
type Output = Ty;
|
|
|
|
fn index(&self, index: ParamTy) -> &Self::Output {
|
|
self.0[index.index as usize].expect_ty()
|
|
}
|
|
}
|
|
|
|
impl std::ops::Index<ParamConst> for GenericArgs {
|
|
type Output = TyConst;
|
|
|
|
fn index(&self, index: ParamConst) -> &Self::Output {
|
|
self.0[index.index as usize].expect_const()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum GenericArgKind {
|
|
Lifetime(Region),
|
|
Type(Ty),
|
|
Const(TyConst),
|
|
}
|
|
|
|
impl GenericArgKind {
|
|
/// Panic if this generic argument is not a type, otherwise
|
|
/// return the type.
|
|
#[track_caller]
|
|
pub fn expect_ty(&self) -> &Ty {
|
|
match self {
|
|
GenericArgKind::Type(ty) => ty,
|
|
_ => panic!("{self:?}"),
|
|
}
|
|
}
|
|
|
|
/// Panic if this generic argument is not a const, otherwise
|
|
/// return the const.
|
|
#[track_caller]
|
|
pub fn expect_const(&self) -> &TyConst {
|
|
match self {
|
|
GenericArgKind::Const(c) => c,
|
|
_ => 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, Serialize)]
|
|
pub enum TermKind {
|
|
Type(Ty),
|
|
Const(TyConst),
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum AliasKind {
|
|
Projection,
|
|
Inherent,
|
|
Opaque,
|
|
Free,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct AliasTy {
|
|
pub def_id: AliasDef,
|
|
pub args: GenericArgs,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct AliasTerm {
|
|
pub def_id: AliasDef,
|
|
pub args: GenericArgs,
|
|
}
|
|
|
|
pub type PolyFnSig = Binder<FnSig>;
|
|
|
|
impl PolyFnSig {
|
|
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
|
|
///
|
|
/// NB: this doesn't handle virtual calls - those should use `Instance::fn_abi`
|
|
/// instead, where the instance is an `InstanceKind::Virtual`.
|
|
pub fn fn_ptr_abi(self) -> Result<FnAbi, Error> {
|
|
with(|cx| cx.fn_ptr_abi(self))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct FnSig {
|
|
pub inputs_and_output: Vec<Ty>,
|
|
pub c_variadic: bool,
|
|
pub safety: Safety,
|
|
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, Serialize)]
|
|
pub enum Abi {
|
|
Rust,
|
|
C { unwind: bool },
|
|
Cdecl { unwind: bool },
|
|
Stdcall { unwind: bool },
|
|
Fastcall { unwind: bool },
|
|
Vectorcall { unwind: bool },
|
|
Thiscall { unwind: bool },
|
|
Aapcs { unwind: bool },
|
|
Win64 { unwind: bool },
|
|
SysV64 { unwind: bool },
|
|
PtxKernel,
|
|
Msp430Interrupt,
|
|
X86Interrupt,
|
|
GpuKernel,
|
|
EfiApi,
|
|
AvrInterrupt,
|
|
AvrNonBlockingInterrupt,
|
|
CCmseNonSecureCall,
|
|
CCmseNonSecureEntry,
|
|
System { unwind: bool },
|
|
RustCall,
|
|
Unadjusted,
|
|
RustCold,
|
|
RiscvInterruptM,
|
|
RiscvInterruptS,
|
|
RustInvalid,
|
|
Custom,
|
|
}
|
|
|
|
/// A binder represents a possibly generic type and its bound vars.
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
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, Serialize)]
|
|
pub struct EarlyBinder<T> {
|
|
pub value: T,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum BoundVariableKind {
|
|
Ty(BoundTyKind),
|
|
Region(BoundRegionKind),
|
|
Const,
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
|
|
pub enum BoundTyKind {
|
|
Anon,
|
|
Param(ParamDef, String),
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum BoundRegionKind {
|
|
BrAnon,
|
|
BrNamed(BrNamedDef, String),
|
|
BrEnv,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum DynKind {
|
|
Dyn,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum ExistentialPredicate {
|
|
Trait(ExistentialTraitRef),
|
|
Projection(ExistentialProjection),
|
|
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, Serialize)]
|
|
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, Serialize)]
|
|
pub struct ExistentialProjection {
|
|
pub def_id: TraitDef,
|
|
pub generic_args: GenericArgs,
|
|
pub term: TermKind,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct ParamTy {
|
|
pub index: u32,
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct BoundTy {
|
|
pub var: usize,
|
|
pub kind: BoundTyKind,
|
|
}
|
|
|
|
pub type Bytes = Vec<Option<u8>>;
|
|
|
|
/// Size in bytes.
|
|
pub type Size = usize;
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
|
|
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, Hash, Serialize)]
|
|
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, Hash, Serialize)]
|
|
pub struct Allocation {
|
|
pub bytes: Bytes,
|
|
pub provenance: ProvenanceMap,
|
|
pub align: Align,
|
|
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, Serialize)]
|
|
pub enum ConstantKind {
|
|
Ty(TyConst),
|
|
Allocated(Allocation),
|
|
Unevaluated(UnevaluatedConst),
|
|
Param(ParamConst),
|
|
/// Store ZST constants.
|
|
/// We have to special handle these constants since its type might be generic.
|
|
ZeroSized,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct ParamConst {
|
|
pub index: u32,
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct UnevaluatedConst {
|
|
pub def: ConstDef,
|
|
pub args: GenericArgs,
|
|
pub promoted: Option<Promoted>,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
|
|
pub enum TraitSpecializationKind {
|
|
None,
|
|
Marker,
|
|
AlwaysApplicable,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct TraitDecl {
|
|
pub def_id: TraitDef,
|
|
pub safety: Safety,
|
|
pub paren_sugar: bool,
|
|
pub has_auto_impl: bool,
|
|
pub is_marker: bool,
|
|
pub is_coinductive: bool,
|
|
pub skip_array_during_method_dispatch: bool,
|
|
pub skip_boxed_slice_during_method_dispatch: bool,
|
|
pub specialization_kind: TraitSpecializationKind,
|
|
pub must_implement_one_of: Option<Vec<Ident>>,
|
|
pub implement_via_object: bool,
|
|
pub deny_explicit_impl: bool,
|
|
}
|
|
|
|
impl TraitDecl {
|
|
pub fn generics_of(&self) -> Generics {
|
|
with(|cx| cx.generics_of(self.def_id.0))
|
|
}
|
|
|
|
pub fn predicates_of(&self) -> GenericPredicates {
|
|
with(|cx| cx.predicates_of(self.def_id.0))
|
|
}
|
|
|
|
pub fn explicit_predicates_of(&self) -> GenericPredicates {
|
|
with(|cx| cx.explicit_predicates_of(self.def_id.0))
|
|
}
|
|
}
|
|
|
|
pub type ImplTrait = EarlyBinder<TraitRef>;
|
|
|
|
/// A complete reference to a trait, i.e., one where `Self` is known.
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct TraitRef {
|
|
pub def_id: TraitDef,
|
|
/// 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, Serialize)]
|
|
pub struct Generics {
|
|
pub parent: Option<GenericDef>,
|
|
pub parent_count: usize,
|
|
pub params: Vec<GenericParamDef>,
|
|
pub param_def_id_to_index: Vec<(GenericDef, u32)>,
|
|
pub has_self: bool,
|
|
pub has_late_bound_regions: Option<Span>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum GenericParamDefKind {
|
|
Lifetime,
|
|
Type { has_default: bool, synthetic: bool },
|
|
Const { has_default: bool },
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct GenericParamDef {
|
|
pub name: super::Symbol,
|
|
pub def_id: GenericDef,
|
|
pub index: u32,
|
|
pub pure_wrt_drop: bool,
|
|
pub kind: GenericParamDefKind,
|
|
}
|
|
|
|
pub struct GenericPredicates {
|
|
pub parent: Option<TraitDef>,
|
|
pub predicates: Vec<(PredicateKind, Span)>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum PredicateKind {
|
|
Clause(ClauseKind),
|
|
DynCompatible(TraitDef),
|
|
SubType(SubtypePredicate),
|
|
Coerce(CoercePredicate),
|
|
ConstEquate(TyConst, TyConst),
|
|
Ambiguous,
|
|
AliasRelate(TermKind, TermKind, AliasRelationDirection),
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum ClauseKind {
|
|
Trait(TraitPredicate),
|
|
RegionOutlives(RegionOutlivesPredicate),
|
|
TypeOutlives(TypeOutlivesPredicate),
|
|
Projection(ProjectionPredicate),
|
|
ConstArgHasType(TyConst, Ty),
|
|
WellFormed(TermKind),
|
|
ConstEvaluatable(TyConst),
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum ClosureKind {
|
|
Fn,
|
|
FnMut,
|
|
FnOnce,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct SubtypePredicate {
|
|
pub a: Ty,
|
|
pub b: Ty,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct CoercePredicate {
|
|
pub a: Ty,
|
|
pub b: Ty,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum AliasRelationDirection {
|
|
Equate,
|
|
Subtype,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct TraitPredicate {
|
|
pub trait_ref: TraitRef,
|
|
pub polarity: PredicatePolarity,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct OutlivesPredicate<A, B>(pub A, pub B);
|
|
|
|
pub type RegionOutlivesPredicate = OutlivesPredicate<Region, Region>;
|
|
pub type TypeOutlivesPredicate = OutlivesPredicate<Ty, Region>;
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct ProjectionPredicate {
|
|
pub projection_term: AliasTerm,
|
|
pub term: TermKind,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum ImplPolarity {
|
|
Positive,
|
|
Negative,
|
|
Reservation,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum PredicatePolarity {
|
|
Positive,
|
|
Negative,
|
|
}
|
|
|
|
macro_rules! index_impl {
|
|
($name:ident) => {
|
|
impl crate::IndexedVal for $name {
|
|
fn to_val(index: usize) -> Self {
|
|
$name(index)
|
|
}
|
|
fn to_index(&self) -> usize {
|
|
self.0
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
index_impl!(TyConstId);
|
|
index_impl!(MirConstId);
|
|
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, Serialize)]
|
|
pub struct VariantIdx(usize);
|
|
|
|
index_impl!(VariantIdx);
|
|
|
|
crate_def! {
|
|
/// Hold information about an Opaque definition, particularly useful in `RPITIT`.
|
|
#[derive(Serialize)]
|
|
pub OpaqueDef;
|
|
}
|
|
|
|
crate_def! {
|
|
#[derive(Serialize)]
|
|
pub AssocDef;
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub struct AssocItem {
|
|
pub def_id: AssocDef,
|
|
pub kind: AssocKind,
|
|
pub container: AssocItemContainer,
|
|
|
|
/// If this is an item in an impl of a trait then this is the `DefId` of
|
|
/// the associated item on the trait that this implements.
|
|
pub trait_item_def_id: Option<AssocDef>,
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Debug, Eq, Serialize)]
|
|
pub enum AssocTypeData {
|
|
Normal(Symbol),
|
|
/// The associated type comes from an RPITIT. It has no name, and the
|
|
/// `ImplTraitInTraitData` provides additional information about its
|
|
/// source.
|
|
Rpitit(ImplTraitInTraitData),
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum AssocKind {
|
|
Const { name: Symbol },
|
|
Fn { name: Symbol, has_self: bool },
|
|
Type { data: AssocTypeData },
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
|
pub enum AssocItemContainer {
|
|
Trait,
|
|
Impl,
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
|
|
pub enum ImplTraitInTraitData {
|
|
Trait { fn_def_id: FnDef, opaque_def_id: OpaqueDef },
|
|
Impl { fn_def_id: FnDef },
|
|
}
|
|
|
|
impl AssocItem {
|
|
pub fn is_impl_trait_in_trait(&self) -> bool {
|
|
matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
|
|
}
|
|
}
|