use std::fmt::{self, Debug, Display, Formatter};
use std::ops::Range;
use serde::Serialize;
use super::mir::{Body, Mutability, Safety};
use super::{with, DefId, Error, Symbol};
use crate::abi::{FnAbi, Layout};
use crate::crate_def::{CrateDef, CrateDefType};
use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
use crate::mir::mono::StaticDef;
use crate::target::MachineInfo;
use crate::{Filename, 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()
}
}
impl Ty {
pub fn from_rigid_kind(kind: RigidTy) -> Ty {
with(|cx| cx.new_rigid_ty(kind))
}
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)?)))
}
pub fn new_array_with_const_len(elem_ty: Ty, len: TyConst) -> Ty {
Ty::from_rigid_kind(RigidTy::Array(elem_ty, len))
}
pub fn new_ptr(pointee_ty: Ty, mutability: Mutability) -> Ty {
Ty::from_rigid_kind(RigidTy::RawPtr(pointee_ty, mutability))
}
pub fn new_ref(reg: Region, pointee_ty: Ty, mutability: Mutability) -> Ty {
Ty::from_rigid_kind(RigidTy::Ref(reg, pointee_ty, mutability))
}
pub fn new_tuple(tys: &[Ty]) -> Ty {
Ty::from_rigid_kind(RigidTy::Tuple(Vec::from(tys)))
}
pub fn new_closure(def: ClosureDef, args: GenericArgs) -> Ty {
Ty::from_rigid_kind(RigidTy::Closure(def, args))
}
pub fn new_coroutine(def: CoroutineDef, args: GenericArgs, mov: Movability) -> Ty {
Ty::from_rigid_kind(RigidTy::Coroutine(def, args, mov))
}
pub fn new_box(inner_ty: Ty) -> Ty {
with(|cx| cx.new_box_ty(inner_ty))
}
pub fn usize_ty() -> Ty {
Ty::from_rigid_kind(RigidTy::Uint(UintTy::Usize))
}
pub fn bool_ty() -> Ty {
Ty::from_rigid_kind(RigidTy::Bool)
}
pub fn signed_ty(inner: IntTy) -> Ty {
Ty::from_rigid_kind(RigidTy::Int(inner))
}
pub fn unsigned_ty(inner: UintTy) -> Ty {
Ty::from_rigid_kind(RigidTy::Uint(inner))
}
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))
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum Pattern {
Range { start: Option<TyConst>, end: Option<TyConst>, include_end: bool },
}
#[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 }
}
pub fn kind(&self) -> &TyConstKind {
&self.kind
}
pub fn try_from_target_usize(val: u64) -> Result<Self, Error> {
with(|cx| cx.try_new_ty_const_uint(val.into(), UintTy::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),
Value(Ty, Allocation),
ZSTValue(Ty),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub struct TyConstId(usize);
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct MirConst {
pub(crate) kind: ConstantKind,
pub(crate) ty: Ty,
pub id: MirConstId,
}
impl MirConst {
pub fn new(kind: ConstantKind, ty: Ty, id: MirConstId) -> MirConst {
MirConst { kind, ty, id }
}
pub fn kind(&self) -> &ConstantKind {
&self.kind
}
pub fn ty(&self) -> Ty {
self.ty
}
pub fn eval_target_usize(&self) -> Result<u64, Error> {
with(|cx| cx.eval_target_usize(self))
}
pub fn try_new_zero_sized(ty: Ty) -> Result<MirConst, Error> {
with(|cx| cx.try_new_const_zst(ty))
}
pub fn from_str(value: &str) -> MirConst {
with(|cx| cx.new_const_str(value))
}
pub fn from_bool(value: bool) -> MirConst {
with(|cx| cx.new_const_bool(value))
}
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 {
pub fn get_filename(&self) -> Filename {
with(|c| c.get_filename(self))
}
pub fn get_lines(&self) -> LineInfo {
with(|c| c.get_lines(self))
}
}
#[derive(Clone, Copy, Debug, Serialize)]
pub struct LineInfo {
pub start_line: usize,
pub start_col: usize,
pub end_line: usize,
pub end_col: usize,
}
#[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(..)))
}
#[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
}
}
pub fn builtin_index(&self) -> Option<Ty> {
match self.rigid()? {
RigidTy::Array(ty, _) | RigidTy::Slice(ty) => Some(*ty),
_ => None,
}
}
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,
}
}
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,
}
}
pub fn discriminant_ty(&self) -> Option<Ty> {
self.rigid().map(|ty| with(|cx| cx.rigid_ty_discriminant_ty(ty)))
}
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),
Coroutine(CoroutineDef, GenericArgs, Movability),
Dynamic(Vec<Binder<ExistentialPredicate>>, Region, DynKind),
Never,
Tuple(Vec<Ty>),
CoroutineWitness(CoroutineWitnessDef, GenericArgs),
}
impl RigidTy {
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 => crate::target::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 => crate::target::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! {
#[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! {
#[derive(Serialize)]
pub FnDef;
}
impl FnDef {
pub fn body(&self) -> Option<Body> {
with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0)))
}
pub fn has_body(&self) -> bool {
with(|ctx| ctx.has_body(self.0))
}
pub fn as_intrinsic(&self) -> Option<IntrinsicDef> {
with(|cx| cx.intrinsic(self.def_id()))
}
#[inline]
pub fn is_intrinsic(&self) -> bool {
self.as_intrinsic().is_some()
}
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 {
pub fn fn_name(&self) -> Symbol {
with(|cx| cx.intrinsic_name(*self))
}
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;
}
crate_def! {
#[derive(Serialize)]
pub CoroutineDef;
}
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))
}
pub fn ty(&self) -> Ty {
with(|cx| cx.def_ty(self.0))
}
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))
}
pub fn num_variants(&self) -> usize {
with(|cx| cx.adt_variants_len(*self))
}
pub fn variants(&self) -> Vec<VariantDef> {
self.variants_iter().collect()
}
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 })
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct VariantDef {
pub idx: VariantIdx,
pub adt_def: AdtDef,
}
impl VariantDef {
pub fn name(&self) -> Symbol {
with(|cx| cx.variant_name(*self))
}
pub fn fields(&self) -> Vec<FieldDef> {
with(|cx| cx.variant_fields(*self))
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct FieldDef {
pub def: DefId,
pub name: Symbol,
}
impl FieldDef {
pub fn ty_with_args(&self, args: &GenericArgs) -> Ty {
with(|cx| cx.def_ty_with_args(self.def, args))
}
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! {
#[derive(Serialize)]
pub 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! {
#[derive(Serialize)]
pub ImplDef;
}
impl ImplDef {
pub fn trait_impl(&self) -> ImplTrait {
with(|cx| cx.trait_impl(self))
}
}
crate_def! {
#[derive(Serialize)]
pub RegionDef;
}
crate_def! {
#[derive(Serialize)]
pub CoroutineWitnessDef;
}
#[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 {
#[track_caller]
pub fn expect_ty(&self) -> &Ty {
match self {
GenericArgKind::Type(ty) => ty,
_ => panic!("{self:?}"),
}
}
#[track_caller]
pub fn expect_const(&self) -> &TyConst {
match self {
GenericArgKind::Const(c) => c,
_ => panic!("{self:?}"),
}
}
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,
Weak,
}
#[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 {
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,
EfiApi,
AvrInterrupt,
AvrNonBlockingInterrupt,
CCmseNonSecureCall,
System { unwind: bool },
RustIntrinsic,
RustCall,
Unadjusted,
RustCold,
RiscvInterruptM,
RiscvInterruptS,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct Binder<T> {
pub value: T,
pub bound_vars: Vec<BoundVariableKind>,
}
impl<T> Binder<T> {
pub fn bind_with_vars(value: T, bound_vars: Vec<BoundVariableKind>) -> Self {
Binder { value, bound_vars }
}
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,
DynStar,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum ExistentialPredicate {
Trait(ExistentialTraitRef),
Projection(ExistentialProjection),
AutoTrait(TraitDef),
}
#[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>>;
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>;
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct ProvenanceMap {
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 {
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))
}
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)
}
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)
}
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)
}
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}`")),
}
}
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),
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>;
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct TraitRef {
pub def_id: TraitDef,
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>,
pub host_effect_index: Option<usize>,
}
#[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),
ObjectSafe(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(GenericArgKind),
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,
}
pub trait IndexedVal {
fn to_val(index: usize) -> Self;
fn to_index(&self) -> usize;
}
macro_rules! index_impl {
($name:ident) => {
impl 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);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct VariantIdx(usize);
index_impl!(VariantIdx);