forked from M-Labs/nac3
Compare commits
6 Commits
master
...
temp/build
Author | SHA1 | Date |
---|---|---|
David Mak | 3a64b0cf07 | |
David Mak | 2cdb057d20 | |
David Mak | 8f95c707d7 | |
David Mak | 9b5fb69875 | |
David Mak | 6c1d8ac001 | |
David Mak | 6d6f8be07f |
|
@ -117,9 +117,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.0"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8"
|
||||
checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -158,7 +158,7 @@ dependencies = [
|
|||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.70",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -421,7 +421,7 @@ checksum = "4fa4d8d74483041a882adaa9a29f633253a66dde85055f0495c121620ac484b2"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.70",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -749,7 +749,7 @@ dependencies = [
|
|||
"phf_shared 0.11.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.70",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -850,7 +850,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"pyo3-macros-backend",
|
||||
"quote",
|
||||
"syn 2.0.70",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -863,7 +863,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"pyo3-build-config",
|
||||
"quote",
|
||||
"syn 2.0.70",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -927,9 +927,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
|
||||
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
@ -1044,7 +1044,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.70",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1134,7 +1134,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.70",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1150,9 +1150,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.70"
|
||||
version = "2.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
|
||||
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1203,22 +1203,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.61"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.61"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.70",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1486,5 +1486,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.70",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
|
|
@ -24,3 +24,4 @@ features = ["llvm14-0", "target-x86", "target-arm", "target-riscv", "no-libffi-l
|
|||
|
||||
[features]
|
||||
init-llvm-profile = []
|
||||
no-escape-analysis = ["nac3core/no-escape-analysis"]
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
from min_artiq import *
|
||||
from numpy import int32
|
||||
|
||||
|
||||
@nac3
|
||||
class EmptyList:
|
||||
core: KernelInvariant[Core]
|
||||
|
||||
def __init__(self):
|
||||
self.core = Core()
|
||||
|
||||
@rpc
|
||||
def get_empty(self) -> list[int32]:
|
||||
return []
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
a: list[int32] = self.get_empty()
|
||||
if a != []:
|
||||
raise ValueError
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
EmptyList().run()
|
|
@ -991,8 +991,15 @@ impl InnerResolver {
|
|||
}
|
||||
_ => unreachable!("must be list"),
|
||||
};
|
||||
let ty = ctx.get_llvm_type(generator, elem_ty);
|
||||
let size_t = generator.get_size_type(ctx.ctx);
|
||||
let ty = if len == 0
|
||||
&& matches!(&*ctx.unifier.get_ty_immutable(elem_ty), TypeEnum::TVar { .. })
|
||||
{
|
||||
// The default type for zero-length lists of unknown element type is size_t
|
||||
size_t.into()
|
||||
} else {
|
||||
ctx.get_llvm_type(generator, elem_ty)
|
||||
};
|
||||
let arr_ty = ctx
|
||||
.ctx
|
||||
.struct_type(&[ty.ptr_type(AddressSpace::default()).into(), size_t.into()], false);
|
||||
|
@ -1073,6 +1080,8 @@ impl InnerResolver {
|
|||
unpack_ndarray_var_tys(&mut ctx.unifier, ndarray_ty);
|
||||
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
// TODO: Special handling required for strings, since there are two representations:
|
||||
// struct %str and [n x i8].
|
||||
let ndarray_dtype_llvm_ty = ctx.get_llvm_type(generator, ndarray_dtype);
|
||||
let ndarray_llvm_ty = NDArrayType::new(generator, ctx.ctx, ndarray_dtype_llvm_ty);
|
||||
|
||||
|
@ -1140,30 +1149,43 @@ impl InnerResolver {
|
|||
})
|
||||
})
|
||||
.collect();
|
||||
let data = data?.unwrap().into_iter();
|
||||
let data = match ndarray_dtype_llvm_ty {
|
||||
BasicTypeEnum::ArrayType(ty) => {
|
||||
ty.const_array(&data.map(BasicValueEnum::into_array_value).collect_vec())
|
||||
}
|
||||
let data = data?.unwrap();
|
||||
|
||||
BasicTypeEnum::FloatType(ty) => {
|
||||
ty.const_array(&data.map(BasicValueEnum::into_float_value).collect_vec())
|
||||
}
|
||||
let make_llvm_array =
|
||||
|llvm_ty: BasicTypeEnum<'ctx>, elems: Vec<BasicValueEnum<'ctx>>| {
|
||||
debug_assert!(elems.iter().all(|elem| elem.get_type() == llvm_ty));
|
||||
|
||||
BasicTypeEnum::IntType(ty) => {
|
||||
ty.const_array(&data.map(BasicValueEnum::into_int_value).collect_vec())
|
||||
}
|
||||
match llvm_ty {
|
||||
BasicTypeEnum::ArrayType(ty) => ty.const_array(
|
||||
&elems.into_iter().map(BasicValueEnum::into_array_value).collect_vec(),
|
||||
),
|
||||
|
||||
BasicTypeEnum::PointerType(ty) => {
|
||||
ty.const_array(&data.map(BasicValueEnum::into_pointer_value).collect_vec())
|
||||
}
|
||||
BasicTypeEnum::FloatType(ty) => ty.const_array(
|
||||
&elems.into_iter().map(BasicValueEnum::into_float_value).collect_vec(),
|
||||
),
|
||||
|
||||
BasicTypeEnum::StructType(ty) => {
|
||||
ty.const_array(&data.map(BasicValueEnum::into_struct_value).collect_vec())
|
||||
}
|
||||
BasicTypeEnum::IntType(ty) => ty.const_array(
|
||||
&elems.into_iter().map(BasicValueEnum::into_int_value).collect_vec(),
|
||||
),
|
||||
|
||||
BasicTypeEnum::VectorType(_) => unreachable!(),
|
||||
};
|
||||
BasicTypeEnum::PointerType(ty) => ty.const_array(
|
||||
&elems
|
||||
.into_iter()
|
||||
.map(BasicValueEnum::into_pointer_value)
|
||||
.collect_vec(),
|
||||
),
|
||||
|
||||
BasicTypeEnum::StructType(ty) => ty.const_array(
|
||||
&elems.into_iter().map(BasicValueEnum::into_struct_value).collect_vec(),
|
||||
),
|
||||
|
||||
BasicTypeEnum::VectorType(_) => unreachable!(),
|
||||
}
|
||||
};
|
||||
|
||||
let ndarray_dtype_llvm_ty =
|
||||
if data.is_empty() { ndarray_dtype_llvm_ty } else { data[0].get_type() };
|
||||
let data = make_llvm_array(ndarray_dtype_llvm_ty, data);
|
||||
|
||||
// create a global for ndarray.data and initialize it using the elements
|
||||
let data_global = ctx.module.add_global(
|
||||
|
|
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
|||
authors = ["M-Labs"]
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
no-escape-analysis = []
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.13"
|
||||
crossbeam = "0.8"
|
||||
|
|
|
@ -951,9 +951,9 @@ pub fn destructure_range<'ctx>(
|
|||
/// Allocates a List structure with the given [type][ty] and [length]. The name of the resulting
|
||||
/// LLVM value is `{name}.addr`, or `list.addr` if [name] is not specified.
|
||||
///
|
||||
/// Setting `ty` to [`None`] implies that the list does not have a known element type, which is only
|
||||
/// valid for empty lists. It is undefined behavior to generate a sized list with an unknown element
|
||||
/// type.
|
||||
/// Setting `ty` to [`None`] implies that the list is empty **and** does not have a known element
|
||||
/// type, and will therefore set the `list.data` type as `size_t*`. It is undefined behavior to
|
||||
/// generate a sized list with an unknown element type.
|
||||
pub fn allocate_list<'ctx, G: CodeGenerator + ?Sized>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
|
|
|
@ -1637,7 +1637,7 @@ pub fn gen_stmt<G: CodeGenerator>(
|
|||
};
|
||||
ctx.make_assert_impl(
|
||||
generator,
|
||||
test.into_int_value(),
|
||||
generator.bool_to_i1(ctx, test.into_int_value()),
|
||||
"0:AssertionError",
|
||||
err_msg,
|
||||
[None, None, None],
|
||||
|
|
|
@ -564,7 +564,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||
match (&tld, prim.details()) {
|
||||
(
|
||||
TopLevelDef::Class { name, object_id, .. },
|
||||
PrimDefDetails::PrimClass { name: exp_name },
|
||||
PrimDefDetails::PrimClass { name: exp_name, .. },
|
||||
) => {
|
||||
let exp_object_id = prim.id();
|
||||
assert_eq!(name, &exp_name.into());
|
||||
|
|
|
@ -766,6 +766,7 @@ impl TopLevelComposer {
|
|||
let target_ty = get_type_from_type_annotation_kinds(
|
||||
&temp_def_list,
|
||||
unifier,
|
||||
primitives,
|
||||
&def,
|
||||
&mut subst_list,
|
||||
)?;
|
||||
|
@ -936,6 +937,7 @@ impl TopLevelComposer {
|
|||
let ty = get_type_from_type_annotation_kinds(
|
||||
temp_def_list.as_ref(),
|
||||
unifier,
|
||||
primitives_store,
|
||||
&type_annotation,
|
||||
&mut None,
|
||||
)?;
|
||||
|
@ -1002,6 +1004,7 @@ impl TopLevelComposer {
|
|||
get_type_from_type_annotation_kinds(
|
||||
&temp_def_list,
|
||||
unifier,
|
||||
primitives_store,
|
||||
&return_ty_annotation,
|
||||
&mut None,
|
||||
)?
|
||||
|
@ -1622,6 +1625,7 @@ impl TopLevelComposer {
|
|||
let self_type = get_type_from_type_annotation_kinds(
|
||||
&def_list,
|
||||
unifier,
|
||||
primitives_ty,
|
||||
&make_self_type_annotation(type_vars, *object_id),
|
||||
&mut None,
|
||||
)?;
|
||||
|
@ -1803,7 +1807,11 @@ impl TopLevelComposer {
|
|||
|
||||
let ty_ann = make_self_type_annotation(type_vars, *class_id);
|
||||
let self_ty = get_type_from_type_annotation_kinds(
|
||||
&def_list, unifier, &ty_ann, &mut None,
|
||||
&def_list,
|
||||
unifier,
|
||||
primitives_ty,
|
||||
&ty_ann,
|
||||
&mut None,
|
||||
)?;
|
||||
vars.extend(type_vars.iter().map(|ty| {
|
||||
let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*ty) else {
|
||||
|
|
|
@ -113,7 +113,7 @@ pub enum PrimDef {
|
|||
/// Associated details of a [`PrimDef`]
|
||||
pub enum PrimDefDetails {
|
||||
PrimFunction { name: &'static str, simple_name: &'static str },
|
||||
PrimClass { name: &'static str },
|
||||
PrimClass { name: &'static str, get_ty_fn: fn(&PrimitiveStore) -> Type },
|
||||
}
|
||||
|
||||
impl PrimDef {
|
||||
|
@ -155,15 +155,17 @@ impl PrimDef {
|
|||
#[must_use]
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self.details() {
|
||||
PrimDefDetails::PrimFunction { name, .. } | PrimDefDetails::PrimClass { name } => name,
|
||||
PrimDefDetails::PrimFunction { name, .. } | PrimDefDetails::PrimClass { name, .. } => {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the associated details of this [`PrimDef`]
|
||||
#[must_use]
|
||||
pub fn details(self) -> PrimDefDetails {
|
||||
fn class(name: &'static str) -> PrimDefDetails {
|
||||
PrimDefDetails::PrimClass { name }
|
||||
fn class(name: &'static str, get_ty_fn: fn(&PrimitiveStore) -> Type) -> PrimDefDetails {
|
||||
PrimDefDetails::PrimClass { name, get_ty_fn }
|
||||
}
|
||||
|
||||
fn fun(name: &'static str, simple_name: Option<&'static str>) -> PrimDefDetails {
|
||||
|
@ -171,22 +173,22 @@ impl PrimDef {
|
|||
}
|
||||
|
||||
match self {
|
||||
PrimDef::Int32 => class("int32"),
|
||||
PrimDef::Int64 => class("int64"),
|
||||
PrimDef::Float => class("float"),
|
||||
PrimDef::Bool => class("bool"),
|
||||
PrimDef::None => class("none"),
|
||||
PrimDef::Range => class("range"),
|
||||
PrimDef::Str => class("str"),
|
||||
PrimDef::Exception => class("Exception"),
|
||||
PrimDef::UInt32 => class("uint32"),
|
||||
PrimDef::UInt64 => class("uint64"),
|
||||
PrimDef::Option => class("Option"),
|
||||
PrimDef::Int32 => class("int32", |primitives| primitives.int32),
|
||||
PrimDef::Int64 => class("int64", |primitives| primitives.int64),
|
||||
PrimDef::Float => class("float", |primitives| primitives.float),
|
||||
PrimDef::Bool => class("bool", |primitives| primitives.bool),
|
||||
PrimDef::None => class("none", |primitives| primitives.none),
|
||||
PrimDef::Range => class("range", |primitives| primitives.range),
|
||||
PrimDef::Str => class("str", |primitives| primitives.str),
|
||||
PrimDef::Exception => class("Exception", |primitives| primitives.exception),
|
||||
PrimDef::UInt32 => class("uint32", |primitives| primitives.uint32),
|
||||
PrimDef::UInt64 => class("uint64", |primitives| primitives.uint64),
|
||||
PrimDef::Option => class("Option", |primitives| primitives.option),
|
||||
PrimDef::OptionIsSome => fun("Option.is_some", Some("is_some")),
|
||||
PrimDef::OptionIsNone => fun("Option.is_none", Some("is_none")),
|
||||
PrimDef::OptionUnwrap => fun("Option.unwrap", Some("unwrap")),
|
||||
PrimDef::List => class("list"),
|
||||
PrimDef::NDArray => class("ndarray"),
|
||||
PrimDef::List => class("list", |primitives| primitives.list),
|
||||
PrimDef::NDArray => class("ndarray", |primitives| primitives.ndarray),
|
||||
PrimDef::NDArrayCopy => fun("ndarray.copy", Some("copy")),
|
||||
PrimDef::NDArrayFill => fun("ndarray.fill", Some("fill")),
|
||||
PrimDef::FunInt32 => fun("int32", None),
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use super::*;
|
||||
use crate::symbol_resolver::SymbolValue;
|
||||
use crate::toplevel::helper::PrimDef;
|
||||
use crate::toplevel::helper::{PrimDef, PrimDefDetails};
|
||||
use crate::typecheck::typedef::VarMap;
|
||||
use nac3parser::ast::Constant;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TypeAnnotation {
|
||||
|
@ -357,6 +358,7 @@ pub fn parse_ast_to_type_annotation_kinds<T, S: std::hash::BuildHasher + Clone>(
|
|||
pub fn get_type_from_type_annotation_kinds(
|
||||
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
||||
unifier: &mut Unifier,
|
||||
primitives: &PrimitiveStore,
|
||||
ann: &TypeAnnotation,
|
||||
subst_list: &mut Option<Vec<Type>>,
|
||||
) -> Result<Type, HashSet<String>> {
|
||||
|
@ -379,100 +381,141 @@ pub fn get_type_from_type_annotation_kinds(
|
|||
let param_ty = params
|
||||
.iter()
|
||||
.map(|x| {
|
||||
get_type_from_type_annotation_kinds(top_level_defs, unifier, x, subst_list)
|
||||
get_type_from_type_annotation_kinds(
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
x,
|
||||
subst_list,
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let subst = {
|
||||
// check for compatible range
|
||||
// TODO: if allow type var to be applied(now this disallowed in the parse_to_type_annotation), need more check
|
||||
let mut result = VarMap::new();
|
||||
for (tvar, p) in type_vars.iter().zip(param_ty) {
|
||||
match unifier.get_ty(*tvar).as_ref() {
|
||||
TypeEnum::TVar {
|
||||
id,
|
||||
range,
|
||||
fields: None,
|
||||
name,
|
||||
loc,
|
||||
is_const_generic: false,
|
||||
} => {
|
||||
let ok: bool = {
|
||||
// create a temp type var and unify to check compatibility
|
||||
p == *tvar || {
|
||||
let temp = unifier.get_fresh_var_with_range(
|
||||
range.as_slice(),
|
||||
*name,
|
||||
*loc,
|
||||
);
|
||||
unifier.unify(temp.ty, p).is_ok()
|
||||
}
|
||||
};
|
||||
if ok {
|
||||
result.insert(*id, p);
|
||||
} else {
|
||||
return Err(HashSet::from([format!(
|
||||
"cannot apply type {} to type variable with id {:?}",
|
||||
unifier.internal_stringify(
|
||||
p,
|
||||
&mut |id| format!("class{id}"),
|
||||
&mut |id| format!("typevar{id}"),
|
||||
&mut None
|
||||
),
|
||||
*id
|
||||
)]));
|
||||
}
|
||||
}
|
||||
let ty = if let Some(prim_def) = PrimDef::iter().find(|prim| prim.id() == *obj_id) {
|
||||
// Primitive TopLevelDefs do not contain all fields that are present in their Type
|
||||
// counterparts, so directly perform subst on the Type instead.
|
||||
|
||||
TypeEnum::TVar { id, range, name, loc, is_const_generic: true, .. } => {
|
||||
let ty = range[0];
|
||||
let ok: bool = {
|
||||
// create a temp type var and unify to check compatibility
|
||||
p == *tvar || {
|
||||
let temp = unifier.get_fresh_const_generic_var(ty, *name, *loc);
|
||||
unifier.unify(temp.ty, p).is_ok()
|
||||
}
|
||||
};
|
||||
if ok {
|
||||
result.insert(*id, p);
|
||||
} else {
|
||||
return Err(HashSet::from([format!(
|
||||
"cannot apply type {} to type variable {}",
|
||||
unifier.stringify(p),
|
||||
name.unwrap_or_else(|| format!("typevar{id}").into()),
|
||||
)]));
|
||||
}
|
||||
}
|
||||
let PrimDefDetails::PrimClass { get_ty_fn, .. } = prim_def.details() else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
_ => unreachable!("must be generic type var"),
|
||||
let base_ty = get_ty_fn(primitives);
|
||||
let params =
|
||||
if let TypeEnum::TObj { params, .. } = &*unifier.get_ty_immutable(base_ty) {
|
||||
params.clone()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
unifier
|
||||
.subst(
|
||||
get_ty_fn(primitives),
|
||||
¶ms
|
||||
.iter()
|
||||
.zip(param_ty)
|
||||
.map(|(obj_tv, param)| (*obj_tv.0, param))
|
||||
.collect(),
|
||||
)
|
||||
.unwrap_or(base_ty)
|
||||
} else {
|
||||
let subst = {
|
||||
// check for compatible range
|
||||
// TODO: if allow type var to be applied(now this disallowed in the parse_to_type_annotation), need more check
|
||||
let mut result = VarMap::new();
|
||||
for (tvar, p) in type_vars.iter().zip(param_ty) {
|
||||
match unifier.get_ty(*tvar).as_ref() {
|
||||
TypeEnum::TVar {
|
||||
id,
|
||||
range,
|
||||
fields: None,
|
||||
name,
|
||||
loc,
|
||||
is_const_generic: false,
|
||||
} => {
|
||||
let ok: bool = {
|
||||
// create a temp type var and unify to check compatibility
|
||||
p == *tvar || {
|
||||
let temp = unifier.get_fresh_var_with_range(
|
||||
range.as_slice(),
|
||||
*name,
|
||||
*loc,
|
||||
);
|
||||
unifier.unify(temp.ty, p).is_ok()
|
||||
}
|
||||
};
|
||||
if ok {
|
||||
result.insert(*id, p);
|
||||
} else {
|
||||
return Err(HashSet::from([format!(
|
||||
"cannot apply type {} to type variable with id {:?}",
|
||||
unifier.internal_stringify(
|
||||
p,
|
||||
&mut |id| format!("class{id}"),
|
||||
&mut |id| format!("typevar{id}"),
|
||||
&mut None
|
||||
),
|
||||
*id
|
||||
)]));
|
||||
}
|
||||
}
|
||||
|
||||
TypeEnum::TVar {
|
||||
id, range, name, loc, is_const_generic: true, ..
|
||||
} => {
|
||||
let ty = range[0];
|
||||
let ok: bool = {
|
||||
// create a temp type var and unify to check compatibility
|
||||
p == *tvar || {
|
||||
let temp =
|
||||
unifier.get_fresh_const_generic_var(ty, *name, *loc);
|
||||
unifier.unify(temp.ty, p).is_ok()
|
||||
}
|
||||
};
|
||||
if ok {
|
||||
result.insert(*id, p);
|
||||
} else {
|
||||
return Err(HashSet::from([format!(
|
||||
"cannot apply type {} to type variable {}",
|
||||
unifier.stringify(p),
|
||||
name.unwrap_or_else(|| format!("typevar{id}").into()),
|
||||
)]));
|
||||
}
|
||||
}
|
||||
|
||||
_ => unreachable!("must be generic type var"),
|
||||
}
|
||||
}
|
||||
result
|
||||
};
|
||||
// Class Attributes keep a copy with Class Definition and are not added to objects
|
||||
let mut tobj_fields = methods
|
||||
.iter()
|
||||
.map(|(name, ty, _)| {
|
||||
let subst_ty = unifier.subst(*ty, &subst).unwrap_or(*ty);
|
||||
// methods are immutable
|
||||
(*name, (subst_ty, false))
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
tobj_fields.extend(fields.iter().map(|(name, ty, mutability)| {
|
||||
let subst_ty = unifier.subst(*ty, &subst).unwrap_or(*ty);
|
||||
(*name, (subst_ty, *mutability))
|
||||
}));
|
||||
let need_subst = !subst.is_empty();
|
||||
let ty = unifier.add_ty(TypeEnum::TObj {
|
||||
obj_id: *obj_id,
|
||||
fields: tobj_fields,
|
||||
params: subst,
|
||||
});
|
||||
|
||||
if need_subst {
|
||||
if let Some(wl) = subst_list.as_mut() {
|
||||
wl.push(ty);
|
||||
}
|
||||
}
|
||||
result
|
||||
|
||||
ty
|
||||
};
|
||||
// Class Attributes keep a copy with Class Definition and are not added to objects
|
||||
let mut tobj_fields = methods
|
||||
.iter()
|
||||
.map(|(name, ty, _)| {
|
||||
let subst_ty = unifier.subst(*ty, &subst).unwrap_or(*ty);
|
||||
// methods are immutable
|
||||
(*name, (subst_ty, false))
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
tobj_fields.extend(fields.iter().map(|(name, ty, mutability)| {
|
||||
let subst_ty = unifier.subst(*ty, &subst).unwrap_or(*ty);
|
||||
(*name, (subst_ty, *mutability))
|
||||
}));
|
||||
let need_subst = !subst.is_empty();
|
||||
let ty = unifier.add_ty(TypeEnum::TObj {
|
||||
obj_id: *obj_id,
|
||||
fields: tobj_fields,
|
||||
params: subst,
|
||||
});
|
||||
if need_subst {
|
||||
if let Some(wl) = subst_list.as_mut() {
|
||||
wl.push(ty);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ty)
|
||||
}
|
||||
TypeAnnotation::Primitive(ty) | TypeAnnotation::TypeVar(ty) => Ok(*ty),
|
||||
|
@ -490,6 +533,7 @@ pub fn get_type_from_type_annotation_kinds(
|
|||
let ty = get_type_from_type_annotation_kinds(
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
ty.as_ref(),
|
||||
subst_list,
|
||||
)?;
|
||||
|
@ -499,7 +543,13 @@ pub fn get_type_from_type_annotation_kinds(
|
|||
let tys = tys
|
||||
.iter()
|
||||
.map(|x| {
|
||||
get_type_from_type_annotation_kinds(top_level_defs, unifier, x, subst_list)
|
||||
get_type_from_type_annotation_kinds(
|
||||
top_level_defs,
|
||||
unifier,
|
||||
primitives,
|
||||
x,
|
||||
subst_list,
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(unifier.add_ty(TypeEnum::TTuple { ty: tys }))
|
||||
|
|
|
@ -207,19 +207,23 @@ impl<'a> Inferencer<'a> {
|
|||
/// This is a workaround preventing the caller from using a variable `alloca`-ed in the body, which
|
||||
/// is freed when the function returns.
|
||||
fn check_return_value_ty(&mut self, ret_ty: Type) -> bool {
|
||||
match &*self.unifier.get_ty_immutable(ret_ty) {
|
||||
TypeEnum::TObj { .. } => [
|
||||
self.primitives.int32,
|
||||
self.primitives.int64,
|
||||
self.primitives.uint32,
|
||||
self.primitives.uint64,
|
||||
self.primitives.float,
|
||||
self.primitives.bool,
|
||||
]
|
||||
.iter()
|
||||
.any(|allowed_ty| self.unifier.unioned(ret_ty, *allowed_ty)),
|
||||
TypeEnum::TTuple { ty } => ty.iter().all(|t| self.check_return_value_ty(*t)),
|
||||
_ => false,
|
||||
if cfg!(feature = "no-escape-analysis") {
|
||||
true
|
||||
} else {
|
||||
match &*self.unifier.get_ty_immutable(ret_ty) {
|
||||
TypeEnum::TObj { .. } => [
|
||||
self.primitives.int32,
|
||||
self.primitives.int64,
|
||||
self.primitives.uint32,
|
||||
self.primitives.uint64,
|
||||
self.primitives.float,
|
||||
self.primitives.bool,
|
||||
]
|
||||
.iter()
|
||||
.any(|allowed_ty| self.unifier.unioned(ret_ty, *allowed_ty)),
|
||||
TypeEnum::TTuple { ty } => ty.iter().all(|t| self.check_return_value_ty(*t)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
|||
authors = ["M-Labs"]
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
no-escape-analysis = ["nac3core/no-escape-analysis"]
|
||||
|
||||
[dependencies]
|
||||
parking_lot = "0.12"
|
||||
nac3parser = { path = "../nac3parser" }
|
||||
|
|
|
@ -113,7 +113,9 @@ fn handle_typevar_definition(
|
|||
x,
|
||||
HashMap::new(),
|
||||
)?;
|
||||
get_type_from_type_annotation_kinds(def_list, unifier, &ty, &mut None)
|
||||
get_type_from_type_annotation_kinds(
|
||||
def_list, unifier, primitives, &ty, &mut None,
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let loc = func.location;
|
||||
|
@ -152,7 +154,7 @@ fn handle_typevar_definition(
|
|||
HashMap::new(),
|
||||
)?;
|
||||
let constraint =
|
||||
get_type_from_type_annotation_kinds(def_list, unifier, &ty, &mut None)?;
|
||||
get_type_from_type_annotation_kinds(def_list, unifier, primitives, &ty, &mut None)?;
|
||||
let loc = func.location;
|
||||
|
||||
Ok(unifier.get_fresh_const_generic_var(constraint, Some(generic_name), Some(loc)).ty)
|
||||
|
|
Loading…
Reference in New Issue