use crate::crate_def::CrateDef;
use crate::mir::Body;
use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, FnSig, GenericArgs, IndexedVal, Ty};
use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol};
use std::fmt::{Debug, Formatter};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum MonoItem {
Fn(Instance),
Static(StaticDef),
GlobalAsm(Opaque),
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Instance {
pub kind: InstanceKind,
pub def: InstanceDef,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum InstanceKind {
Item,
Intrinsic,
Virtual { idx: usize },
Shim,
}
impl Instance {
pub fn body(&self) -> Option<Body> {
with(|context| context.instance_body(self.def))
}
pub fn is_foreign_item(&self) -> bool {
let item = CrateItem::try_from(*self);
item.as_ref().is_ok_and(CrateItem::is_foreign_item)
}
pub fn ty(&self) -> Ty {
with(|context| context.instance_ty(self.def))
}
pub fn mangled_name(&self) -> Symbol {
with(|context| context.instance_mangled_name(self.def))
}
pub fn name(&self) -> Symbol {
with(|context| context.instance_name(self.def, false))
}
pub fn trimmed_name(&self) -> Symbol {
with(|context| context.instance_name(self.def, true))
}
pub fn resolve(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
with(|context| {
context.resolve_instance(def, args).ok_or_else(|| {
crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
})
})
}
pub fn resolve_drop_in_place(ty: Ty) -> Instance {
with(|cx| cx.resolve_drop_in_place(ty))
}
pub fn resolve_for_fn_ptr(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
with(|context| {
context.resolve_for_fn_ptr(def, args).ok_or_else(|| {
crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
})
})
}
pub fn resolve_closure(
def: ClosureDef,
args: &GenericArgs,
kind: ClosureKind,
) -> Result<Instance, crate::Error> {
with(|context| {
context.resolve_closure(def, args, kind).ok_or_else(|| {
crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
})
})
}
pub fn fn_sig(&self) -> FnSig {
self.ty().kind().fn_sig().unwrap().skip_binder()
}
pub fn is_empty_shim(&self) -> bool {
self.kind == InstanceKind::Shim && with(|cx| cx.is_empty_drop_shim(self.def))
}
}
impl Debug for Instance {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Instance")
.field("kind", &self.kind)
.field("def", &self.mangled_name())
.finish()
}
}
impl TryFrom<CrateItem> for Instance {
type Error = crate::Error;
fn try_from(item: CrateItem) -> Result<Self, Self::Error> {
with(|context| {
if !context.requires_monomorphization(item.0) {
Ok(context.mono_instance(item))
} else {
Err(Error::new("Item requires monomorphization".to_string()))
}
})
}
}
impl TryFrom<Instance> for CrateItem {
type Error = crate::Error;
fn try_from(value: Instance) -> Result<Self, Self::Error> {
with(|context| {
if value.kind == InstanceKind::Item && context.has_body(value.def.def_id()) {
Ok(CrateItem(context.instance_def_id(value.def)))
} else {
Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind)))
}
})
}
}
impl From<Instance> for MonoItem {
fn from(value: Instance) -> Self {
MonoItem::Fn(value)
}
}
impl From<StaticDef> for MonoItem {
fn from(value: StaticDef) -> Self {
MonoItem::Static(value)
}
}
impl From<StaticDef> for CrateItem {
fn from(value: StaticDef) -> Self {
CrateItem(value.0)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InstanceDef(usize);
impl CrateDef for InstanceDef {
fn def_id(&self) -> DefId {
with(|context| context.instance_def_id(*self))
}
}
crate_def! {
pub StaticDef;
}
impl TryFrom<CrateItem> for StaticDef {
type Error = crate::Error;
fn try_from(value: CrateItem) -> Result<Self, Self::Error> {
if matches!(value.kind(), ItemKind::Static | ItemKind::Const) {
Ok(StaticDef(value.0))
} else {
Err(Error::new(format!("Expected a static item, but found: {value:?}")))
}
}
}
impl StaticDef {
pub fn ty(&self) -> Ty {
with(|cx| cx.def_ty(self.0))
}
pub fn eval_initializer(&self) -> Result<Allocation, Error> {
with(|cx| cx.eval_static_initializer(*self))
}
}
impl IndexedVal for InstanceDef {
fn to_val(index: usize) -> Self {
InstanceDef(index)
}
fn to_index(&self) -> usize {
self.0
}
}