1
Fork 0

Add more APIs and fix Instance::body

Add more APIs to retrieve information about types, and add more instance
resolution options.

Make `Instance::body()` return an Option<Body>, since not every instance
might have an available body. For example, foreign instances, virtual
instances, dependencies.
This commit is contained in:
Celina G. Val 2023-11-16 12:01:10 -08:00
parent 3f87dac9a2
commit 6515ac9d3f
9 changed files with 422 additions and 47 deletions

View file

@ -36,6 +36,7 @@ pub mod mir;
pub mod ty;
pub mod visitor;
use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind};
pub use error::*;
use mir::mono::Instance;
use ty::{FnDef, GenericArgs};
@ -99,7 +100,13 @@ pub struct Crate {
pub is_local: bool,
}
pub type DefKind = Opaque;
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum ItemKind {
Fn,
Static,
Const,
}
pub type Filename = Opaque;
/// Holds information about an item in the crate.
@ -119,13 +126,17 @@ impl CrateItem {
with(|cx| cx.name_of_def_id(self.0))
}
pub fn kind(&self) -> DefKind {
with(|cx| cx.def_kind(self.0))
pub fn kind(&self) -> ItemKind {
with(|cx| cx.item_kind(*self))
}
pub fn requires_monomorphization(&self) -> bool {
with(|cx| cx.requires_monomorphization(self.0))
}
pub fn ty(&self) -> Ty {
with(|cx| cx.def_ty(self.0))
}
}
/// Return the function where execution starts if the current
@ -204,7 +215,13 @@ pub trait Context {
fn get_lines(&self, span: &Span) -> LineInfo;
/// Returns the `kind` of given `DefId`
fn def_kind(&self, def_id: DefId) -> DefKind;
fn item_kind(&self, item: CrateItem) -> ItemKind;
/// Returns the kind of a given algebraic data type
fn adt_kind(&self, def: AdtDef) -> AdtKind;
/// Returns the type of given crate item.
fn def_ty(&self, item: DefId) -> Ty;
/// `Span` of an item
fn span_of_an_item(&self, def_id: DefId) -> Span;
@ -214,7 +231,7 @@ pub trait Context {
/// Get the body of an Instance.
/// FIXME: Monomorphize the body.
fn instance_body(&self, instance: InstanceDef) -> Body;
fn instance_body(&self, instance: InstanceDef) -> Option<Body>;
/// Get the instance type with generic substitutions applied and lifetimes erased.
fn instance_ty(&self, instance: InstanceDef) -> Ty;
@ -234,6 +251,20 @@ pub trait Context {
/// Resolve an instance from the given function definition and generic arguments.
fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
/// Resolve an instance for drop_in_place for the given type.
fn resolve_drop_in_place(&self, ty: Ty) -> Option<Instance>;
/// Resolve instance for a function pointer.
fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
/// Resolve instance for a closure with the requested type.
fn resolve_closure(
&self,
def: ClosureDef,
args: &GenericArgs,
kind: ClosureKind,
) -> Option<Instance>;
}
// A thread local variable that stores a pointer to the tables mapping between TyCtxt

View file

@ -1,16 +1,16 @@
use crate::mir::Body;
use crate::ty::{FnDef, GenericArgs, IndexedVal, Ty};
use crate::{with, CrateItem, DefId, Error, Opaque};
use crate::ty::{ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque};
use std::fmt::Debug;
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum MonoItem {
Fn(Instance),
Static(StaticDef),
GlobalAsm(Opaque),
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Instance {
/// The type of instance.
pub kind: InstanceKind,
@ -19,7 +19,7 @@ pub struct Instance {
pub def: InstanceDef,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum InstanceKind {
/// A user defined item.
Item,
@ -33,7 +33,7 @@ pub enum InstanceKind {
impl Instance {
/// Get the body of an Instance. The body will be eagerly monomorphized.
pub fn body(&self) -> Body {
pub fn body(&self) -> Option<Body> {
with(|context| context.instance_body(self.def))
}
@ -54,6 +54,34 @@ impl Instance {
})
})
}
/// Resolve the drop in place for a given type.
/// Return `None` if the drop is a no-op.
pub fn resolve_drop_in_place(ty: Ty) -> Option<Instance> {
with(|cx| cx.resolve_drop_in_place(ty))
}
/// Resolve the drop in place for a given type.
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:?}`"))
})
})
}
/// Resolve a closure (do we need kind? -- most cases use FnOnce)
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:?}`"))
})
})
}
}
/// Try to convert a crate item into an instance.
@ -86,12 +114,36 @@ impl TryFrom<Instance> for CrateItem {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
impl From<Instance> for MonoItem {
fn from(value: Instance) -> Self {
MonoItem::Fn(value)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InstanceDef(usize);
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct StaticDef(pub DefId);
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))
}
}
impl IndexedVal for InstanceDef {
fn to_val(index: usize) -> Self {
InstanceDef(index)

View file

@ -4,7 +4,7 @@ use super::{
with, AllocId, DefId, Symbol,
};
use crate::{Filename, Opaque};
use std::fmt::{self, Debug, Formatter};
use std::fmt::{self, Debug, Display, Formatter};
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Ty(pub usize);
@ -135,6 +135,46 @@ pub enum TyKind {
Bound(usize, BoundTy),
}
impl TyKind {
pub fn rigid(&self) -> Option<&RigidTy> {
if let TyKind::RigidTy(inner) = self { Some(inner) } else { None }
}
pub fn is_unit(&self) -> bool {
matches!(self, TyKind::RigidTy(RigidTy::Tuple(data)) if data.len() == 0)
}
pub fn is_trait(&self) -> bool {
matches!(self, TyKind::RigidTy(RigidTy::Dynamic(_, _, DynKind::Dyn)))
}
pub fn is_enum(&self) -> bool {
matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Enum)
}
pub fn is_struct(&self) -> bool {
matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Struct)
}
pub fn is_union(&self) -> bool {
matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Union)
}
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
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RigidTy {
Bool,
@ -218,6 +258,43 @@ pub struct BrNamedDef(pub DefId);
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct AdtDef(pub DefId);
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum AdtKind {
Enum,
Union,
Struct,
}
impl AdtDef {
pub fn kind(&self) -> AdtKind {
with(|cx| cx.adt_kind(*self))
}
}
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)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct AliasDef(pub DefId);
@ -355,6 +432,30 @@ pub struct Binder<T> {
pub bound_vars: Vec<BoundVariableKind>,
}
impl<T> Binder<T> {
pub fn skip_binder(self) -> T {
self.value
}
pub fn map_bound_ref<F, U>(&self, f: F) -> Binder<U>
where
F: FnOnce(&T) -> U,
{
let Binder { value, bound_vars } = self;
let new_value = f(value);
Binder { value: new_value, bound_vars: bound_vars.clone() }
}
pub fn map_bound<F, U>(self, f: F) -> Binder<U>
where
F: FnOnce(T) -> U,
{
let Binder { value, bound_vars } = self;
let new_value = f(value);
Binder { value: new_value, bound_vars }
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EarlyBinder<T> {
pub value: T,
@ -393,12 +494,27 @@ pub enum ExistentialPredicate {
AutoTrait(TraitDef),
}
/// An existential reference to a trait where `Self` is not included.
///
/// The `generic_args` will include any other known argument.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExistentialTraitRef {
pub def_id: TraitDef,
pub generic_args: GenericArgs,
}
impl Binder<ExistentialTraitRef> {
pub fn with_self_ty(&self, self_ty: Ty) -> Binder<TraitRef> {
self.map_bound_ref(|trait_ref| trait_ref.with_self_ty(self_ty))
}
}
impl ExistentialTraitRef {
pub fn with_self_ty(&self, self_ty: Ty) -> TraitRef {
TraitRef::new(self.def_id, self_ty, &self.generic_args)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExistentialProjection {
pub def_id: TraitDef,
@ -504,10 +620,39 @@ impl TraitDecl {
pub type ImplTrait = EarlyBinder<TraitRef>;
/// A complete reference to a trait, i.e., one where `Self` is known.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TraitRef {
pub def_id: TraitDef,
pub args: GenericArgs,
/// The generic arguments for this definition.
/// The first element must always be type, and it represents `Self`.
args: GenericArgs,
}
impl TraitRef {
pub fn new(def_id: TraitDef, self_ty: Ty, gen_args: &GenericArgs) -> TraitRef {
let mut args = vec![GenericArgKind::Type(self_ty)];
args.extend_from_slice(&gen_args.0);
TraitRef { def_id, args: GenericArgs(args) }
}
pub fn try_new(def_id: TraitDef, args: GenericArgs) -> Result<TraitRef, ()> {
match &args.0[..] {
[GenericArgKind::Type(_), ..] => Ok(TraitRef { def_id, args }),
_ => Err(()),
}
}
pub fn args(&self) -> &GenericArgs {
&self.args
}
pub fn self_ty(&self) -> Ty {
let GenericArgKind::Type(self_ty) = self.args.0[0] else {
panic!("Self must be a type, but found: {:?}", self.args.0[0])
};
self_ty
}
}
#[derive(Clone, Debug, Eq, PartialEq)]