forked from M-Labs/nac3
core/typedef: Add GenericObjectType
This commit is contained in:
parent
10a88e1799
commit
da4dec08a5
@ -4,6 +4,7 @@ use inkwell::{
|
|||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use nac3core::typecheck::typedef::{GenericObjectType, GenericTypeAdapter};
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::{
|
codegen::{
|
||||||
classes::{NDArrayType, ProxyType},
|
classes::{NDArrayType, ProxyType},
|
||||||
@ -17,7 +18,7 @@ use nac3core::{
|
|||||||
},
|
},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::PrimitiveStore,
|
type_inferencer::PrimitiveStore,
|
||||||
typedef::{into_var_map, iter_type_vars, Type, TypeEnum, TypeVar, Unifier, VarMap},
|
typedef::{Type, TypeEnum, TypeVar, Unifier, VarMap},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use nac3parser::ast::{self, StrRef};
|
use nac3parser::ast::{self, StrRef};
|
||||||
@ -767,13 +768,12 @@ impl InnerResolver {
|
|||||||
// if is `none`
|
// if is `none`
|
||||||
let zelf_id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
|
let zelf_id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
|
||||||
if zelf_id == self.primitive_ids.none {
|
if zelf_id == self.primitive_ids.none {
|
||||||
let ty_enum = unifier.get_ty_immutable(primitives.option);
|
let extracted_ty = GenericTypeAdapter::create(extracted_ty, unifier);
|
||||||
let TypeEnum::TObj { params, .. } = ty_enum.as_ref() else {
|
let var_map = extracted_ty.iter_var_map(unifier, |tvar_iter, unifier| {
|
||||||
unreachable!("must be tobj")
|
tvar_iter
|
||||||
};
|
.map(|tvar| {
|
||||||
|
let TypeEnum::TVar { id, range, name, loc, .. } =
|
||||||
let var_map = into_var_map(iter_type_vars(params).map(|tvar| {
|
&*unifier.get_ty(tvar.ty)
|
||||||
let TypeEnum::TVar { id, range, name, loc, .. } = &*unifier.get_ty(tvar.ty)
|
|
||||||
else {
|
else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
@ -781,7 +781,10 @@ impl InnerResolver {
|
|||||||
assert_eq!(*id, tvar.id);
|
assert_eq!(*id, tvar.id);
|
||||||
let ty = unifier.get_fresh_var_with_range(range, *name, *loc).ty;
|
let ty = unifier.get_fresh_var_with_range(range, *name, *loc).ty;
|
||||||
TypeVar { id: *id, ty }
|
TypeVar { id: *id, ty }
|
||||||
}));
|
})
|
||||||
|
.map(TypeVar::into)
|
||||||
|
.collect::<VarMap>()
|
||||||
|
});
|
||||||
return Ok(Ok(unifier.subst(primitives.option, &var_map).unwrap()));
|
return Ok(Ok(unifier.subst(primitives.option, &var_map).unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,10 +800,14 @@ impl InnerResolver {
|
|||||||
let res = unifier.subst(extracted_ty, &new_var_map).unwrap_or(extracted_ty);
|
let res = unifier.subst(extracted_ty, &new_var_map).unwrap_or(extracted_ty);
|
||||||
Ok(Ok(res))
|
Ok(Ok(res))
|
||||||
}
|
}
|
||||||
(TypeEnum::TObj { params, fields, .. }, false) => {
|
(TypeEnum::TObj { fields, .. }, false) => {
|
||||||
self.pyid_to_type.write().insert(py_obj_id, extracted_ty);
|
self.pyid_to_type.write().insert(py_obj_id, extracted_ty);
|
||||||
let var_map = into_var_map(iter_type_vars(params).map(|tvar| {
|
let extracted_ty = GenericTypeAdapter::create(extracted_ty, unifier);
|
||||||
let TypeEnum::TVar { id, range, name, loc, .. } = &*unifier.get_ty(tvar.ty)
|
let var_map = extracted_ty.iter_var_map(unifier, |tvar_iter, unifier| {
|
||||||
|
tvar_iter
|
||||||
|
.map(|tvar| {
|
||||||
|
let TypeEnum::TVar { id, range, name, loc, .. } =
|
||||||
|
&*unifier.get_ty(tvar.ty)
|
||||||
else {
|
else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
@ -808,8 +815,11 @@ impl InnerResolver {
|
|||||||
assert_eq!(*id, tvar.id);
|
assert_eq!(*id, tvar.id);
|
||||||
let ty = unifier.get_fresh_var_with_range(range, *name, *loc).ty;
|
let ty = unifier.get_fresh_var_with_range(range, *name, *loc).ty;
|
||||||
TypeVar { id: *id, ty }
|
TypeVar { id: *id, ty }
|
||||||
}));
|
})
|
||||||
let mut instantiate_obj = || {
|
.map(TypeVar::into)
|
||||||
|
.collect::<VarMap>()
|
||||||
|
});
|
||||||
|
let instantiate_obj = || {
|
||||||
// loop through non-function fields of the class to get the instantiated value
|
// loop through non-function fields of the class to get the instantiated value
|
||||||
for field in fields {
|
for field in fields {
|
||||||
let name: String = (*field.0).into();
|
let name: String = (*field.0).into();
|
||||||
@ -844,6 +854,7 @@ impl InnerResolver {
|
|||||||
return Ok(Err("object is not of concrete type".into()));
|
return Ok(Err("object is not of concrete type".into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let extracted_ty = extracted_ty.into();
|
||||||
let extracted_ty =
|
let extracted_ty =
|
||||||
unifier.subst(extracted_ty, &var_map).unwrap_or(extracted_ty);
|
unifier.subst(extracted_ty, &var_map).unwrap_or(extracted_ty);
|
||||||
Ok(Ok(extracted_ty))
|
Ok(Ok(extracted_ty))
|
||||||
|
@ -11,6 +11,7 @@ use inkwell::{
|
|||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::typecheck::typedef::{GenericObjectType, GenericTypeAdapter};
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{
|
codegen::{
|
||||||
builtin_fns,
|
builtin_fns,
|
||||||
@ -25,7 +26,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
symbol_resolver::SymbolValue,
|
symbol_resolver::SymbolValue,
|
||||||
toplevel::{helper::PrimDef, numpy::make_ndarray_ty},
|
toplevel::{helper::PrimDef, numpy::make_ndarray_ty},
|
||||||
typecheck::typedef::{into_var_map, iter_type_vars, TypeVar, VarMap},
|
typecheck::typedef::{into_var_map, TypeVar, VarMap},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -345,23 +346,23 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
|
|
||||||
// Option-related
|
// Option-related
|
||||||
let (is_some_ty, unwrap_ty, option_tvar) =
|
let (is_some_ty, unwrap_ty, option_tvar) =
|
||||||
if let TypeEnum::TObj { fields, params, .. } = unifier.get_ty(option).as_ref() {
|
if let TypeEnum::TObj { fields, .. } = &*unifier.get_ty(option) {
|
||||||
|
let option = GenericTypeAdapter::create(option, unifier);
|
||||||
(
|
(
|
||||||
*fields.get(&PrimDef::OptionIsSome.simple_name().into()).unwrap(),
|
*fields.get(&PrimDef::OptionIsSome.simple_name().into()).unwrap(),
|
||||||
*fields.get(&PrimDef::OptionUnwrap.simple_name().into()).unwrap(),
|
*fields.get(&PrimDef::OptionUnwrap.simple_name().into()).unwrap(),
|
||||||
iter_type_vars(params).next().unwrap(),
|
option.get_var_at(unifier, 0).unwrap(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
let TypeEnum::TObj { fields: ndarray_fields, params: ndarray_params, .. } =
|
let TypeEnum::TObj { fields: ndarray_fields, .. } = &*unifier.get_ty(ndarray) else {
|
||||||
&*unifier.get_ty(ndarray)
|
|
||||||
else {
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let ndarray_dtype_tvar = iter_type_vars(ndarray_params).next().unwrap();
|
let ndarray = GenericTypeAdapter::create(ndarray, unifier);
|
||||||
let ndarray_ndims_tvar = iter_type_vars(ndarray_params).nth(1).unwrap();
|
let ndarray_dtype_tvar = ndarray.get_var_at(unifier, 0).unwrap();
|
||||||
|
let ndarray_ndims_tvar = ndarray.get_var_at(unifier, 1).unwrap();
|
||||||
let ndarray_copy_ty =
|
let ndarray_copy_ty =
|
||||||
*ndarray_fields.get(&PrimDef::NDArrayCopy.simple_name().into()).unwrap();
|
*ndarray_fields.get(&PrimDef::NDArrayCopy.simple_name().into()).unwrap();
|
||||||
let ndarray_fill_ty =
|
let ndarray_fill_ty =
|
||||||
|
@ -89,6 +89,24 @@ pub struct TypeVar {
|
|||||||
pub ty: Type,
|
pub ty: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<(TypeVarId, Type)> for TypeVar {
|
||||||
|
fn from((id, ty): (TypeVarId, Type)) -> Self {
|
||||||
|
TypeVar { id, ty }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(&TypeVarId, &Type)> for TypeVar {
|
||||||
|
fn from((id, ty): (&TypeVarId, &Type)) -> Self {
|
||||||
|
TypeVar { id: *id, ty: *ty }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TypeVar> for (TypeVarId, Type) {
|
||||||
|
fn from(value: TypeVar) -> Self {
|
||||||
|
(value.id, value.ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The mapping between [`TypeVarId`] and [unifier type][`Type`].
|
/// The mapping between [`TypeVarId`] and [unifier type][`Type`].
|
||||||
pub type VarMap = IndexMapping<TypeVarId>;
|
pub type VarMap = IndexMapping<TypeVarId>;
|
||||||
|
|
||||||
@ -102,9 +120,83 @@ where
|
|||||||
vars.into_iter().map(|var| (var.id, var.ty)).collect()
|
vars.into_iter().map(|var| (var.id, var.ty)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an iterator of [`TypeVar`]s from a [`VarMap`]
|
/// A trait representing a possibly generic object type.
|
||||||
pub fn iter_type_vars(var_map: &VarMap) -> impl Iterator<Item = TypeVar> + '_ {
|
pub trait GenericObjectType
|
||||||
var_map.iter().map(|(&id, &ty)| TypeVar { id, ty })
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
fn try_create(ty: Type, unifier: &mut Unifier) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Creates an instance from a [`Type`].
|
||||||
|
#[must_use]
|
||||||
|
fn create(ty: Type, unifier: &mut Unifier) -> Self {
|
||||||
|
Self::try_create(ty, unifier).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`Type`] underlying this instance.
|
||||||
|
#[must_use]
|
||||||
|
fn get_type(&self) -> Type;
|
||||||
|
|
||||||
|
/// See [`Type::obj_id`].
|
||||||
|
#[must_use]
|
||||||
|
fn obj_id(&self, unifier: &Unifier) -> DefinitionId {
|
||||||
|
self.get_type().obj_id(unifier).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a copy of the [`VarMap`] of this object type.
|
||||||
|
#[must_use]
|
||||||
|
fn var_map(&self, unifier: &mut Unifier) -> VarMap {
|
||||||
|
let TypeEnum::TObj { params, .. } = &*unifier.get_ty(self.get_type()) else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
params.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an iterator over the [`VarMap`] of this object type, applying `iter_fn` on the
|
||||||
|
/// created [`Iterator`].
|
||||||
|
#[must_use]
|
||||||
|
fn iter_var_map<R, IterFn: FnOnce(&mut dyn Iterator<Item = TypeVar>, &mut Unifier) -> R>(
|
||||||
|
&self,
|
||||||
|
unifier: &mut Unifier,
|
||||||
|
iter_fn: IterFn,
|
||||||
|
) -> R {
|
||||||
|
let TypeEnum::TObj { params, .. } = &*unifier.get_ty(self.get_type()) else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = iter_fn(&mut params.iter().map(TypeVar::from), unifier);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`TypeVar`] instance at the given index.
|
||||||
|
#[must_use]
|
||||||
|
fn get_var_at(&self, unifier: &mut Unifier, i: usize) -> Option<TypeVar> {
|
||||||
|
self.iter_var_map(unifier, |iter, _| iter.nth(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: GenericObjectType> From<T> for Type {
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
value.get_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An adapter that converts [`Type`] into
|
||||||
|
pub struct GenericTypeAdapter(Type);
|
||||||
|
|
||||||
|
impl GenericObjectType for GenericTypeAdapter {
|
||||||
|
fn try_create(ty: Type, unifier: &mut Unifier) -> Option<Self> {
|
||||||
|
if let TypeEnum::TObj { .. } = &*unifier.get_ty_immutable(ty) {
|
||||||
|
Some(GenericTypeAdapter(ty))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_type(&self) -> Type {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
Loading…
Reference in New Issue
Block a user