Compare commits
8 Commits
d6565feed3
...
ba32fab374
Author | SHA1 | Date | |
---|---|---|---|
ba32fab374 | |||
c4052b6342 | |||
66c205275f | |||
c85e412206 | |||
075536d7bd | |||
13beeaa2bf | |||
2194dbddd5 | |||
94a1d547d6 |
78
Cargo.lock
generated
78
Cargo.lock
generated
@ -105,9 +105,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.5.0"
|
version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
@ -117,9 +117,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.99"
|
version = "1.0.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
|
checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@ -129,9 +129,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.7"
|
version = "4.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
|
checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -139,9 +139,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.7"
|
version = "4.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
|
checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -151,14 +151,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.5"
|
version = "4.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
|
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -270,9 +270,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.12.0"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ena"
|
name = "ena"
|
||||||
@ -421,7 +421,7 @@ checksum = "4fa4d8d74483041a882adaa9a29f633253a66dde85055f0495c121620ac484b2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -501,9 +501,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
@ -513,9 +513,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.8.3"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
@ -568,9 +568,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.21"
|
version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
@ -749,7 +749,7 @@ dependencies = [
|
|||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.2",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -796,9 +796,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.85"
|
version = "1.0.86"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@ -850,7 +850,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-macros-backend",
|
"pyo3-macros-backend",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -863,7 +863,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1044,14 +1044,14 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.117"
|
version = "1.0.120"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@ -1120,9 +1120,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum"
|
name = "strum"
|
||||||
version = "0.26.2"
|
version = "0.26.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
|
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum_macros"
|
name = "strum_macros"
|
||||||
@ -1134,7 +1134,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.66",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1150,9 +1150,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.66"
|
version = "2.0.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1218,7 +1218,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1471,20 +1471,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.34"
|
version = "0.7.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.7.34"
|
version = "0.7.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
@ -6,8 +6,8 @@ use nac3core::{
|
|||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
},
|
},
|
||||||
symbol_resolver::ValueEnum,
|
symbol_resolver::ValueEnum,
|
||||||
toplevel::{helper::PrimDef, DefinitionId, GenCall},
|
toplevel::{helper::PrimDef, numpy::unpack_ndarray_var_tys, DefinitionId, GenCall},
|
||||||
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum, VarMap},
|
typecheck::typedef::{iter_type_vars, FunSignature, FuncArg, Type, TypeEnum, VarMap},
|
||||||
};
|
};
|
||||||
|
|
||||||
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
|
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
|
||||||
@ -23,7 +23,6 @@ use pyo3::{
|
|||||||
|
|
||||||
use crate::{symbol_resolver::InnerResolver, timeline::TimeFns};
|
use crate::{symbol_resolver::InnerResolver, timeline::TimeFns};
|
||||||
|
|
||||||
use nac3core::toplevel::numpy::unpack_ndarray_var_tys;
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::hash_map::DefaultHasher,
|
collections::hash_map::DefaultHasher,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -394,9 +393,11 @@ fn gen_rpc_tag(
|
|||||||
gen_rpc_tag(ctx, *ty, buffer)?;
|
gen_rpc_tag(ctx, *ty, buffer)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TList { ty } => {
|
TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
|
let ty = iter_type_vars(params).next().unwrap().ty;
|
||||||
|
|
||||||
buffer.push(b'l');
|
buffer.push(b'l');
|
||||||
gen_rpc_tag(ctx, *ty, buffer)?;
|
gen_rpc_tag(ctx, ty, buffer)?;
|
||||||
}
|
}
|
||||||
TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
||||||
let (ndarray_dtype, ndarray_ndims) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
let (ndarray_dtype, ndarray_ndims) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
||||||
@ -675,8 +676,10 @@ pub fn attributes_writeback(
|
|||||||
host_attributes.append(pydict)?;
|
host_attributes.append(pydict)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeEnum::TList { ty: elem_ty } => {
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
if gen_rpc_tag(ctx, *elem_ty, &mut scratch_buffer).is_ok() {
|
let elem_ty = iter_type_vars(params).next().unwrap().ty;
|
||||||
|
|
||||||
|
if gen_rpc_tag(ctx, elem_ty, &mut scratch_buffer).is_ok() {
|
||||||
let pydict = PyDict::new(py);
|
let pydict = PyDict::new(py);
|
||||||
pydict.set_item("obj", val)?;
|
pydict.set_item("obj", val)?;
|
||||||
host_attributes.append(pydict)?;
|
host_attributes.append(pydict)?;
|
||||||
|
@ -329,8 +329,19 @@ impl InnerResolver {
|
|||||||
Ok(Ok((primitives.exception, true)))
|
Ok(Ok((primitives.exception, true)))
|
||||||
} else if ty_id == self.primitive_ids.list {
|
} else if ty_id == self.primitive_ids.list {
|
||||||
// do not handle type var param and concrete check here
|
// do not handle type var param and concrete check here
|
||||||
|
let list_tvar = if let TypeEnum::TObj { obj_id, params, .. } =
|
||||||
|
&*unifier.get_ty_immutable(primitives.list)
|
||||||
|
{
|
||||||
|
assert_eq!(*obj_id, PrimDef::List.id());
|
||||||
|
iter_type_vars(params).nth(0).unwrap()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
let var = unifier.get_dummy_var().ty;
|
let var = unifier.get_dummy_var().ty;
|
||||||
let list = unifier.add_ty(TypeEnum::TList { ty: var });
|
let list = unifier
|
||||||
|
.subst(primitives.list, &into_var_map([TypeVar { id: list_tvar.id, ty: var }]))
|
||||||
|
.unwrap();
|
||||||
Ok(Ok((list, false)))
|
Ok(Ok((list, false)))
|
||||||
} else if ty_id == self.primitive_ids.ndarray {
|
} else if ty_id == self.primitive_ids.ndarray {
|
||||||
// do not handle type var param and concrete check here
|
// do not handle type var param and concrete check here
|
||||||
@ -460,7 +471,7 @@ impl InnerResolver {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match &*unifier.get_ty(origin_ty) {
|
match &*unifier.get_ty(origin_ty) {
|
||||||
TypeEnum::TList { .. } => {
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
if args.len() == 1 {
|
if args.len() == 1 {
|
||||||
let ty = match self.get_pyty_obj_type(
|
let ty = match self.get_pyty_obj_type(
|
||||||
py,
|
py,
|
||||||
@ -477,7 +488,21 @@ impl InnerResolver {
|
|||||||
"type list should take concrete parameters in typevar range".into(),
|
"type list should take concrete parameters in typevar range".into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(Ok((unifier.add_ty(TypeEnum::TList { ty: ty.0 }), true)))
|
let list_tvar = if let TypeEnum::TObj { obj_id, params, .. } =
|
||||||
|
&*unifier.get_ty_immutable(primitives.list)
|
||||||
|
{
|
||||||
|
assert_eq!(*obj_id, PrimDef::List.id());
|
||||||
|
iter_type_vars(params).nth(0).unwrap()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let list = unifier
|
||||||
|
.subst(
|
||||||
|
primitives.list,
|
||||||
|
&into_var_map([TypeVar { id: list_tvar.id, ty: ty.0 }]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
Ok(Ok((list, true)))
|
||||||
} else {
|
} else {
|
||||||
return Ok(Err(format!(
|
return Ok(Err(format!(
|
||||||
"type list needs exactly 1 type parameters, found {}",
|
"type list needs exactly 1 type parameters, found {}",
|
||||||
@ -693,11 +718,12 @@ impl InnerResolver {
|
|||||||
};
|
};
|
||||||
match (&*unifier.get_ty(extracted_ty), inst_check) {
|
match (&*unifier.get_ty(extracted_ty), inst_check) {
|
||||||
// do the instantiation for these four types
|
// do the instantiation for these four types
|
||||||
(TypeEnum::TList { ty }, false) => {
|
(TypeEnum::TObj { obj_id, params, .. }, false) if *obj_id == PrimDef::List.id() => {
|
||||||
|
let ty = iter_type_vars(params).nth(0).unwrap().ty;
|
||||||
let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?;
|
let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?;
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&*unifier.get_ty(*ty),
|
&*unifier.get_ty(ty),
|
||||||
TypeEnum::TVar { fields: None, range, .. }
|
TypeEnum::TVar { fields: None, range, .. }
|
||||||
if range.is_empty()
|
if range.is_empty()
|
||||||
));
|
));
|
||||||
@ -706,8 +732,25 @@ impl InnerResolver {
|
|||||||
let actual_ty =
|
let actual_ty =
|
||||||
self.get_list_elem_type(py, obj, len, unifier, defs, primitives)?;
|
self.get_list_elem_type(py, obj, len, unifier, defs, primitives)?;
|
||||||
match actual_ty {
|
match actual_ty {
|
||||||
Ok(t) => match unifier.unify(*ty, t) {
|
Ok(t) => match unifier.unify(ty, t) {
|
||||||
Ok(()) => Ok(Ok(unifier.add_ty(TypeEnum::TList { ty: *ty }))),
|
Ok(()) => {
|
||||||
|
let list_tvar = if let TypeEnum::TObj { obj_id, params, .. } =
|
||||||
|
&*unifier.get_ty_immutable(primitives.list)
|
||||||
|
{
|
||||||
|
assert_eq!(*obj_id, PrimDef::List.id());
|
||||||
|
iter_type_vars(params).nth(0).unwrap()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let list = unifier
|
||||||
|
.subst(
|
||||||
|
primitives.list,
|
||||||
|
&into_var_map([TypeVar { id: list_tvar.id, ty }]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
Ok(Ok(list))
|
||||||
|
}
|
||||||
|
|
||||||
Err(e) => Ok(Err(format!(
|
Err(e) => Ok(Err(format!(
|
||||||
"type error ({}) for the list",
|
"type error ({}) for the list",
|
||||||
e.to_display(unifier)
|
e.to_display(unifier)
|
||||||
@ -942,12 +985,11 @@ impl InnerResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?;
|
let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?;
|
||||||
let elem_ty = if let TypeEnum::TList { ty } =
|
let elem_ty = match ctx.unifier.get_ty_immutable(expected_ty).as_ref() {
|
||||||
ctx.unifier.get_ty_immutable(expected_ty).as_ref()
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
{
|
iter_type_vars(params).nth(0).unwrap().ty
|
||||||
*ty
|
}
|
||||||
} else {
|
_ => unreachable!("must be list"),
|
||||||
unreachable!("must be list")
|
|
||||||
};
|
};
|
||||||
let ty = ctx.get_llvm_type(generator, elem_ty);
|
let ty = ctx.get_llvm_type(generator, elem_ty);
|
||||||
let size_t = generator.get_size_type(ctx.ctx);
|
let size_t = generator.get_size_type(ctx.ctx);
|
||||||
|
@ -10,7 +10,7 @@ constant-optimization = ["fold"]
|
|||||||
fold = []
|
fold = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.5"
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
string-interner = "0.17"
|
string-interner = "0.17"
|
||||||
fxhash = "0.2"
|
fxhash = "0.2"
|
||||||
|
@ -725,7 +725,7 @@ pub fn call_numpy_min<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
ctx,
|
ctx,
|
||||||
llvm_usize.const_int(1, false),
|
llvm_usize.const_int(1, false),
|
||||||
(n_sz, false),
|
(n_sz, false),
|
||||||
|generator, ctx, idx| {
|
|generator, ctx, _, idx| {
|
||||||
let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) };
|
let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) };
|
||||||
|
|
||||||
let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
||||||
@ -941,7 +941,7 @@ pub fn call_numpy_max<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
ctx,
|
ctx,
|
||||||
llvm_usize.const_int(1, false),
|
llvm_usize.const_int(1, false),
|
||||||
(n_sz, false),
|
(n_sz, false),
|
||||||
|generator, ctx, idx| {
|
|generator, ctx, _, idx| {
|
||||||
let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) };
|
let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) };
|
||||||
|
|
||||||
let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
||||||
|
@ -713,12 +713,25 @@ impl<'ctx> ListValue<'ctx> {
|
|||||||
/// If `size` is [None], the size stored in the field of this instance is used instead.
|
/// If `size` is [None], the size stored in the field of this instance is used instead.
|
||||||
pub fn create_data(
|
pub fn create_data(
|
||||||
&self,
|
&self,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
elem_ty: BasicTypeEnum<'ctx>,
|
elem_ty: BasicTypeEnum<'ctx>,
|
||||||
size: Option<IntValue<'ctx>>,
|
size: Option<IntValue<'ctx>>,
|
||||||
) {
|
) {
|
||||||
let size = size.unwrap_or_else(|| self.load_size(ctx, None));
|
let size = size.unwrap_or_else(|| self.load_size(ctx, None));
|
||||||
self.store_data(ctx, ctx.builder.build_array_alloca(elem_ty, size, "").unwrap());
|
|
||||||
|
let data = ctx
|
||||||
|
.builder
|
||||||
|
.build_select(
|
||||||
|
ctx.builder
|
||||||
|
.build_int_compare(IntPredicate::NE, size, self.llvm_usize.const_zero(), "")
|
||||||
|
.unwrap(),
|
||||||
|
ctx.builder.build_array_alloca(elem_ty, size, "").unwrap(),
|
||||||
|
elem_ty.ptr_type(AddressSpace::default()).const_zero(),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.map(BasicValueEnum::into_pointer_value)
|
||||||
|
.unwrap();
|
||||||
|
self.store_data(ctx, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr`
|
/// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr`
|
||||||
@ -1706,7 +1719,7 @@ impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index>
|
|||||||
ctx,
|
ctx,
|
||||||
llvm_usize.const_zero(),
|
llvm_usize.const_zero(),
|
||||||
(len, false),
|
(len, false),
|
||||||
|generator, ctx, i| {
|
|generator, ctx, _, i| {
|
||||||
let (dim_idx, dim_sz) = unsafe {
|
let (dim_idx, dim_sz) = unsafe {
|
||||||
(
|
(
|
||||||
indices.get_unchecked(ctx, generator, &i, None).into_int_value(),
|
indices.get_unchecked(ctx, generator, &i, None).into_int_value(),
|
||||||
|
@ -47,9 +47,6 @@ pub enum ConcreteTypeEnum {
|
|||||||
TTuple {
|
TTuple {
|
||||||
ty: Vec<ConcreteType>,
|
ty: Vec<ConcreteType>,
|
||||||
},
|
},
|
||||||
TList {
|
|
||||||
ty: ConcreteType,
|
|
||||||
},
|
|
||||||
TObj {
|
TObj {
|
||||||
obj_id: DefinitionId,
|
obj_id: DefinitionId,
|
||||||
fields: HashMap<StrRef, (ConcreteType, bool)>,
|
fields: HashMap<StrRef, (ConcreteType, bool)>,
|
||||||
@ -167,9 +164,6 @@ impl ConcreteTypeStore {
|
|||||||
.map(|t| self.from_unifier_type(unifier, primitives, *t, cache))
|
.map(|t| self.from_unifier_type(unifier, primitives, *t, cache))
|
||||||
.collect(),
|
.collect(),
|
||||||
},
|
},
|
||||||
TypeEnum::TList { ty } => ConcreteTypeEnum::TList {
|
|
||||||
ty: self.from_unifier_type(unifier, primitives, *ty, cache),
|
|
||||||
},
|
|
||||||
TypeEnum::TObj { obj_id, fields, params } => ConcreteTypeEnum::TObj {
|
TypeEnum::TObj { obj_id, fields, params } => ConcreteTypeEnum::TObj {
|
||||||
obj_id: *obj_id,
|
obj_id: *obj_id,
|
||||||
fields: fields
|
fields: fields
|
||||||
@ -260,9 +254,6 @@ impl ConcreteTypeStore {
|
|||||||
.map(|cty| self.to_unifier_type(unifier, primitives, *cty, cache))
|
.map(|cty| self.to_unifier_type(unifier, primitives, *cty, cache))
|
||||||
.collect(),
|
.collect(),
|
||||||
},
|
},
|
||||||
ConcreteTypeEnum::TList { ty } => {
|
|
||||||
TypeEnum::TList { ty: self.to_unifier_type(unifier, primitives, *ty, cache) }
|
|
||||||
}
|
|
||||||
ConcreteTypeEnum::TVirtual { ty } => {
|
ConcreteTypeEnum::TVirtual { ty } => {
|
||||||
TypeEnum::TVirtual { ty: self.to_unifier_type(unifier, primitives, *ty, cache) }
|
TypeEnum::TVirtual { ty: self.to_unifier_type(unifier, primitives, *ty, cache) }
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,22 @@ use std::{collections::HashMap, convert::TryInto, iter::once, iter::zip};
|
|||||||
use crate::{
|
use crate::{
|
||||||
codegen::{
|
codegen::{
|
||||||
classes::{
|
classes::{
|
||||||
ArrayLikeIndexer, ArrayLikeValue, ListValue, NDArrayValue, ProxyValue, RangeValue,
|
ArrayLikeIndexer, ArrayLikeValue, ListType, ListValue, NDArrayValue, ProxyType,
|
||||||
TypedArrayLikeAccessor, UntypedArrayLikeAccessor,
|
ProxyValue, RangeValue, TypedArrayLikeAccessor, UntypedArrayLikeAccessor,
|
||||||
},
|
},
|
||||||
concrete_type::{ConcreteFuncArg, ConcreteTypeEnum, ConcreteTypeStore},
|
concrete_type::{ConcreteFuncArg, ConcreteTypeEnum, ConcreteTypeStore},
|
||||||
gen_in_range_check, get_llvm_abi_type, get_llvm_type,
|
gen_in_range_check, get_llvm_abi_type, get_llvm_type,
|
||||||
irrt::*,
|
irrt::*,
|
||||||
llvm_intrinsics::{call_expect, call_float_floor, call_float_pow, call_float_powi},
|
llvm_intrinsics::{
|
||||||
numpy,
|
call_expect, call_float_floor, call_float_pow, call_float_powi, call_int_smax,
|
||||||
stmt::{gen_if_else_expr_callback, gen_raise, gen_var},
|
call_memcpy_generic,
|
||||||
CodeGenContext, CodeGenTask,
|
},
|
||||||
|
need_sret, numpy,
|
||||||
|
stmt::{
|
||||||
|
gen_for_callback_incrementing, gen_if_callback, gen_if_else_expr_callback, gen_raise,
|
||||||
|
gen_var,
|
||||||
|
},
|
||||||
|
CodeGenContext, CodeGenTask, CodeGenerator,
|
||||||
},
|
},
|
||||||
symbol_resolver::{SymbolValue, ValueEnum},
|
symbol_resolver::{SymbolValue, ValueEnum},
|
||||||
toplevel::{
|
toplevel::{
|
||||||
@ -29,15 +35,14 @@ use inkwell::{
|
|||||||
attributes::{Attribute, AttributeLoc},
|
attributes::{Attribute, AttributeLoc},
|
||||||
types::{AnyType, BasicType, BasicTypeEnum},
|
types::{AnyType, BasicType, BasicTypeEnum},
|
||||||
values::{BasicValueEnum, CallSiteValue, FunctionValue, IntValue, PointerValue},
|
values::{BasicValueEnum, CallSiteValue, FunctionValue, IntValue, PointerValue},
|
||||||
AddressSpace, IntPredicate,
|
AddressSpace, IntPredicate, OptimizationLevel,
|
||||||
};
|
};
|
||||||
use itertools::{chain, izip, Either, Itertools};
|
use itertools::{chain, izip, Either, Itertools};
|
||||||
use nac3parser::ast::{
|
use nac3parser::ast::{
|
||||||
self, Boolop, Comprehension, Constant, Expr, ExprKind, Location, Operator, StrRef,
|
self, Boolop, Cmpop, Comprehension, Constant, Expr, ExprKind, Location, Operator, StrRef,
|
||||||
|
Unaryop,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{llvm_intrinsics::call_memcpy_generic, need_sret, CodeGenerator};
|
|
||||||
|
|
||||||
pub fn get_subst_key(
|
pub fn get_subst_key(
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
obj: Option<Type>,
|
obj: Option<Type>,
|
||||||
@ -946,30 +951,26 @@ pub fn destructure_range<'ctx>(
|
|||||||
/// Allocates a List structure with the given [type][ty] and [length]. The name of the resulting
|
/// 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.
|
/// LLVM value is `{name}.addr`, or `list.addr` if [name] is not specified.
|
||||||
///
|
///
|
||||||
/// Returns an instance of [`PointerValue`] pointing to the List structure. The List structure is
|
/// Setting `ty` to [`None`] implies that the list does not have a known element type, which is only
|
||||||
/// defined as `type { ty*, size_t }` in LLVM, where the first element stores the pointer to the
|
/// valid for empty lists. It is undefined behavior to generate a sized list with an unknown element
|
||||||
/// data, and the second element stores the size of the List.
|
/// type.
|
||||||
pub fn allocate_list<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn allocate_list<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
ty: BasicTypeEnum<'ctx>,
|
ty: Option<BasicTypeEnum<'ctx>>,
|
||||||
length: IntValue<'ctx>,
|
length: IntValue<'ctx>,
|
||||||
name: Option<&str>,
|
name: Option<&'ctx str>,
|
||||||
) -> ListValue<'ctx> {
|
) -> ListValue<'ctx> {
|
||||||
let size_t = generator.get_size_type(ctx.ctx);
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
let llvm_elem_ty = ty.unwrap_or(llvm_usize.into());
|
||||||
|
|
||||||
// List structure; type { ty*, size_t }
|
// List structure; type { ty*, size_t }
|
||||||
let arr_ty =
|
let arr_ty = ListType::new(generator, ctx.ctx, llvm_elem_ty);
|
||||||
ctx.ctx.struct_type(&[ty.ptr_type(AddressSpace::default()).into(), size_t.into()], false);
|
let list = arr_ty.new_value(generator, ctx, name);
|
||||||
|
|
||||||
let arr_str_ptr = ctx
|
let length = ctx.builder.build_int_z_extend(length, llvm_usize, "").unwrap();
|
||||||
.builder
|
|
||||||
.build_alloca(arr_ty, format!("{}.addr", name.unwrap_or("list")).as_str())
|
|
||||||
.unwrap();
|
|
||||||
let list = ListValue::from_ptr_val(arr_str_ptr, size_t, Some("list"));
|
|
||||||
|
|
||||||
let length = ctx.builder.build_int_z_extend(length, size_t, "").unwrap();
|
|
||||||
list.store_size(ctx, generator, length);
|
list.store_size(ctx, generator, length);
|
||||||
list.create_data(ctx, ty, None);
|
list.create_data(ctx, llvm_elem_ty, None);
|
||||||
|
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
@ -1042,7 +1043,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
list = allocate_list(
|
list = allocate_list(
|
||||||
generator,
|
generator,
|
||||||
ctx,
|
ctx,
|
||||||
elem_ty,
|
Some(elem_ty),
|
||||||
list_alloc_size.into_int_value(),
|
list_alloc_size.into_int_value(),
|
||||||
Some("listcomp.addr"),
|
Some("listcomp.addr"),
|
||||||
);
|
);
|
||||||
@ -1081,7 +1082,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
Some("length"),
|
Some("length"),
|
||||||
)
|
)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
list = allocate_list(generator, ctx, elem_ty, length, Some("listcomp"));
|
list = allocate_list(generator, ctx, Some(elem_ty), length, Some("listcomp"));
|
||||||
list_content = list.data().base_ptr(ctx, generator);
|
list_content = list.data().base_ptr(ctx, generator);
|
||||||
let counter = generator.gen_var_alloc(ctx, size_t.into(), Some("counter.addr"))?;
|
let counter = generator.gen_var_alloc(ctx, size_t.into(), Some("counter.addr"))?;
|
||||||
// counter = -1
|
// counter = -1
|
||||||
@ -1197,6 +1198,168 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
Some("f_pow_i"),
|
Some("f_pow_i"),
|
||||||
);
|
);
|
||||||
Ok(Some(res.into()))
|
Ok(Some(res.into()))
|
||||||
|
} else if ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id())
|
||||||
|
|| ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id())
|
||||||
|
{
|
||||||
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
|
||||||
|
if is_aug_assign {
|
||||||
|
todo!("Augmented assignment operators not implemented for lists")
|
||||||
|
}
|
||||||
|
|
||||||
|
match op {
|
||||||
|
Operator::Add => {
|
||||||
|
debug_assert_eq!(ty1.obj_id(&ctx.unifier), Some(PrimDef::List.id()));
|
||||||
|
debug_assert_eq!(ty2.obj_id(&ctx.unifier), Some(PrimDef::List.id()));
|
||||||
|
|
||||||
|
let elem_ty1 =
|
||||||
|
if let TypeEnum::TObj { params, .. } = &*ctx.unifier.get_ty_immutable(ty1) {
|
||||||
|
ctx.unifier.get_representative(*params.iter().next().unwrap().1)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let elem_ty2 =
|
||||||
|
if let TypeEnum::TObj { params, .. } = &*ctx.unifier.get_ty_immutable(ty2) {
|
||||||
|
ctx.unifier.get_representative(*params.iter().next().unwrap().1)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
debug_assert!(ctx.unifier.unioned(elem_ty1, elem_ty2));
|
||||||
|
|
||||||
|
let llvm_elem_ty = ctx.get_llvm_type(generator, elem_ty1);
|
||||||
|
|
||||||
|
let lhs = ListValue::from_ptr_val(left_val.into_pointer_value(), llvm_usize, None);
|
||||||
|
let rhs = ListValue::from_ptr_val(right_val.into_pointer_value(), llvm_usize, None);
|
||||||
|
|
||||||
|
let size = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_add(lhs.load_size(ctx, None), rhs.load_size(ctx, None), "")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_list = allocate_list(generator, ctx, Some(llvm_elem_ty), size, None);
|
||||||
|
|
||||||
|
let lhs_len = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_mul(lhs.load_size(ctx, None), llvm_elem_ty.size_of().unwrap(), "")
|
||||||
|
.unwrap();
|
||||||
|
let rhs_len = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_mul(rhs.load_size(ctx, None), llvm_elem_ty.size_of().unwrap(), "")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let list_ptr = new_list.data().base_ptr(ctx, generator);
|
||||||
|
call_memcpy_generic(
|
||||||
|
ctx,
|
||||||
|
list_ptr,
|
||||||
|
lhs.data().base_ptr(ctx, generator),
|
||||||
|
lhs_len,
|
||||||
|
ctx.ctx.bool_type().const_zero(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let list_ptr = unsafe {
|
||||||
|
new_list.data().ptr_offset_unchecked(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
&lhs.load_size(ctx, None),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
call_memcpy_generic(
|
||||||
|
ctx,
|
||||||
|
list_ptr,
|
||||||
|
rhs.data().base_ptr(ctx, generator),
|
||||||
|
rhs_len,
|
||||||
|
ctx.ctx.bool_type().const_zero(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Some(new_list.as_base_value().into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
Operator::Mult => {
|
||||||
|
let (elem_ty, list_val, int_val) =
|
||||||
|
if ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id()) {
|
||||||
|
let elem_ty = if let TypeEnum::TObj { params, .. } =
|
||||||
|
&*ctx.unifier.get_ty_immutable(ty1)
|
||||||
|
{
|
||||||
|
*params.iter().next().unwrap().1
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
(elem_ty, left_val, right_val)
|
||||||
|
} else if ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id()) {
|
||||||
|
let elem_ty = if let TypeEnum::TObj { params, .. } =
|
||||||
|
&*ctx.unifier.get_ty_immutable(ty2)
|
||||||
|
{
|
||||||
|
*params.iter().next().unwrap().1
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
(elem_ty, right_val, left_val)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let list_val =
|
||||||
|
ListValue::from_ptr_val(list_val.into_pointer_value(), llvm_usize, None);
|
||||||
|
let int_val = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_s_extend(int_val.into_int_value(), llvm_usize, "")
|
||||||
|
.unwrap();
|
||||||
|
// [...] * (i where i < 0) => []
|
||||||
|
let int_val = call_int_smax(ctx, int_val, llvm_usize.const_zero(), None);
|
||||||
|
|
||||||
|
let elem_llvm_ty = ctx.get_llvm_type(generator, elem_ty);
|
||||||
|
|
||||||
|
let new_list = allocate_list(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
Some(elem_llvm_ty),
|
||||||
|
ctx.builder.build_int_mul(list_val.load_size(ctx, None), int_val, "").unwrap(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
gen_for_callback_incrementing(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
llvm_usize.const_zero(),
|
||||||
|
(int_val, false),
|
||||||
|
|generator, ctx, _, i| {
|
||||||
|
let offset = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_mul(i, list_val.load_size(ctx, None), "")
|
||||||
|
.unwrap();
|
||||||
|
let ptr = unsafe {
|
||||||
|
new_list.data().ptr_offset_unchecked(ctx, generator, &offset, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
let memcpy_sz = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_mul(
|
||||||
|
list_val.load_size(ctx, None),
|
||||||
|
elem_llvm_ty.size_of().unwrap(),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
call_memcpy_generic(
|
||||||
|
ctx,
|
||||||
|
ptr,
|
||||||
|
list_val.data().base_ptr(ctx, generator),
|
||||||
|
memcpy_sz,
|
||||||
|
ctx.ctx.bool_type().const_zero(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
llvm_usize.const_int(1, false),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(Some(new_list.as_base_value().into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => todo!("Operator not supported"),
|
||||||
|
}
|
||||||
} else if ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
} else if ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
||||||
|| ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
|| ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
||||||
{
|
{
|
||||||
@ -1674,6 +1837,188 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
ctx.builder.build_float_compare(op, lhs, rhs, "cmp").unwrap()
|
ctx.builder.build_float_compare(op, lhs, rhs, "cmp").unwrap()
|
||||||
|
} else if [left_ty, right_ty]
|
||||||
|
.iter()
|
||||||
|
.any(|ty| ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id()))
|
||||||
|
{
|
||||||
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
|
||||||
|
let gen_list_cmpop = |generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>|
|
||||||
|
-> Result<IntValue<'ctx>, String> {
|
||||||
|
let is_list1 =
|
||||||
|
left_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id());
|
||||||
|
let is_list2 =
|
||||||
|
right_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id());
|
||||||
|
|
||||||
|
let gen_bool_const = |ctx: &CodeGenContext<'ctx, '_>, val: bool| {
|
||||||
|
let llvm_i1 = ctx.ctx.bool_type();
|
||||||
|
|
||||||
|
match (op, val) {
|
||||||
|
(Cmpop::Eq, true) | (Cmpop::NotEq, false) => llvm_i1.const_all_ones(),
|
||||||
|
(Cmpop::Eq, false) | (Cmpop::NotEq, true) => llvm_i1.const_zero(),
|
||||||
|
(_, _) => unreachable!(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !(is_list1 && is_list2) {
|
||||||
|
return Ok(generator.bool_to_i8(ctx, gen_bool_const(ctx, false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let left_elem_ty = if let TypeEnum::TObj { params, .. } =
|
||||||
|
&*ctx.unifier.get_ty_immutable(left_ty)
|
||||||
|
{
|
||||||
|
*params.iter().next().unwrap().1
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let right_elem_ty = if let TypeEnum::TObj { params, .. } =
|
||||||
|
&*ctx.unifier.get_ty_immutable(right_ty)
|
||||||
|
{
|
||||||
|
*params.iter().next().unwrap().1
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
if !ctx.unifier.unioned(left_elem_ty, right_elem_ty) {
|
||||||
|
return Ok(generator.bool_to_i8(ctx, gen_bool_const(ctx, false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ![Cmpop::Eq, Cmpop::NotEq].contains(op) {
|
||||||
|
todo!("Only __eq__ and __ne__ is implemented for lists")
|
||||||
|
}
|
||||||
|
|
||||||
|
let left_val =
|
||||||
|
ListValue::from_ptr_val(lhs.into_pointer_value(), llvm_usize, None);
|
||||||
|
let right_val =
|
||||||
|
ListValue::from_ptr_val(rhs.into_pointer_value(), llvm_usize, None);
|
||||||
|
|
||||||
|
Ok(gen_if_else_expr_callback(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
|_, ctx| {
|
||||||
|
Ok(ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(
|
||||||
|
IntPredicate::EQ,
|
||||||
|
left_val.load_size(ctx, None),
|
||||||
|
right_val.load_size(ctx, None),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.unwrap())
|
||||||
|
},
|
||||||
|
|generator, ctx| {
|
||||||
|
let acc_addr = generator
|
||||||
|
.gen_var_alloc(ctx, ctx.ctx.bool_type().into(), None)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder
|
||||||
|
.build_store(acc_addr, ctx.ctx.bool_type().const_all_ones())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
gen_for_callback_incrementing(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
llvm_usize.const_zero(),
|
||||||
|
(left_val.load_size(ctx, None), false),
|
||||||
|
|generator, ctx, hooks, i| {
|
||||||
|
let left = unsafe {
|
||||||
|
left_val.data().get_unchecked(ctx, generator, &i, None)
|
||||||
|
};
|
||||||
|
let right = unsafe {
|
||||||
|
right_val.data().get_unchecked(ctx, generator, &i, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = gen_cmpop_expr_with_values(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
(Some(left_elem_ty), left),
|
||||||
|
&[Cmpop::Eq],
|
||||||
|
&[(Some(right_elem_ty), right)],
|
||||||
|
)?
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator, ctx.primitives.bool)
|
||||||
|
.unwrap()
|
||||||
|
.into_int_value();
|
||||||
|
|
||||||
|
gen_if_callback(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
|_, ctx| {
|
||||||
|
Ok(ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(
|
||||||
|
IntPredicate::EQ,
|
||||||
|
res,
|
||||||
|
res.get_type().const_zero(),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.unwrap())
|
||||||
|
},
|
||||||
|
|_, ctx| {
|
||||||
|
ctx.builder
|
||||||
|
.build_store(
|
||||||
|
acc_addr,
|
||||||
|
ctx.ctx.bool_type().const_zero(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder
|
||||||
|
.build_unconditional_branch(hooks.exit_bb)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
|_, _| Ok(()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
llvm_usize.const_int(1, false),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let acc = ctx
|
||||||
|
.builder
|
||||||
|
.build_load(acc_addr, "")
|
||||||
|
.map(BasicValueEnum::into_int_value)
|
||||||
|
.unwrap();
|
||||||
|
let acc = if *op == Cmpop::NotEq {
|
||||||
|
gen_unaryop_expr_with_values(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
Unaryop::Not,
|
||||||
|
(&Some(ctx.primitives.bool), acc.into()),
|
||||||
|
)?
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator, ctx.primitives.bool)?
|
||||||
|
.into_int_value()
|
||||||
|
} else {
|
||||||
|
acc
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Some(generator.bool_to_i8(ctx, acc)))
|
||||||
|
},
|
||||||
|
|generator, ctx| {
|
||||||
|
Ok(Some(generator.bool_to_i8(ctx, gen_bool_const(ctx, false))))
|
||||||
|
},
|
||||||
|
)?
|
||||||
|
.map(BasicValueEnum::into_int_value)
|
||||||
|
.unwrap())
|
||||||
|
};
|
||||||
|
|
||||||
|
gen_list_cmpop(generator, ctx)?
|
||||||
|
} else if [left_ty, right_ty].iter().any(|ty| matches!(&*ctx.unifier.get_ty_immutable(*ty), TypeEnum::TVar { .. })) {
|
||||||
|
if ctx.registry.llvm_options.opt_level != OptimizationLevel::None {
|
||||||
|
ctx.make_assert(
|
||||||
|
generator,
|
||||||
|
ctx.ctx.bool_type().const_all_ones(),
|
||||||
|
"0:AssertionError",
|
||||||
|
"nac3core::codegen::expr::gen_cmpop_expr_with_values: Unexpected comparison between two typevar values",
|
||||||
|
[None, None, None],
|
||||||
|
ctx.current_loc,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.ctx.bool_type().get_poison()
|
||||||
} else {
|
} else {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
};
|
};
|
||||||
@ -2124,13 +2469,23 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ty = if elements.is_empty() {
|
let ty = if elements.is_empty() {
|
||||||
let TypeEnum::TList { ty } = &*ctx.unifier.get_ty(expr.custom.unwrap()) else {
|
let ty = if let TypeEnum::TObj { obj_id, params, .. } =
|
||||||
|
&*ctx.unifier.get_ty(expr.custom.unwrap())
|
||||||
|
{
|
||||||
|
assert_eq!(*obj_id, PrimDef::List.id());
|
||||||
|
|
||||||
|
*params.iter().next().unwrap().1
|
||||||
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.get_llvm_type(generator, *ty)
|
if let TypeEnum::TVar { .. } = &*ctx.unifier.get_ty_immutable(ty) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(ctx.get_llvm_type(generator, ty))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
elements[0].get_type()
|
Some(elements[0].get_type())
|
||||||
};
|
};
|
||||||
let length = generator.get_size_type(ctx.ctx).const_int(elements.len() as u64, false);
|
let length = generator.get_size_type(ctx.ctx).const_int(elements.len() as u64, false);
|
||||||
let arr_str_ptr = allocate_list(generator, ctx, ty, length, Some("list"));
|
let arr_str_ptr = allocate_list(generator, ctx, ty, length, Some("list"));
|
||||||
@ -2550,7 +2905,9 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
ExprKind::Subscript { value, slice, .. } => {
|
ExprKind::Subscript { value, slice, .. } => {
|
||||||
match &*ctx.unifier.get_ty(value.custom.unwrap()) {
|
match &*ctx.unifier.get_ty(value.custom.unwrap()) {
|
||||||
TypeEnum::TList { ty } => {
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
|
let ty = params.iter().next().unwrap().1;
|
||||||
|
|
||||||
let v = if let Some(v) = generator.gen_expr(ctx, value)? {
|
let v = if let Some(v) = generator.gen_expr(ctx, value)? {
|
||||||
v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
||||||
.into_pointer_value()
|
.into_pointer_value()
|
||||||
@ -2589,7 +2946,8 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
step,
|
step,
|
||||||
);
|
);
|
||||||
let res_array_ret = allocate_list(generator, ctx, ty, length, Some("ret"));
|
let res_array_ret =
|
||||||
|
allocate_list(generator, ctx, Some(ty), length, Some("ret"));
|
||||||
let Some(res_ind) = handle_slice_indices(
|
let Some(res_ind) = handle_slice_indices(
|
||||||
&None,
|
&None,
|
||||||
&None,
|
&None,
|
||||||
|
@ -800,7 +800,7 @@ pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
ctx,
|
ctx,
|
||||||
llvm_usize.const_zero(),
|
llvm_usize.const_zero(),
|
||||||
(min_ndims, false),
|
(min_ndims, false),
|
||||||
|generator, ctx, idx| {
|
|generator, ctx, _, idx| {
|
||||||
let idx = ctx.builder.build_int_sub(min_ndims, idx, "").unwrap();
|
let idx = ctx.builder.build_int_sub(min_ndims, idx, "").unwrap();
|
||||||
let (lhs_dim_sz, rhs_dim_sz) = unsafe {
|
let (lhs_dim_sz, rhs_dim_sz) = unsafe {
|
||||||
(
|
(
|
||||||
|
@ -456,6 +456,20 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
|
let element_type = get_llvm_type(
|
||||||
|
ctx,
|
||||||
|
module,
|
||||||
|
generator,
|
||||||
|
unifier,
|
||||||
|
top_level,
|
||||||
|
type_cache,
|
||||||
|
*params.iter().next().unwrap().1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ListType::new(generator, ctx, element_type).as_base_type().into()
|
||||||
|
}
|
||||||
|
|
||||||
TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
||||||
let (dtype, _) = unpack_ndarray_var_tys(unifier, ty);
|
let (dtype, _) = unpack_ndarray_var_tys(unifier, ty);
|
||||||
let element_type = get_llvm_type(
|
let element_type = get_llvm_type(
|
||||||
@ -516,12 +530,6 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
.collect_vec();
|
.collect_vec();
|
||||||
ctx.struct_type(&fields, false).into()
|
ctx.struct_type(&fields, false).into()
|
||||||
}
|
}
|
||||||
TList { ty } => {
|
|
||||||
let element_type =
|
|
||||||
get_llvm_type(ctx, module, generator, unifier, top_level, type_cache, *ty);
|
|
||||||
|
|
||||||
ListType::new(generator, ctx, element_type).as_base_type().into()
|
|
||||||
}
|
|
||||||
TVirtual { .. } => unimplemented!(),
|
TVirtual { .. } => unimplemented!(),
|
||||||
_ => unreachable!("{}", ty_enum.get_type_name()),
|
_ => unreachable!("{}", ty_enum.get_type_name()),
|
||||||
};
|
};
|
||||||
|
@ -86,7 +86,7 @@ where
|
|||||||
ctx,
|
ctx,
|
||||||
llvm_usize.const_zero(),
|
llvm_usize.const_zero(),
|
||||||
(shape_len, false),
|
(shape_len, false),
|
||||||
|generator, ctx, i| {
|
|generator, ctx, _, i| {
|
||||||
let shape_dim = shape_data_fn(generator, ctx, shape, i)?;
|
let shape_dim = shape_data_fn(generator, ctx, shape, i)?;
|
||||||
debug_assert!(shape_dim.get_type().get_bit_width() <= llvm_usize.get_bit_width());
|
debug_assert!(shape_dim.get_type().get_bit_width() <= llvm_usize.get_bit_width());
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ where
|
|||||||
ctx,
|
ctx,
|
||||||
llvm_usize.const_zero(),
|
llvm_usize.const_zero(),
|
||||||
(shape_len, false),
|
(shape_len, false),
|
||||||
|generator, ctx, i| {
|
|generator, ctx, _, i| {
|
||||||
let shape_dim = shape_data_fn(generator, ctx, shape, i)?;
|
let shape_dim = shape_data_fn(generator, ctx, shape, i)?;
|
||||||
debug_assert!(shape_dim.get_type().get_bit_width() <= llvm_usize.get_bit_width());
|
debug_assert!(shape_dim.get_type().get_bit_width() <= llvm_usize.get_bit_width());
|
||||||
let shape_dim = ctx.builder.build_int_z_extend(shape_dim, llvm_usize, "").unwrap();
|
let shape_dim = ctx.builder.build_int_z_extend(shape_dim, llvm_usize, "").unwrap();
|
||||||
@ -382,7 +382,7 @@ where
|
|||||||
ctx,
|
ctx,
|
||||||
llvm_usize.const_zero(),
|
llvm_usize.const_zero(),
|
||||||
(ndarray_num_elems, false),
|
(ndarray_num_elems, false),
|
||||||
|generator, ctx, i| {
|
|generator, ctx, _, i| {
|
||||||
let elem = unsafe { ndarray.data().ptr_offset_unchecked(ctx, generator, &i, None) };
|
let elem = unsafe { ndarray.data().ptr_offset_unchecked(ctx, generator, &i, None) };
|
||||||
|
|
||||||
let value = value_fn(generator, ctx, i)?;
|
let value = value_fn(generator, ctx, i)?;
|
||||||
@ -1243,7 +1243,7 @@ pub fn ndarray_sliced_copy<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
ctx,
|
ctx,
|
||||||
llvm_usize.const_int(slices.len() as u64, false),
|
llvm_usize.const_int(slices.len() as u64, false),
|
||||||
(this.load_ndims(ctx), false),
|
(this.load_ndims(ctx), false),
|
||||||
|generator, ctx, idx| {
|
|generator, ctx, _, idx| {
|
||||||
unsafe {
|
unsafe {
|
||||||
let dim_sz = this.dim_sizes().get_typed_unchecked(ctx, generator, &idx, None);
|
let dim_sz = this.dim_sizes().get_typed_unchecked(ctx, generator, &idx, None);
|
||||||
ndarray.dim_sizes().set_typed_unchecked(ctx, generator, &idx, dim_sz);
|
ndarray.dim_sizes().set_typed_unchecked(ctx, generator, &idx, dim_sz);
|
||||||
@ -1647,7 +1647,7 @@ pub fn ndarray_matmul_2d<'ctx, G: CodeGenerator>(
|
|||||||
ctx,
|
ctx,
|
||||||
llvm_i32.const_zero(),
|
llvm_i32.const_zero(),
|
||||||
(common_dim, false),
|
(common_dim, false),
|
||||||
|generator, ctx, i| {
|
|generator, ctx, _, i| {
|
||||||
let i = ctx.builder.build_int_truncate(i, llvm_i32, "").unwrap();
|
let i = ctx.builder.build_int_truncate(i, llvm_i32, "").unwrap();
|
||||||
|
|
||||||
let ab_idx = generator.gen_array_var_alloc(
|
let ab_idx = generator.gen_array_var_alloc(
|
||||||
@ -1804,10 +1804,15 @@ pub fn gen_ndarray_array<'ctx>(
|
|||||||
unpack_ndarray_var_tys(&mut context.unifier, obj_ty).0
|
unpack_ndarray_var_tys(&mut context.unifier, obj_ty).0
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeEnum::TList { ty } => {
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
let mut ty = *ty;
|
let mut ty = *params.iter().next().unwrap().1;
|
||||||
while let TypeEnum::TList { ty: elem_ty } = &*context.unifier.get_ty_immutable(ty) {
|
while let TypeEnum::TObj { obj_id, params, .. } = &*context.unifier.get_ty_immutable(ty)
|
||||||
ty = *elem_ty;
|
{
|
||||||
|
if *obj_id != PrimDef::List.id() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ty = *params.iter().next().unwrap().1;
|
||||||
}
|
}
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ pub fn gen_store_target<'ctx, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
ExprKind::Subscript { value, slice, .. } => {
|
ExprKind::Subscript { value, slice, .. } => {
|
||||||
match ctx.unifier.get_ty_immutable(value.custom.unwrap()).as_ref() {
|
match ctx.unifier.get_ty_immutable(value.custom.unwrap()).as_ref() {
|
||||||
TypeEnum::TList { .. } => {
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
let v = generator
|
let v = generator
|
||||||
.gen_expr(ctx, value)?
|
.gen_expr(ctx, value)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -243,7 +243,9 @@ pub fn gen_assign<'ctx, G: CodeGenerator>(
|
|||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let value = ListValue::from_ptr_val(value, llvm_usize, None);
|
let value = ListValue::from_ptr_val(value, llvm_usize, None);
|
||||||
let ty = match &*ctx.unifier.get_ty_immutable(target.custom.unwrap()) {
|
let ty = match &*ctx.unifier.get_ty_immutable(target.custom.unwrap()) {
|
||||||
TypeEnum::TList { ty } => *ty,
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
|
*params.iter().next().unwrap().1
|
||||||
|
}
|
||||||
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
||||||
unpack_ndarray_var_tys(&mut ctx.unifier, target.custom.unwrap()).0
|
unpack_ndarray_var_tys(&mut ctx.unifier, target.custom.unwrap()).0
|
||||||
}
|
}
|
||||||
@ -462,6 +464,16 @@ pub fn gen_for<G: CodeGenerator>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug, Clone, Copy, Hash)]
|
||||||
|
pub struct BreakContinueHooks<'ctx> {
|
||||||
|
/// The [exit block][`BasicBlock`] to branch to when `break`-ing out of a loop.
|
||||||
|
pub exit_bb: BasicBlock<'ctx>,
|
||||||
|
|
||||||
|
/// The [latch basic block][`BasicBlock`] to branch to for `continue`-ing to the next iteration
|
||||||
|
/// of the loop.
|
||||||
|
pub latch_bb: BasicBlock<'ctx>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Generates a C-style `for` construct using lambdas, similar to the following C code:
|
/// Generates a C-style `for` construct using lambdas, similar to the following C code:
|
||||||
///
|
///
|
||||||
/// ```c
|
/// ```c
|
||||||
@ -489,7 +501,8 @@ where
|
|||||||
I: Clone,
|
I: Clone,
|
||||||
InitFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<I, String>,
|
InitFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<I, String>,
|
||||||
CondFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, I) -> Result<IntValue<'ctx>, String>,
|
CondFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, I) -> Result<IntValue<'ctx>, String>,
|
||||||
BodyFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, I) -> Result<(), String>,
|
BodyFn:
|
||||||
|
FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, BreakContinueHooks, I) -> Result<(), String>,
|
||||||
UpdateFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, I) -> Result<(), String>,
|
UpdateFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, I) -> Result<(), String>,
|
||||||
{
|
{
|
||||||
let current_bb = ctx.builder.get_insert_block().unwrap();
|
let current_bb = ctx.builder.get_insert_block().unwrap();
|
||||||
@ -520,7 +533,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.builder.position_at_end(body_bb);
|
ctx.builder.position_at_end(body_bb);
|
||||||
body(generator, ctx, loop_var.clone())?;
|
let hooks = BreakContinueHooks { exit_bb: cont_bb, latch_bb: update_bb };
|
||||||
|
body(generator, ctx, hooks, loop_var.clone())?;
|
||||||
if !ctx.is_terminated() {
|
if !ctx.is_terminated() {
|
||||||
ctx.builder.build_unconditional_branch(update_bb).unwrap();
|
ctx.builder.build_unconditional_branch(update_bb).unwrap();
|
||||||
}
|
}
|
||||||
@ -562,7 +576,12 @@ pub fn gen_for_callback_incrementing<'ctx, 'a, G, BodyFn>(
|
|||||||
) -> Result<(), String>
|
) -> Result<(), String>
|
||||||
where
|
where
|
||||||
G: CodeGenerator + ?Sized,
|
G: CodeGenerator + ?Sized,
|
||||||
BodyFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, IntValue<'ctx>) -> Result<(), String>,
|
BodyFn: FnOnce(
|
||||||
|
&mut G,
|
||||||
|
&mut CodeGenContext<'ctx, 'a>,
|
||||||
|
BreakContinueHooks,
|
||||||
|
IntValue<'ctx>,
|
||||||
|
) -> Result<(), String>,
|
||||||
{
|
{
|
||||||
let init_val_t = init_val.get_type();
|
let init_val_t = init_val.get_type();
|
||||||
|
|
||||||
@ -584,10 +603,10 @@ where
|
|||||||
|
|
||||||
Ok(ctx.builder.build_int_compare(cmp_op, i, max_val, "").unwrap())
|
Ok(ctx.builder.build_int_compare(cmp_op, i, max_val, "").unwrap())
|
||||||
},
|
},
|
||||||
|generator, ctx, i_addr| {
|
|generator, ctx, hooks, i_addr| {
|
||||||
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
||||||
|
|
||||||
body(generator, ctx, i)
|
body(generator, ctx, hooks, i)
|
||||||
},
|
},
|
||||||
|_, ctx, i_addr| {
|
|_, ctx, i_addr| {
|
||||||
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
||||||
@ -698,7 +717,7 @@ where
|
|||||||
|
|
||||||
Ok(cond)
|
Ok(cond)
|
||||||
},
|
},
|
||||||
|generator, ctx, (i_addr, _)| {
|
|generator, ctx, _, (i_addr, _)| {
|
||||||
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
||||||
|
|
||||||
body_fn(generator, ctx, i)
|
body_fn(generator, ctx, i)
|
||||||
|
@ -382,13 +382,12 @@ pub trait SymbolResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static IDENTIFIER_ID: [StrRef; 12] = [
|
static IDENTIFIER_ID: [StrRef; 11] = [
|
||||||
"int32".into(),
|
"int32".into(),
|
||||||
"int64".into(),
|
"int64".into(),
|
||||||
"float".into(),
|
"float".into(),
|
||||||
"bool".into(),
|
"bool".into(),
|
||||||
"virtual".into(),
|
"virtual".into(),
|
||||||
"list".into(),
|
|
||||||
"tuple".into(),
|
"tuple".into(),
|
||||||
"str".into(),
|
"str".into(),
|
||||||
"Exception".into(),
|
"Exception".into(),
|
||||||
@ -413,13 +412,12 @@ pub fn parse_type_annotation<T>(
|
|||||||
let float_id = ids[2];
|
let float_id = ids[2];
|
||||||
let bool_id = ids[3];
|
let bool_id = ids[3];
|
||||||
let virtual_id = ids[4];
|
let virtual_id = ids[4];
|
||||||
let list_id = ids[5];
|
let tuple_id = ids[5];
|
||||||
let tuple_id = ids[6];
|
let str_id = ids[6];
|
||||||
let str_id = ids[7];
|
let exn_id = ids[7];
|
||||||
let exn_id = ids[8];
|
let uint32_id = ids[8];
|
||||||
let uint32_id = ids[9];
|
let uint64_id = ids[9];
|
||||||
let uint64_id = ids[10];
|
let literal_id = ids[10];
|
||||||
let literal_id = ids[11];
|
|
||||||
|
|
||||||
let name_handling = |id: &StrRef, loc: Location, unifier: &mut Unifier| {
|
let name_handling = |id: &StrRef, loc: Location, unifier: &mut Unifier| {
|
||||||
if *id == int32_id {
|
if *id == int32_id {
|
||||||
@ -476,9 +474,6 @@ pub fn parse_type_annotation<T>(
|
|||||||
if *id == virtual_id {
|
if *id == virtual_id {
|
||||||
let ty = parse_type_annotation(resolver, top_level_defs, unifier, primitives, slice)?;
|
let ty = parse_type_annotation(resolver, top_level_defs, unifier, primitives, slice)?;
|
||||||
Ok(unifier.add_ty(TypeEnum::TVirtual { ty }))
|
Ok(unifier.add_ty(TypeEnum::TVirtual { ty }))
|
||||||
} else if *id == list_id {
|
|
||||||
let ty = parse_type_annotation(resolver, top_level_defs, unifier, primitives, slice)?;
|
|
||||||
Ok(unifier.add_ty(TypeEnum::TList { ty }))
|
|
||||||
} else if *id == tuple_id {
|
} else if *id == tuple_id {
|
||||||
if let Tuple { elts, .. } = &slice.node {
|
if let Tuple { elts, .. } = &slice.node {
|
||||||
let ty = elts
|
let ty = elts
|
||||||
|
@ -305,6 +305,8 @@ struct BuiltinBuilder<'a> {
|
|||||||
unwrap_ty: (Type, bool),
|
unwrap_ty: (Type, bool),
|
||||||
option_tvar: TypeVar,
|
option_tvar: TypeVar,
|
||||||
|
|
||||||
|
list_tvar: TypeVar,
|
||||||
|
|
||||||
ndarray_dtype_tvar: TypeVar,
|
ndarray_dtype_tvar: TypeVar,
|
||||||
ndarray_ndims_tvar: TypeVar,
|
ndarray_ndims_tvar: TypeVar,
|
||||||
ndarray_copy_ty: (Type, bool),
|
ndarray_copy_ty: (Type, bool),
|
||||||
@ -395,7 +397,17 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
unifier.get_fresh_var_with_range(&[num_ty.ty, ndarray_num_ty], Some("T".into()), None);
|
unifier.get_fresh_var_with_range(&[num_ty.ty, ndarray_num_ty], Some("T".into()), None);
|
||||||
let num_or_ndarray_var_map = into_var_map([num_ty, num_or_ndarray_ty]);
|
let num_or_ndarray_var_map = into_var_map([num_ty, num_or_ndarray_ty]);
|
||||||
|
|
||||||
let list_int32 = unifier.add_ty(TypeEnum::TList { ty: int32 });
|
let list_tvar = if let TypeEnum::TObj { obj_id, params, .. } =
|
||||||
|
&*unifier.get_ty_immutable(primitives.list)
|
||||||
|
{
|
||||||
|
assert_eq!(*obj_id, PrimDef::List.id());
|
||||||
|
iter_type_vars(params).nth(0).unwrap()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let list_int32 = unifier
|
||||||
|
.subst(primitives.list, &into_var_map([TypeVar { id: list_tvar.id, ty: int32 }]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let ndarray_factory_fn_shape_arg_tvar = unifier.get_fresh_var(Some("Shape".into()), None);
|
let ndarray_factory_fn_shape_arg_tvar = unifier.get_fresh_var(Some("Shape".into()), None);
|
||||||
|
|
||||||
@ -407,6 +419,8 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
unwrap_ty,
|
unwrap_ty,
|
||||||
option_tvar,
|
option_tvar,
|
||||||
|
|
||||||
|
list_tvar,
|
||||||
|
|
||||||
ndarray_dtype_tvar,
|
ndarray_dtype_tvar,
|
||||||
ndarray_ndims_tvar,
|
ndarray_ndims_tvar,
|
||||||
ndarray_copy_ty,
|
ndarray_copy_ty,
|
||||||
@ -457,6 +471,8 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
| PrimDef::OptionUnwrap
|
| PrimDef::OptionUnwrap
|
||||||
| PrimDef::FunSome => self.build_option_class_related(prim),
|
| PrimDef::FunSome => self.build_option_class_related(prim),
|
||||||
|
|
||||||
|
PrimDef::List => self.build_list_class_related(prim),
|
||||||
|
|
||||||
PrimDef::NDArray | PrimDef::NDArrayCopy | PrimDef::NDArrayFill => {
|
PrimDef::NDArray | PrimDef::NDArrayCopy | PrimDef::NDArrayFill => {
|
||||||
self.build_ndarray_class_related(prim)
|
self.build_ndarray_class_related(prim)
|
||||||
}
|
}
|
||||||
@ -735,6 +751,27 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_list_class_related(&self, prim: PrimDef) -> TopLevelDef {
|
||||||
|
debug_assert_prim_is_allowed(prim, &[PrimDef::List]);
|
||||||
|
|
||||||
|
match prim {
|
||||||
|
PrimDef::List => TopLevelDef::Class {
|
||||||
|
name: prim.name().into(),
|
||||||
|
object_id: prim.id(),
|
||||||
|
type_vars: vec![self.list_tvar.ty],
|
||||||
|
fields: Vec::default(),
|
||||||
|
attributes: Vec::default(),
|
||||||
|
methods: Vec::default(),
|
||||||
|
ancestors: Vec::default(),
|
||||||
|
constructor: None,
|
||||||
|
resolver: None,
|
||||||
|
loc: None,
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Build the class `ndarray` and its associated methods.
|
/// Build the class `ndarray` and its associated methods.
|
||||||
fn build_ndarray_class_related(&self, prim: PrimDef) -> TopLevelDef {
|
fn build_ndarray_class_related(&self, prim: PrimDef) -> TopLevelDef {
|
||||||
debug_assert_prim_is_allowed(
|
debug_assert_prim_is_allowed(
|
||||||
@ -1335,7 +1372,13 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
let PrimitiveStore { uint64, int32, .. } = *self.primitives;
|
let PrimitiveStore { uint64, int32, .. } = *self.primitives;
|
||||||
|
|
||||||
let tvar = self.unifier.get_fresh_var(Some("L".into()), None);
|
let tvar = self.unifier.get_fresh_var(Some("L".into()), None);
|
||||||
let list = self.unifier.add_ty(TypeEnum::TList { ty: tvar.ty });
|
let list = self
|
||||||
|
.unifier
|
||||||
|
.subst(
|
||||||
|
self.primitives.list,
|
||||||
|
&into_var_map([TypeVar { id: self.list_tvar.id, ty: tvar.ty }]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let ndims = self.unifier.get_fresh_const_generic_var(uint64, Some("N".into()), None);
|
let ndims = self.unifier.get_fresh_const_generic_var(uint64, Some("N".into()), None);
|
||||||
let ndarray = make_ndarray_ty(self.unifier, self.primitives, Some(tvar.ty), Some(ndims.ty));
|
let ndarray = make_ndarray_ty(self.unifier, self.primitives, Some(tvar.ty), Some(ndims.ty));
|
||||||
|
|
||||||
@ -1367,7 +1410,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
Some(calculate_len_for_slice_range(generator, ctx, start, end, step).into())
|
Some(calculate_len_for_slice_range(generator, ctx, start, end, step).into())
|
||||||
} else {
|
} else {
|
||||||
match &*ctx.unifier.get_ty_immutable(arg_ty) {
|
match &*ctx.unifier.get_ty_immutable(arg_ty) {
|
||||||
TypeEnum::TList { .. } => {
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let zero = int32.const_zero();
|
let zero = int32.const_zero();
|
||||||
let len = ctx
|
let len = ctx
|
||||||
|
@ -2,7 +2,7 @@ use std::convert::TryInto;
|
|||||||
|
|
||||||
use crate::symbol_resolver::SymbolValue;
|
use crate::symbol_resolver::SymbolValue;
|
||||||
use crate::toplevel::numpy::unpack_ndarray_var_tys;
|
use crate::toplevel::numpy::unpack_ndarray_var_tys;
|
||||||
use crate::typecheck::typedef::{into_var_map, Mapping, TypeVarId, VarMap};
|
use crate::typecheck::typedef::{into_var_map, iter_type_vars, Mapping, TypeVarId, VarMap};
|
||||||
use nac3parser::ast::{Constant, Location};
|
use nac3parser::ast::{Constant, Location};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use strum_macros::EnumIter;
|
use strum_macros::EnumIter;
|
||||||
@ -12,6 +12,7 @@ use super::*;
|
|||||||
/// All primitive types and functions in nac3core.
|
/// All primitive types and functions in nac3core.
|
||||||
#[derive(Clone, Copy, Debug, EnumIter, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, EnumIter, PartialEq, Eq)]
|
||||||
pub enum PrimDef {
|
pub enum PrimDef {
|
||||||
|
// Classes
|
||||||
Int32,
|
Int32,
|
||||||
Int64,
|
Int64,
|
||||||
Float,
|
Float,
|
||||||
@ -23,10 +24,13 @@ pub enum PrimDef {
|
|||||||
UInt32,
|
UInt32,
|
||||||
UInt64,
|
UInt64,
|
||||||
Option,
|
Option,
|
||||||
|
List,
|
||||||
|
NDArray,
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
OptionIsSome,
|
OptionIsSome,
|
||||||
OptionIsNone,
|
OptionIsNone,
|
||||||
OptionUnwrap,
|
OptionUnwrap,
|
||||||
NDArray,
|
|
||||||
NDArrayCopy,
|
NDArrayCopy,
|
||||||
NDArrayFill,
|
NDArrayFill,
|
||||||
FunInt32,
|
FunInt32,
|
||||||
@ -99,6 +103,8 @@ pub enum PrimDef {
|
|||||||
FunNpLdExp,
|
FunNpLdExp,
|
||||||
FunNpHypot,
|
FunNpHypot,
|
||||||
FunNpNextAfter,
|
FunNpNextAfter,
|
||||||
|
|
||||||
|
// Top-Level Functions
|
||||||
FunSome,
|
FunSome,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +183,7 @@ impl PrimDef {
|
|||||||
PrimDef::OptionIsSome => fun("Option.is_some", Some("is_some")),
|
PrimDef::OptionIsSome => fun("Option.is_some", Some("is_some")),
|
||||||
PrimDef::OptionIsNone => fun("Option.is_none", Some("is_none")),
|
PrimDef::OptionIsNone => fun("Option.is_none", Some("is_none")),
|
||||||
PrimDef::OptionUnwrap => fun("Option.unwrap", Some("unwrap")),
|
PrimDef::OptionUnwrap => fun("Option.unwrap", Some("unwrap")),
|
||||||
|
PrimDef::List => class("list"),
|
||||||
PrimDef::NDArray => class("ndarray"),
|
PrimDef::NDArray => class("ndarray"),
|
||||||
PrimDef::NDArrayCopy => fun("ndarray.copy", Some("copy")),
|
PrimDef::NDArrayCopy => fun("ndarray.copy", Some("copy")),
|
||||||
PrimDef::NDArrayFill => fun("ndarray.fill", Some("fill")),
|
PrimDef::NDArrayFill => fun("ndarray.fill", Some("fill")),
|
||||||
@ -410,6 +417,13 @@ impl TopLevelComposer {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let list_elem_tvar = unifier.get_fresh_var(Some("list_elem".into()), None);
|
||||||
|
let list = unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: PrimDef::List.id(),
|
||||||
|
fields: Mapping::new(),
|
||||||
|
params: into_var_map([list_elem_tvar]),
|
||||||
|
});
|
||||||
|
|
||||||
let ndarray_dtype_tvar = unifier.get_fresh_var(Some("ndarray_dtype".into()), None);
|
let ndarray_dtype_tvar = unifier.get_fresh_var(Some("ndarray_dtype".into()), None);
|
||||||
let ndarray_ndims_tvar =
|
let ndarray_ndims_tvar =
|
||||||
unifier.get_fresh_const_generic_var(size_t_ty, Some("ndarray_ndims".into()), None);
|
unifier.get_fresh_const_generic_var(size_t_ty, Some("ndarray_ndims".into()), None);
|
||||||
@ -451,6 +465,7 @@ impl TopLevelComposer {
|
|||||||
str,
|
str,
|
||||||
exception,
|
exception,
|
||||||
option,
|
option,
|
||||||
|
list,
|
||||||
ndarray,
|
ndarray,
|
||||||
size_t,
|
size_t,
|
||||||
};
|
};
|
||||||
@ -888,7 +903,9 @@ pub fn arraylike_flatten_element_type(unifier: &mut Unifier, ty: Type) -> Type {
|
|||||||
unpack_ndarray_var_tys(unifier, ty).0
|
unpack_ndarray_var_tys(unifier, ty).0
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeEnum::TList { ty } => arraylike_flatten_element_type(unifier, *ty),
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
|
arraylike_flatten_element_type(unifier, iter_type_vars(params).next().unwrap().ty)
|
||||||
|
}
|
||||||
_ => ty,
|
_ => ty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -909,7 +926,9 @@ pub fn arraylike_get_ndims(unifier: &mut Unifier, ty: Type) -> u64 {
|
|||||||
u64::try_from(values[0].clone()).unwrap()
|
u64::try_from(values[0].clone()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeEnum::TList { ty } => arraylike_get_ndims(unifier, *ty) + 1,
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
|
arraylike_get_ndims(unifier, iter_type_vars(params).next().unwrap().ty) + 1
|
||||||
|
}
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ expression: res_vec
|
|||||||
[
|
[
|
||||||
"Class {\nname: \"Generic_A\",\nancestors: [\"Generic_A[V]\", \"B\"],\nfields: [\"aa\", \"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\"), (\"fun\", \"fn[[a:int32], V]\")],\ntype_vars: [\"V\"]\n}\n",
|
"Class {\nname: \"Generic_A\",\nancestors: [\"Generic_A[V]\", \"B\"],\nfields: [\"aa\", \"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\"), (\"fun\", \"fn[[a:int32], V]\")],\ntype_vars: [\"V\"]\n}\n",
|
||||||
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [TypeVarId(240)]\n}\n",
|
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [TypeVarId(245)]\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",
|
||||||
|
@ -7,7 +7,7 @@ expression: res_vec
|
|||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B[typevar229]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar229\"]\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B[typevar234]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar234\"]\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"C\",\nancestors: [\"C\", \"B[bool]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"C\",\nancestors: [\"C\", \"B[bool]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n",
|
||||||
|
@ -5,8 +5,8 @@ expression: res_vec
|
|||||||
[
|
[
|
||||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A[T, V]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A[T, V]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [TypeVarId(242)]\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [TypeVarId(247)]\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(247)]\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(252)]\n}\n",
|
||||||
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[list[float], int32]], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[list[float], int32]], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
|
@ -3,7 +3,7 @@ source: nac3core/src/toplevel/test.rs
|
|||||||
expression: res_vec
|
expression: res_vec
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A[typevar228, typevar229]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar228\", \"typevar229\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A[typevar233, typevar234]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar233\", \"typevar234\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[float, bool], b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[float, bool], b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[float, bool]], A[bool, int32]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[float, bool]], A[bool, int32]]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\")],\ntype_vars: []\n}\n",
|
||||||
|
@ -6,12 +6,12 @@ expression: res_vec
|
|||||||
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [TypeVarId(248)]\n}\n",
|
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [TypeVarId(253)]\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B\", \"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\", \"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"C\",\nancestors: [\"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"C\",\nancestors: [\"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(256)]\n}\n",
|
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(261)]\n}\n",
|
||||||
]
|
]
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::toplevel::helper::PrimDef;
|
||||||
|
use crate::typecheck::typedef::into_var_map;
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::CodeGenContext,
|
codegen::CodeGenContext,
|
||||||
symbol_resolver::{SymbolResolver, ValueEnum},
|
symbol_resolver::{SymbolResolver, ValueEnum},
|
||||||
@ -14,8 +17,6 @@ use parking_lot::Mutex;
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
struct ResolverInternal {
|
struct ResolverInternal {
|
||||||
id_to_type: Mutex<HashMap<StrRef, Type>>,
|
id_to_type: Mutex<HashMap<StrRef, Type>>,
|
||||||
id_to_def: Mutex<HashMap<StrRef, DefinitionId>>,
|
id_to_def: Mutex<HashMap<StrRef, DefinitionId>>,
|
||||||
@ -775,8 +776,15 @@ fn make_internal_resolver_with_tvar(
|
|||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
print: bool,
|
print: bool,
|
||||||
) -> Arc<ResolverInternal> {
|
) -> Arc<ResolverInternal> {
|
||||||
|
let list_elem_tvar = unifier.get_fresh_var(Some("list_elem".into()), None);
|
||||||
|
let list = unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: PrimDef::List.id(),
|
||||||
|
fields: HashMap::new(),
|
||||||
|
params: into_var_map([list_elem_tvar]),
|
||||||
|
});
|
||||||
|
|
||||||
let res: Arc<ResolverInternal> = ResolverInternal {
|
let res: Arc<ResolverInternal> = ResolverInternal {
|
||||||
id_to_def: Mutex::default(),
|
id_to_def: Mutex::new(HashMap::from([("list".into(), PrimDef::List.id())])),
|
||||||
id_to_type: tvars
|
id_to_type: tvars
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(name, range)| {
|
.map(|(name, range)| {
|
||||||
@ -790,7 +798,7 @@ fn make_internal_resolver_with_tvar(
|
|||||||
})
|
})
|
||||||
.collect::<HashMap<_, _>>()
|
.collect::<HashMap<_, _>>()
|
||||||
.into(),
|
.into(),
|
||||||
class_names: Mutex::default(),
|
class_names: Mutex::new(HashMap::from([("list".into(), list)])),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
if print {
|
if print {
|
||||||
|
@ -18,7 +18,6 @@ pub enum TypeAnnotation {
|
|||||||
TypeVar(Type),
|
TypeVar(Type),
|
||||||
/// A `Literal` allowing a subset of literals.
|
/// A `Literal` allowing a subset of literals.
|
||||||
Literal(Vec<Constant>),
|
Literal(Vec<Constant>),
|
||||||
List(Box<TypeAnnotation>),
|
|
||||||
Tuple(Vec<TypeAnnotation>),
|
Tuple(Vec<TypeAnnotation>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +50,6 @@ impl TypeAnnotation {
|
|||||||
format!("Literal({})", values.iter().map(|v| format!("{v:?}")).join(", "))
|
format!("Literal({})", values.iter().map(|v| format!("{v:?}")).join(", "))
|
||||||
}
|
}
|
||||||
Virtual(ty) => format!("virtual[{}]", ty.stringify(unifier)),
|
Virtual(ty) => format!("virtual[{}]", ty.stringify(unifier)),
|
||||||
List(ty) => format!("list[{}]", ty.stringify(unifier)),
|
|
||||||
Tuple(types) => {
|
Tuple(types) => {
|
||||||
format!(
|
format!(
|
||||||
"tuple[{}]",
|
"tuple[{}]",
|
||||||
@ -145,9 +143,7 @@ pub fn parse_ast_to_type_annotation_kinds<T, S: std::hash::BuildHasher + Clone>(
|
|||||||
slice: &ast::Expr<T>,
|
slice: &ast::Expr<T>,
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
mut locked: HashMap<DefinitionId, Vec<Type>, S>| {
|
mut locked: HashMap<DefinitionId, Vec<Type>, S>| {
|
||||||
if ["virtual".into(), "Generic".into(), "list".into(), "tuple".into(), "Option".into()]
|
if ["virtual".into(), "Generic".into(), "tuple".into(), "Option".into()].contains(id) {
|
||||||
.contains(id)
|
|
||||||
{
|
|
||||||
return Err(HashSet::from([format!(
|
return Err(HashSet::from([format!(
|
||||||
"keywords cannot be class name (at {})",
|
"keywords cannot be class name (at {})",
|
||||||
expr.location
|
expr.location
|
||||||
@ -236,23 +232,6 @@ pub fn parse_ast_to_type_annotation_kinds<T, S: std::hash::BuildHasher + Clone>(
|
|||||||
Ok(TypeAnnotation::Virtual(def.into()))
|
Ok(TypeAnnotation::Virtual(def.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// list
|
|
||||||
ast::ExprKind::Subscript { value, slice, .. }
|
|
||||||
if {
|
|
||||||
matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"list".into())
|
|
||||||
} =>
|
|
||||||
{
|
|
||||||
let def_ann = parse_ast_to_type_annotation_kinds(
|
|
||||||
resolver,
|
|
||||||
top_level_defs,
|
|
||||||
unifier,
|
|
||||||
primitives,
|
|
||||||
slice.as_ref(),
|
|
||||||
locked,
|
|
||||||
)?;
|
|
||||||
Ok(TypeAnnotation::List(def_ann.into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// option
|
// option
|
||||||
ast::ExprKind::Subscript { value, slice, .. }
|
ast::ExprKind::Subscript { value, slice, .. }
|
||||||
if {
|
if {
|
||||||
@ -516,15 +495,6 @@ pub fn get_type_from_type_annotation_kinds(
|
|||||||
)?;
|
)?;
|
||||||
Ok(unifier.add_ty(TypeEnum::TVirtual { ty }))
|
Ok(unifier.add_ty(TypeEnum::TVirtual { ty }))
|
||||||
}
|
}
|
||||||
TypeAnnotation::List(ty) => {
|
|
||||||
let ty = get_type_from_type_annotation_kinds(
|
|
||||||
top_level_defs,
|
|
||||||
unifier,
|
|
||||||
ty.as_ref(),
|
|
||||||
subst_list,
|
|
||||||
)?;
|
|
||||||
Ok(unifier.add_ty(TypeEnum::TList { ty }))
|
|
||||||
}
|
|
||||||
TypeAnnotation::Tuple(tys) => {
|
TypeAnnotation::Tuple(tys) => {
|
||||||
let tys = tys
|
let tys = tys
|
||||||
.iter()
|
.iter()
|
||||||
@ -565,7 +535,7 @@ pub fn get_type_var_contained_in_type_annotation(ann: &TypeAnnotation) -> Vec<Ty
|
|||||||
let mut result: Vec<TypeAnnotation> = Vec::new();
|
let mut result: Vec<TypeAnnotation> = Vec::new();
|
||||||
match ann {
|
match ann {
|
||||||
TypeAnnotation::TypeVar(..) => result.push(ann.clone()),
|
TypeAnnotation::TypeVar(..) => result.push(ann.clone()),
|
||||||
TypeAnnotation::Virtual(ann) | TypeAnnotation::List(ann) => {
|
TypeAnnotation::Virtual(ann) => {
|
||||||
result.extend(get_type_var_contained_in_type_annotation(ann.as_ref()));
|
result.extend(get_type_var_contained_in_type_annotation(ann.as_ref()));
|
||||||
}
|
}
|
||||||
TypeAnnotation::CustomClass { params, .. } => {
|
TypeAnnotation::CustomClass { params, .. } => {
|
||||||
@ -606,8 +576,7 @@ pub fn check_overload_type_annotation_compatible(
|
|||||||
|
|
||||||
a == b
|
a == b
|
||||||
}
|
}
|
||||||
(TypeAnnotation::Virtual(a), TypeAnnotation::Virtual(b))
|
(TypeAnnotation::Virtual(a), TypeAnnotation::Virtual(b)) => {
|
||||||
| (TypeAnnotation::List(a), TypeAnnotation::List(b)) => {
|
|
||||||
check_overload_type_annotation_compatible(a.as_ref(), b.as_ref(), unifier)
|
check_overload_type_annotation_compatible(a.as_ref(), b.as_ref(), unifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::typecheck::typedef::TypeEnum;
|
use crate::toplevel::helper::PrimDef;
|
||||||
|
|
||||||
use super::type_inferencer::Inferencer;
|
use super::type_inferencer::Inferencer;
|
||||||
use super::typedef::Type;
|
use super::typedef::{Type, TypeEnum};
|
||||||
use nac3parser::ast::{
|
use nac3parser::ast::{
|
||||||
self, Constant, Expr, ExprKind,
|
self, Constant, Expr, ExprKind,
|
||||||
Operator::{LShift, RShift},
|
Operator::{LShift, RShift},
|
||||||
@ -69,6 +69,7 @@ impl<'a> Inferencer<'a> {
|
|||||||
// there are some cases where the custom field is None
|
// there are some cases where the custom field is None
|
||||||
if let Some(ty) = &expr.custom {
|
if let Some(ty) = &expr.custom {
|
||||||
if !matches!(&expr.node, ExprKind::Constant { value: Constant::Ellipsis, .. })
|
if !matches!(&expr.node, ExprKind::Constant { value: Constant::Ellipsis, .. })
|
||||||
|
&& !ty.obj_id(self.unifier).is_some_and(|id| id == PrimDef::List.id())
|
||||||
&& !self.unifier.is_concrete(*ty, &self.function_data.bound_variables)
|
&& !self.unifier.is_concrete(*ty, &self.function_data.bound_variables)
|
||||||
{
|
{
|
||||||
return Err(HashSet::from([format!(
|
return Err(HashSet::from([format!(
|
||||||
|
@ -429,12 +429,27 @@ pub fn typeof_binop(
|
|||||||
lhs: Type,
|
lhs: Type,
|
||||||
rhs: Type,
|
rhs: Type,
|
||||||
) -> Result<Option<Type>, String> {
|
) -> Result<Option<Type>, String> {
|
||||||
|
let is_left_list = lhs.obj_id(unifier).is_some_and(|id| id == PrimDef::List.id());
|
||||||
|
let is_right_list = rhs.obj_id(unifier).is_some_and(|id| id == PrimDef::List.id());
|
||||||
let is_left_ndarray = lhs.obj_id(unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
let is_left_ndarray = lhs.obj_id(unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
||||||
let is_right_ndarray = rhs.obj_id(unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
let is_right_ndarray = rhs.obj_id(unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
||||||
|
|
||||||
Ok(Some(match op {
|
Ok(Some(match op {
|
||||||
Operator::Add | Operator::Sub | Operator::Mult | Operator::Mod | Operator::FloorDiv => {
|
Operator::Add | Operator::Sub | Operator::Mult | Operator::Mod | Operator::FloorDiv => {
|
||||||
if is_left_ndarray || is_right_ndarray {
|
if is_left_list || is_right_list {
|
||||||
|
if ![Operator::Add, Operator::Mult].contains(&op) {
|
||||||
|
return Err(format!(
|
||||||
|
"Binary operator {} not supported for list",
|
||||||
|
binop_name(op)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_left_list {
|
||||||
|
lhs
|
||||||
|
} else {
|
||||||
|
rhs
|
||||||
|
}
|
||||||
|
} else if is_left_ndarray || is_right_ndarray {
|
||||||
typeof_ndarray_broadcast(unifier, primitives, lhs, rhs)?
|
typeof_ndarray_broadcast(unifier, primitives, lhs, rhs)?
|
||||||
} else if unifier.unioned(lhs, rhs) {
|
} else if unifier.unioned(lhs, rhs) {
|
||||||
lhs
|
lhs
|
||||||
@ -604,6 +619,7 @@ pub fn set_primitives_magic_methods(store: &PrimitiveStore, unifier: &mut Unifie
|
|||||||
bool: bool_t,
|
bool: bool_t,
|
||||||
uint32: uint32_t,
|
uint32: uint32_t,
|
||||||
uint64: uint64_t,
|
uint64: uint64_t,
|
||||||
|
list: list_t,
|
||||||
ndarray: ndarray_t,
|
ndarray: ndarray_t,
|
||||||
..
|
..
|
||||||
} = *store;
|
} = *store;
|
||||||
@ -648,6 +664,11 @@ pub fn set_primitives_magic_methods(store: &PrimitiveStore, unifier: &mut Unifie
|
|||||||
impl_sign(unifier, store, bool_t, Some(int32_t));
|
impl_sign(unifier, store, bool_t, Some(int32_t));
|
||||||
impl_eq(unifier, store, bool_t, &[bool_t, ndarray_bool_t], None);
|
impl_eq(unifier, store, bool_t, &[bool_t, ndarray_bool_t], None);
|
||||||
|
|
||||||
|
/* list ======== */
|
||||||
|
impl_binop(unifier, store, list_t, &[list_t], Some(list_t), &[Operator::Add]);
|
||||||
|
impl_binop(unifier, store, list_t, &[int32_t, int64_t], Some(list_t), &[Operator::Mult]);
|
||||||
|
impl_cmpop(unifier, store, list_t, &[list_t], &[Cmpop::Eq, Cmpop::NotEq], Some(bool_t));
|
||||||
|
|
||||||
/* ndarray ===== */
|
/* ndarray ===== */
|
||||||
let ndarray_usized_ndims_tvar =
|
let ndarray_usized_ndims_tvar =
|
||||||
unifier.get_fresh_const_generic_var(size_t, Some("ndarray_ndims".into()), None);
|
unifier.get_fresh_const_generic_var(size_t, Some("ndarray_ndims".into()), None);
|
||||||
|
@ -4,15 +4,20 @@ use std::iter::once;
|
|||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
use std::{cell::RefCell, sync::Arc};
|
use std::{cell::RefCell, sync::Arc};
|
||||||
|
|
||||||
use super::typedef::{Call, FunSignature, FuncArg, RecordField, Type, TypeEnum, Unifier, VarMap};
|
use super::{
|
||||||
use super::{magic_methods::*, type_error::TypeError, typedef::CallId};
|
magic_methods::*,
|
||||||
use crate::toplevel::TopLevelDef;
|
type_error::TypeError,
|
||||||
|
typedef::{
|
||||||
|
into_var_map, iter_type_vars, Call, CallId, FunSignature, FuncArg, RecordField, Type,
|
||||||
|
TypeEnum, TypeVar, Unifier, VarMap,
|
||||||
|
},
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
symbol_resolver::{SymbolResolver, SymbolValue},
|
symbol_resolver::{SymbolResolver, SymbolValue},
|
||||||
toplevel::{
|
toplevel::{
|
||||||
helper::{arraylike_flatten_element_type, arraylike_get_ndims, PrimDef},
|
helper::{arraylike_flatten_element_type, arraylike_get_ndims, PrimDef},
|
||||||
numpy::{make_ndarray_ty, unpack_ndarray_var_tys},
|
numpy::{make_ndarray_ty, unpack_ndarray_var_tys},
|
||||||
TopLevelContext,
|
TopLevelContext, TopLevelDef,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use itertools::{izip, Itertools};
|
use itertools::{izip, Itertools};
|
||||||
@ -50,6 +55,7 @@ pub struct PrimitiveStore {
|
|||||||
pub str: Type,
|
pub str: Type,
|
||||||
pub exception: Type,
|
pub exception: Type,
|
||||||
pub option: Type,
|
pub option: Type,
|
||||||
|
pub list: Type,
|
||||||
pub ndarray: Type,
|
pub ndarray: Type,
|
||||||
pub size_t: u32,
|
pub size_t: u32,
|
||||||
}
|
}
|
||||||
@ -242,8 +248,17 @@ impl<'a> Fold<()> for Inferencer<'a> {
|
|||||||
self.unify(self.primitives.int32, target.custom.unwrap(), &target.location)?;
|
self.unify(self.primitives.int32, target.custom.unwrap(), &target.location)?;
|
||||||
} else {
|
} else {
|
||||||
let list_like_ty = match &*self.unifier.get_ty(iter.custom.unwrap()) {
|
let list_like_ty = match &*self.unifier.get_ty(iter.custom.unwrap()) {
|
||||||
TypeEnum::TList { .. } => {
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
self.unifier.add_ty(TypeEnum::TList { ty: target.custom.unwrap() })
|
let list_tvar = iter_type_vars(params).nth(0).unwrap();
|
||||||
|
self.unifier
|
||||||
|
.subst(
|
||||||
|
self.primitives.list,
|
||||||
|
&into_var_map([TypeVar {
|
||||||
|
id: list_tvar.id,
|
||||||
|
ty: target.custom.unwrap(),
|
||||||
|
}]),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
||||||
todo!()
|
todo!()
|
||||||
@ -764,6 +779,16 @@ impl<'a> Inferencer<'a> {
|
|||||||
generators[0].target.location,
|
generators[0].target.location,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let list_tvar = if let TypeEnum::TObj { obj_id, params, .. } =
|
||||||
|
&*self.unifier.get_ty_immutable(self.primitives.list)
|
||||||
|
{
|
||||||
|
assert_eq!(*obj_id, PrimDef::List.id());
|
||||||
|
iter_type_vars(params).nth(0).unwrap()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
let variable_mapping = self.variable_mapping.clone();
|
let variable_mapping = self.variable_mapping.clone();
|
||||||
let defined_identifiers = self.defined_identifiers.clone();
|
let defined_identifiers = self.defined_identifiers.clone();
|
||||||
let mut new_context = Inferencer {
|
let mut new_context = Inferencer {
|
||||||
@ -792,7 +817,13 @@ impl<'a> Inferencer<'a> {
|
|||||||
&target.location,
|
&target.location,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
let list = new_context.unifier.add_ty(TypeEnum::TList { ty: target.custom.unwrap() });
|
let list = new_context
|
||||||
|
.unifier
|
||||||
|
.subst(
|
||||||
|
self.primitives.list,
|
||||||
|
&into_var_map([TypeVar { id: list_tvar.id, ty: target.custom.unwrap() }]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
new_context.unify(iter.custom.unwrap(), list, &iter.location)?;
|
new_context.unify(iter.custom.unwrap(), list, &iter.location)?;
|
||||||
}
|
}
|
||||||
let ifs: Vec<_> = generator
|
let ifs: Vec<_> = generator
|
||||||
@ -809,9 +840,16 @@ impl<'a> Inferencer<'a> {
|
|||||||
new_context.unify(v.custom.unwrap(), new_context.primitives.bool, &v.location)?;
|
new_context.unify(v.custom.unwrap(), new_context.primitives.bool, &v.location)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let custom = new_context
|
||||||
|
.unifier
|
||||||
|
.subst(
|
||||||
|
self.primitives.list,
|
||||||
|
&into_var_map([TypeVar { id: list_tvar.id, ty: elt.custom.unwrap() }]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
Ok(Located {
|
Ok(Located {
|
||||||
location,
|
location,
|
||||||
custom: Some(new_context.unifier.add_ty(TypeEnum::TList { ty: elt.custom.unwrap() })),
|
custom: Some(custom),
|
||||||
node: ExprKind::ListComp {
|
node: ExprKind::ListComp {
|
||||||
elt: Box::new(elt),
|
elt: Box::new(elt),
|
||||||
generators: vec![Comprehension {
|
generators: vec![Comprehension {
|
||||||
@ -893,11 +931,13 @@ impl<'a> Inferencer<'a> {
|
|||||||
// Here, we also take the opportunity to deduce `ndims` statically.
|
// Here, we also take the opportunity to deduce `ndims` statically.
|
||||||
let shape_ty_enum = &*self.unifier.get_ty(shape_ty);
|
let shape_ty_enum = &*self.unifier.get_ty(shape_ty);
|
||||||
let ndims = match shape_ty_enum {
|
let ndims = match shape_ty_enum {
|
||||||
TypeEnum::TList { ty } => {
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
// Handle 1. A list of int32s
|
// Handle 1. A list of int32s
|
||||||
|
|
||||||
|
let ty = iter_type_vars(params).nth(0).unwrap().ty;
|
||||||
|
|
||||||
// Typecheck
|
// Typecheck
|
||||||
self.unifier.unify(*ty, self.primitives.int32).map_err(|err| {
|
self.unifier.unify(ty, self.primitives.int32).map_err(|err| {
|
||||||
HashSet::from([err
|
HashSet::from([err
|
||||||
.at(Some(shape.location))
|
.at(Some(shape.location))
|
||||||
.to_display(self.unifier)
|
.to_display(self.unifier)
|
||||||
@ -1563,7 +1603,19 @@ impl<'a> Inferencer<'a> {
|
|||||||
for t in elts {
|
for t in elts {
|
||||||
self.unify(ty, t.custom.unwrap(), &t.location)?;
|
self.unify(ty, t.custom.unwrap(), &t.location)?;
|
||||||
}
|
}
|
||||||
Ok(self.unifier.add_ty(TypeEnum::TList { ty }))
|
let list_tvar = if let TypeEnum::TObj { obj_id, params, .. } =
|
||||||
|
&*self.unifier.get_ty_immutable(self.primitives.list)
|
||||||
|
{
|
||||||
|
assert_eq!(*obj_id, PrimDef::List.id());
|
||||||
|
iter_type_vars(params).nth(0).unwrap()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let list = self
|
||||||
|
.unifier
|
||||||
|
.subst(self.primitives.list, &into_var_map([TypeVar { id: list_tvar.id, ty }]))
|
||||||
|
.unwrap();
|
||||||
|
Ok(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
@ -1885,7 +1937,16 @@ impl<'a> Inferencer<'a> {
|
|||||||
self.constrain(v.custom.unwrap(), self.primitives.int32, &v.location)?;
|
self.constrain(v.custom.unwrap(), self.primitives.int32, &v.location)?;
|
||||||
}
|
}
|
||||||
let list_like_ty = match &*self.unifier.get_ty(value.custom.unwrap()) {
|
let list_like_ty = match &*self.unifier.get_ty(value.custom.unwrap()) {
|
||||||
TypeEnum::TList { .. } => self.unifier.add_ty(TypeEnum::TList { ty }),
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
|
let list_tvar = iter_type_vars(params).nth(0).unwrap();
|
||||||
|
self.unifier
|
||||||
|
.subst(
|
||||||
|
self.primitives.list,
|
||||||
|
&into_var_map([TypeVar { id: list_tvar.id, ty }]),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
||||||
let (_, ndims) =
|
let (_, ndims) =
|
||||||
unpack_ndarray_var_tys(self.unifier, value.custom.unwrap());
|
unpack_ndarray_var_tys(self.unifier, value.custom.unwrap());
|
||||||
@ -1960,13 +2021,20 @@ impl<'a> Inferencer<'a> {
|
|||||||
|
|
||||||
// the index is not a constant, so value can only be a list-like structure
|
// the index is not a constant, so value can only be a list-like structure
|
||||||
match &*self.unifier.get_ty(value.custom.unwrap()) {
|
match &*self.unifier.get_ty(value.custom.unwrap()) {
|
||||||
TypeEnum::TList { .. } => {
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
self.constrain(
|
self.constrain(
|
||||||
slice.custom.unwrap(),
|
slice.custom.unwrap(),
|
||||||
self.primitives.int32,
|
self.primitives.int32,
|
||||||
&slice.location,
|
&slice.location,
|
||||||
)?;
|
)?;
|
||||||
let list = self.unifier.add_ty(TypeEnum::TList { ty });
|
let list_tvar = iter_type_vars(params).nth(0).unwrap();
|
||||||
|
let list = self
|
||||||
|
.unifier
|
||||||
|
.subst(
|
||||||
|
self.primitives.list,
|
||||||
|
&into_var_map([TypeVar { id: list_tvar.id, ty }]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
self.constrain(value.custom.unwrap(), list, &value.location)?;
|
self.constrain(value.custom.unwrap(), list, &value.location)?;
|
||||||
Ok(ty)
|
Ok(ty)
|
||||||
}
|
}
|
||||||
|
@ -139,6 +139,12 @@ impl TestEnvironment {
|
|||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
params: VarMap::new(),
|
params: VarMap::new(),
|
||||||
});
|
});
|
||||||
|
let list_elem_tvar = unifier.get_fresh_var(Some("list_elem".into()), None);
|
||||||
|
let list = unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: PrimDef::List.id(),
|
||||||
|
fields: HashMap::new(),
|
||||||
|
params: into_var_map([list_elem_tvar]),
|
||||||
|
});
|
||||||
let ndarray_dtype_tvar = unifier.get_fresh_var(Some("ndarray_dtype".into()), None);
|
let ndarray_dtype_tvar = unifier.get_fresh_var(Some("ndarray_dtype".into()), None);
|
||||||
let ndarray_ndims_tvar =
|
let ndarray_ndims_tvar =
|
||||||
unifier.get_fresh_const_generic_var(uint64, Some("ndarray_ndims".into()), None);
|
unifier.get_fresh_const_generic_var(uint64, Some("ndarray_ndims".into()), None);
|
||||||
@ -159,6 +165,7 @@ impl TestEnvironment {
|
|||||||
uint32,
|
uint32,
|
||||||
uint64,
|
uint64,
|
||||||
option,
|
option,
|
||||||
|
list,
|
||||||
ndarray,
|
ndarray,
|
||||||
size_t: 64,
|
size_t: 64,
|
||||||
};
|
};
|
||||||
@ -273,15 +280,35 @@ impl TestEnvironment {
|
|||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
params: VarMap::new(),
|
params: VarMap::new(),
|
||||||
});
|
});
|
||||||
|
let list_elem_tvar = unifier.get_fresh_var(Some("list_elem".into()), None);
|
||||||
|
let list = unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: PrimDef::List.id(),
|
||||||
|
fields: HashMap::new(),
|
||||||
|
params: into_var_map([list_elem_tvar]),
|
||||||
|
});
|
||||||
let ndarray = unifier.add_ty(TypeEnum::TObj {
|
let ndarray = unifier.add_ty(TypeEnum::TObj {
|
||||||
obj_id: PrimDef::NDArray.id(),
|
obj_id: PrimDef::NDArray.id(),
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
params: VarMap::new(),
|
params: VarMap::new(),
|
||||||
});
|
});
|
||||||
identifier_mapping.insert("None".into(), none);
|
identifier_mapping.insert("None".into(), none);
|
||||||
for (i, name) in ["int32", "int64", "float", "bool", "none", "range", "str", "Exception"]
|
for (i, name) in [
|
||||||
.iter()
|
"int32",
|
||||||
.enumerate()
|
"int64",
|
||||||
|
"float",
|
||||||
|
"bool",
|
||||||
|
"none",
|
||||||
|
"range",
|
||||||
|
"str",
|
||||||
|
"Exception",
|
||||||
|
"uint32",
|
||||||
|
"uint64",
|
||||||
|
"Option",
|
||||||
|
"list",
|
||||||
|
"ndarray",
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
{
|
{
|
||||||
top_level_defs.push(
|
top_level_defs.push(
|
||||||
RwLock::new(TopLevelDef::Class {
|
RwLock::new(TopLevelDef::Class {
|
||||||
@ -299,7 +326,7 @@ impl TestEnvironment {
|
|||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let defs = 7;
|
let defs = 12;
|
||||||
|
|
||||||
let primitives = PrimitiveStore {
|
let primitives = PrimitiveStore {
|
||||||
int32,
|
int32,
|
||||||
@ -313,6 +340,7 @@ impl TestEnvironment {
|
|||||||
uint32,
|
uint32,
|
||||||
uint64,
|
uint64,
|
||||||
option,
|
option,
|
||||||
|
list,
|
||||||
ndarray,
|
ndarray,
|
||||||
size_t: 64,
|
size_t: 64,
|
||||||
};
|
};
|
||||||
@ -424,6 +452,11 @@ impl TestEnvironment {
|
|||||||
"range".into(),
|
"range".into(),
|
||||||
"str".into(),
|
"str".into(),
|
||||||
"exception".into(),
|
"exception".into(),
|
||||||
|
"uint32".into(),
|
||||||
|
"uint64".into(),
|
||||||
|
"option".into(),
|
||||||
|
"list".into(),
|
||||||
|
"ndarray".into(),
|
||||||
"Foo".into(),
|
"Foo".into(),
|
||||||
"Bar".into(),
|
"Bar".into(),
|
||||||
"Bar2".into(),
|
"Bar2".into(),
|
||||||
|
@ -13,7 +13,7 @@ use nac3parser::ast::{Location, StrRef};
|
|||||||
use super::type_error::{TypeError, TypeErrorKind};
|
use super::type_error::{TypeError, TypeErrorKind};
|
||||||
use super::unification_table::{UnificationKey, UnificationTable};
|
use super::unification_table::{UnificationKey, UnificationTable};
|
||||||
use crate::symbol_resolver::SymbolValue;
|
use crate::symbol_resolver::SymbolValue;
|
||||||
use crate::toplevel::{DefinitionId, TopLevelContext, TopLevelDef};
|
use crate::toplevel::{helper::PrimDef, DefinitionId, TopLevelContext, TopLevelDef};
|
||||||
use crate::typecheck::type_inferencer::PrimitiveStore;
|
use crate::typecheck::type_inferencer::PrimitiveStore;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -207,12 +207,6 @@ pub enum TypeEnum {
|
|||||||
ty: Vec<Type>,
|
ty: Vec<Type>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// A list type.
|
|
||||||
TList {
|
|
||||||
/// The type of elements present in this list.
|
|
||||||
ty: Type,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// An object type.
|
/// An object type.
|
||||||
TObj {
|
TObj {
|
||||||
/// The [`DefinitionId`] of this object type.
|
/// The [`DefinitionId`] of this object type.
|
||||||
@ -246,7 +240,6 @@ impl TypeEnum {
|
|||||||
TypeEnum::TVar { .. } => "TVar",
|
TypeEnum::TVar { .. } => "TVar",
|
||||||
TypeEnum::TLiteral { .. } => "TConstant",
|
TypeEnum::TLiteral { .. } => "TConstant",
|
||||||
TypeEnum::TTuple { .. } => "TTuple",
|
TypeEnum::TTuple { .. } => "TTuple",
|
||||||
TypeEnum::TList { .. } => "TList",
|
|
||||||
TypeEnum::TObj { .. } => "TObj",
|
TypeEnum::TObj { .. } => "TObj",
|
||||||
TypeEnum::TVirtual { .. } => "TVirtual",
|
TypeEnum::TVirtual { .. } => "TVirtual",
|
||||||
TypeEnum::TCall { .. } => "TCall",
|
TypeEnum::TCall { .. } => "TCall",
|
||||||
@ -482,9 +475,27 @@ impl Unifier {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeEnum::TList { ty } => self
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
||||||
.get_instantiations(*ty)
|
let tv = iter_type_vars(params).nth(0).unwrap();
|
||||||
.map(|ty| ty.iter().map(|&ty| self.add_ty(TypeEnum::TList { ty })).collect_vec()),
|
|
||||||
|
let tv_id = if let TypeEnum::TVar { id, .. } =
|
||||||
|
self.unification_table.probe_value(tv.ty).as_ref()
|
||||||
|
{
|
||||||
|
*id
|
||||||
|
} else {
|
||||||
|
tv.id
|
||||||
|
};
|
||||||
|
|
||||||
|
self.get_instantiations(tv.ty).map(|ty_insts| {
|
||||||
|
ty_insts
|
||||||
|
.iter()
|
||||||
|
.map(|&ty_inst| {
|
||||||
|
self.subst(ty, &into_var_map([TypeVar { id: tv_id, ty: ty_inst }]))
|
||||||
|
.unwrap_or(ty)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
TypeEnum::TVirtual { ty } => self.get_instantiations(*ty).map(|ty| {
|
TypeEnum::TVirtual { ty } => self.get_instantiations(*ty).map(|ty| {
|
||||||
ty.iter().map(|&ty| self.add_ty(TypeEnum::TVirtual { ty })).collect_vec()
|
ty.iter().map(|&ty| self.add_ty(TypeEnum::TVirtual { ty })).collect_vec()
|
||||||
}),
|
}),
|
||||||
@ -541,9 +552,7 @@ impl Unifier {
|
|||||||
|
|
||||||
TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)),
|
TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)),
|
||||||
TCall { .. } => false,
|
TCall { .. } => false,
|
||||||
TList { ty }
|
TVirtual { ty } => self.is_concrete(*ty, allowed_typevars),
|
||||||
| TVirtual { ty } => self.is_concrete(*ty, allowed_typevars),
|
|
||||||
|
|
||||||
TTuple { ty } => ty.iter().all(|ty| self.is_concrete(*ty, allowed_typevars)),
|
TTuple { ty } => ty.iter().all(|ty| self.is_concrete(*ty, allowed_typevars)),
|
||||||
TObj { params: vars, .. } => {
|
TObj { params: vars, .. } => {
|
||||||
vars.values().all(|ty| self.is_concrete(*ty, allowed_typevars))
|
vars.values().all(|ty| self.is_concrete(*ty, allowed_typevars))
|
||||||
@ -885,22 +894,6 @@ impl Unifier {
|
|||||||
self.unify_impl(x, b, false)?;
|
self.unify_impl(x, b, false)?;
|
||||||
self.set_a_to_b(a, x);
|
self.set_a_to_b(a, x);
|
||||||
}
|
}
|
||||||
(TVar { fields: Some(fields), range, is_const_generic: false, .. }, TList { ty }) => {
|
|
||||||
for (k, v) in fields {
|
|
||||||
match *k {
|
|
||||||
RecordKey::Int(_) => {
|
|
||||||
self.unify_impl(v.ty, *ty, false).map_err(|e| e.at(v.loc))?;
|
|
||||||
}
|
|
||||||
RecordKey::Str(_) => {
|
|
||||||
return Err(TypeError::new(TypeErrorKind::NoSuchField(*k, b), v.loc))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let x = self.check_var_compatibility(b, range)?.unwrap_or(b);
|
|
||||||
self.unify_impl(x, b, false)?;
|
|
||||||
self.set_a_to_b(a, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
(
|
||||||
TVar { id: id1, range: ty1, is_const_generic: true, .. },
|
TVar { id: id1, range: ty1, is_const_generic: true, .. },
|
||||||
TVar { id: id2, range: ty2, .. },
|
TVar { id: id2, range: ty2, .. },
|
||||||
@ -979,13 +972,7 @@ impl Unifier {
|
|||||||
}
|
}
|
||||||
self.set_a_to_b(a, b);
|
self.set_a_to_b(a, b);
|
||||||
}
|
}
|
||||||
(TList { ty: ty1 }, TList { ty: ty2 }) => {
|
(TVar { fields: Some(map), range, .. }, TObj { obj_id, fields, params }) => {
|
||||||
if self.unify_impl(*ty1, *ty2, false).is_err() {
|
|
||||||
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
|
|
||||||
}
|
|
||||||
self.set_a_to_b(a, b);
|
|
||||||
}
|
|
||||||
(TVar { fields: Some(map), range, .. }, TObj { fields, .. }) => {
|
|
||||||
for (k, field) in map {
|
for (k, field) in map {
|
||||||
match *k {
|
match *k {
|
||||||
RecordKey::Str(s) => {
|
RecordKey::Str(s) => {
|
||||||
@ -1004,10 +991,18 @@ impl Unifier {
|
|||||||
self.unify_impl(field.ty, ty, false).map_err(|v| v.at(field.loc))?;
|
self.unify_impl(field.ty, ty, false).map_err(|v| v.at(field.loc))?;
|
||||||
}
|
}
|
||||||
RecordKey::Int(_) => {
|
RecordKey::Int(_) => {
|
||||||
return Err(TypeError::new(
|
// Allow expressions such as list[0]
|
||||||
TypeErrorKind::NoSuchField(*k, b),
|
if *obj_id == PrimDef::List.id() {
|
||||||
field.loc,
|
let ty = iter_type_vars(params).nth(0).unwrap().ty;
|
||||||
))
|
|
||||||
|
self.unify_impl(field.ty, ty, false)
|
||||||
|
.map_err(|e| e.at(field.loc))?;
|
||||||
|
} else {
|
||||||
|
return Err(TypeError::new(
|
||||||
|
TypeErrorKind::NoSuchField(*k, b),
|
||||||
|
field.loc,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1222,9 +1217,6 @@ impl Unifier {
|
|||||||
ty.iter().map(|v| self.internal_stringify(*v, obj_to_name, var_to_name, notes));
|
ty.iter().map(|v| self.internal_stringify(*v, obj_to_name, var_to_name, notes));
|
||||||
format!("tuple[{}]", fields.join(", "))
|
format!("tuple[{}]", fields.join(", "))
|
||||||
}
|
}
|
||||||
TypeEnum::TList { ty } => {
|
|
||||||
format!("list[{}]", self.internal_stringify(*ty, obj_to_name, var_to_name, notes))
|
|
||||||
}
|
|
||||||
TypeEnum::TVirtual { ty } => {
|
TypeEnum::TVirtual { ty } => {
|
||||||
format!(
|
format!(
|
||||||
"virtual[{}]",
|
"virtual[{}]",
|
||||||
@ -1357,9 +1349,6 @@ impl Unifier {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeEnum::TList { ty } => {
|
|
||||||
self.subst_impl(*ty, mapping, cache).map(|t| self.add_ty(TypeEnum::TList { ty: t }))
|
|
||||||
}
|
|
||||||
TypeEnum::TVirtual { ty } => self
|
TypeEnum::TVirtual { ty } => self
|
||||||
.subst_impl(*ty, mapping, cache)
|
.subst_impl(*ty, mapping, cache)
|
||||||
.map(|t| self.add_ty(TypeEnum::TVirtual { ty: t })),
|
.map(|t| self.add_ty(TypeEnum::TVirtual { ty: t })),
|
||||||
@ -1370,6 +1359,7 @@ impl Unifier {
|
|||||||
// This is also used to prevent infinite substitution...
|
// This is also used to prevent infinite substitution...
|
||||||
let need_subst = params.values().any(|v| {
|
let need_subst = params.values().any(|v| {
|
||||||
let ty = self.unification_table.probe_value(*v);
|
let ty = self.unification_table.probe_value(*v);
|
||||||
|
// TODO(Derppening): #444
|
||||||
if let TypeEnum::TVar { id, .. } = ty.as_ref() {
|
if let TypeEnum::TVar { id, .. } = ty.as_ref() {
|
||||||
mapping.contains_key(id)
|
mapping.contains_key(id)
|
||||||
} else {
|
} else {
|
||||||
@ -1526,8 +1516,22 @@ impl Unifier {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(TList { ty: ty1 }, TList { ty: ty2 }) => {
|
// TODO(Derppening): #444
|
||||||
Ok(self.get_intersection(*ty1, *ty2)?.map(|ty| self.add_ty(TList { ty })))
|
(
|
||||||
|
TObj { obj_id: id1, fields, params: params1 },
|
||||||
|
TObj { obj_id: id2, params: params2, .. },
|
||||||
|
) if *id1 == PrimDef::List.id() && *id2 == PrimDef::List.id() => {
|
||||||
|
let tv_id = iter_type_vars(params1).nth(0).unwrap().id;
|
||||||
|
let ty1 = iter_type_vars(params1).nth(0).unwrap().ty;
|
||||||
|
let ty2 = iter_type_vars(params2).nth(0).unwrap().ty;
|
||||||
|
|
||||||
|
Ok(self.get_intersection(ty1, ty2)?.map(|ty| {
|
||||||
|
self.add_ty(TObj {
|
||||||
|
obj_id: *id1,
|
||||||
|
fields: fields.clone(),
|
||||||
|
params: into_var_map([TypeVar { id: tv_id, ty }]),
|
||||||
|
})
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
(TVirtual { ty: ty1 }, TVirtual { ty: ty2 }) => {
|
(TVirtual { ty: ty1 }, TVirtual { ty: ty2 }) => {
|
||||||
Ok(self.get_intersection(*ty1, *ty2)?.map(|ty| self.add_ty(TVirtual { ty })))
|
Ok(self.get_intersection(*ty1, *ty2)?.map(|ty| self.add_ty(TVirtual { ty })))
|
||||||
|
@ -32,10 +32,7 @@ impl Unifier {
|
|||||||
ty1.len() == ty2.len()
|
ty1.len() == ty2.len()
|
||||||
&& ty1.iter().zip(ty2.iter()).all(|(t1, t2)| self.eq(*t1, *t2))
|
&& ty1.iter().zip(ty2.iter()).all(|(t1, t2)| self.eq(*t1, *t2))
|
||||||
}
|
}
|
||||||
(TypeEnum::TList { ty: ty1 }, TypeEnum::TList { ty: ty2 })
|
(TypeEnum::TVirtual { ty: ty1 }, TypeEnum::TVirtual { ty: ty2 }) => self.eq(*ty1, *ty2),
|
||||||
| (TypeEnum::TVirtual { ty: ty1 }, TypeEnum::TVirtual { ty: ty2 }) => {
|
|
||||||
self.eq(*ty1, *ty2)
|
|
||||||
}
|
|
||||||
(
|
(
|
||||||
TypeEnum::TObj { obj_id: id1, params: params1, .. },
|
TypeEnum::TObj { obj_id: id1, params: params1, .. },
|
||||||
TypeEnum::TObj { obj_id: id2, params: params2, .. },
|
TypeEnum::TObj { obj_id: id2, params: params2, .. },
|
||||||
@ -119,6 +116,15 @@ impl TestEnvironment {
|
|||||||
params: into_var_map([tvar]),
|
params: into_var_map([tvar]),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
let tvar = unifier.get_dummy_var();
|
||||||
|
type_mapping.insert(
|
||||||
|
"list".into(),
|
||||||
|
unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: PrimDef::List.id(),
|
||||||
|
fields: HashMap::new(),
|
||||||
|
params: into_var_map([tvar]),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
TestEnvironment { unifier, type_mapping }
|
TestEnvironment { unifier, type_mapping }
|
||||||
}
|
}
|
||||||
@ -133,6 +139,36 @@ impl TestEnvironment {
|
|||||||
// for testing only, so we can just panic when the input is malformed
|
// for testing only, so we can just panic when the input is malformed
|
||||||
let end = typ.find(|c| ['[', ',', ']', '='].contains(&c)).unwrap_or(typ.len());
|
let end = typ.find(|c| ['[', ',', ']', '='].contains(&c)).unwrap_or(typ.len());
|
||||||
match &typ[..end] {
|
match &typ[..end] {
|
||||||
|
"list" => {
|
||||||
|
let mut s = &typ[end..];
|
||||||
|
assert_eq!(&s[0..1], "[");
|
||||||
|
let mut ty = Vec::new();
|
||||||
|
while &s[0..1] != "]" {
|
||||||
|
let result = self.internal_parse(&s[1..], mapping);
|
||||||
|
ty.push(result.0);
|
||||||
|
s = result.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(ty.len(), 1);
|
||||||
|
|
||||||
|
let list_elem_tvar = if let TypeEnum::TObj { params, .. } =
|
||||||
|
&*self.unifier.get_ty_immutable(self.type_mapping["list"])
|
||||||
|
{
|
||||||
|
iter_type_vars(params).next().unwrap()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
self.unifier
|
||||||
|
.subst(
|
||||||
|
self.type_mapping["list"],
|
||||||
|
&into_var_map([TypeVar { id: list_elem_tvar.id, ty: ty[0] }]),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
&s[1..],
|
||||||
|
)
|
||||||
|
}
|
||||||
"tuple" => {
|
"tuple" => {
|
||||||
let mut s = &typ[end..];
|
let mut s = &typ[end..];
|
||||||
assert_eq!(&s[0..1], "[");
|
assert_eq!(&s[0..1], "[");
|
||||||
@ -144,12 +180,6 @@ impl TestEnvironment {
|
|||||||
}
|
}
|
||||||
(self.unifier.add_ty(TypeEnum::TTuple { ty }), &s[1..])
|
(self.unifier.add_ty(TypeEnum::TTuple { ty }), &s[1..])
|
||||||
}
|
}
|
||||||
"list" => {
|
|
||||||
assert_eq!(&typ[end..=end], "[");
|
|
||||||
let (ty, s) = self.internal_parse(&typ[end + 1..], mapping);
|
|
||||||
assert_eq!(&s[0..1], "]");
|
|
||||||
(self.unifier.add_ty(TypeEnum::TList { ty }), &s[1..])
|
|
||||||
}
|
|
||||||
"Record" => {
|
"Record" => {
|
||||||
let mut s = &typ[end..];
|
let mut s = &typ[end..];
|
||||||
assert_eq!(&s[0..1], "[");
|
assert_eq!(&s[0..1], "[");
|
||||||
@ -274,7 +304,7 @@ fn test_unify(
|
|||||||
("v1", "tuple[int]"),
|
("v1", "tuple[int]"),
|
||||||
("v2", "list[int]"),
|
("v2", "list[int]"),
|
||||||
],
|
],
|
||||||
(("v1", "v2"), "Incompatible types: list[0] and tuple[0]")
|
(("v1", "v2"), "Incompatible types: 11[0] and tuple[0]")
|
||||||
; "type mismatch"
|
; "type mismatch"
|
||||||
)]
|
)]
|
||||||
#[test_case(2,
|
#[test_case(2,
|
||||||
@ -298,7 +328,7 @@ fn test_unify(
|
|||||||
("v1", "Record[a=float,b=int]"),
|
("v1", "Record[a=float,b=int]"),
|
||||||
("v2", "Foo[v3]"),
|
("v2", "Foo[v3]"),
|
||||||
],
|
],
|
||||||
(("v1", "v2"), "`3[typevar4]::b` field/method does not exist")
|
(("v1", "v2"), "`3[typevar5]::b` field/method does not exist")
|
||||||
; "record obj merge"
|
; "record obj merge"
|
||||||
)]
|
)]
|
||||||
/// Test cases for invalid unifications.
|
/// Test cases for invalid unifications.
|
||||||
@ -388,6 +418,14 @@ fn test_typevar_range() {
|
|||||||
let int_list = env.parse("list[int]", &HashMap::new());
|
let int_list = env.parse("list[int]", &HashMap::new());
|
||||||
let float_list = env.parse("list[float]", &HashMap::new());
|
let float_list = env.parse("list[float]", &HashMap::new());
|
||||||
|
|
||||||
|
let list_elem_tvar = if let TypeEnum::TObj { params, .. } =
|
||||||
|
&*env.unifier.get_ty_immutable(env.type_mapping["list"])
|
||||||
|
{
|
||||||
|
iter_type_vars(params).next().unwrap()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
// unification between v and int
|
// unification between v and int
|
||||||
// where v in (int, bool)
|
// where v in (int, bool)
|
||||||
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
|
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
|
||||||
@ -398,7 +436,7 @@ fn test_typevar_range() {
|
|||||||
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
|
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.unify(int_list, v),
|
env.unify(int_list, v),
|
||||||
Err("Expected any one of these types: 0, 2, but got list[0]".to_string())
|
Err("Expected any one of these types: 0, 2, but got 11[0]".to_string())
|
||||||
);
|
);
|
||||||
|
|
||||||
// unification between v and float
|
// unification between v and float
|
||||||
@ -410,7 +448,11 @@ fn test_typevar_range() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let v1 = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
|
let v1 = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
|
||||||
let v1_list = env.unifier.add_ty(TypeEnum::TList { ty: v1 });
|
let v1_list = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: v1 }]),
|
||||||
|
});
|
||||||
let v = env.unifier.get_fresh_var_with_range(&[int, v1_list], None, None).ty;
|
let v = env.unifier.get_fresh_var_with_range(&[int, v1_list], None, None).ty;
|
||||||
// unification between v and int
|
// unification between v and int
|
||||||
// where v in (int, list[v1]), v1 in (int, bool)
|
// where v in (int, list[v1]), v1 in (int, bool)
|
||||||
@ -424,9 +466,10 @@ fn test_typevar_range() {
|
|||||||
let v = env.unifier.get_fresh_var_with_range(&[int, v1_list], None, None).ty;
|
let v = env.unifier.get_fresh_var_with_range(&[int, v1_list], None, None).ty;
|
||||||
// unification between v and list[float]
|
// unification between v and list[float]
|
||||||
// where v in (int, list[v1]), v1 in (int, bool)
|
// where v in (int, list[v1]), v1 in (int, bool)
|
||||||
|
println!("float_list: {}, v: {}", env.unifier.stringify(float_list), env.unifier.stringify(v));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.unify(float_list, v),
|
env.unify(float_list, v),
|
||||||
Err("Expected any one of these types: 0, list[typevar5], but got list[1]\n\nNotes:\n typevar5 ∈ {0, 2}".to_string())
|
Err("Expected any one of these types: 0, 11[typevar6], but got 11[1]\n\nNotes:\n typevar6 ∈ {0, 2}".to_string())
|
||||||
);
|
);
|
||||||
|
|
||||||
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
|
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
|
||||||
@ -441,34 +484,66 @@ fn test_typevar_range() {
|
|||||||
|
|
||||||
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
|
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
|
||||||
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).ty;
|
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).ty;
|
||||||
let a_list = env.unifier.add_ty(TypeEnum::TList { ty: a });
|
let a_list = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: a }]),
|
||||||
|
});
|
||||||
let a_list = env.unifier.get_fresh_var_with_range(&[a_list], None, None).ty;
|
let a_list = env.unifier.get_fresh_var_with_range(&[a_list], None, None).ty;
|
||||||
let b_list = env.unifier.add_ty(TypeEnum::TList { ty: b });
|
let b_list = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: b }]),
|
||||||
|
});
|
||||||
let b_list = env.unifier.get_fresh_var_with_range(&[b_list], None, None).ty;
|
let b_list = env.unifier.get_fresh_var_with_range(&[b_list], None, None).ty;
|
||||||
env.unifier.unify(a_list, b_list).unwrap();
|
env.unifier.unify(a_list, b_list).unwrap();
|
||||||
let float_list = env.unifier.add_ty(TypeEnum::TList { ty: float });
|
let float_list = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: float }]),
|
||||||
|
});
|
||||||
env.unifier.unify(a_list, float_list).unwrap();
|
env.unifier.unify(a_list, float_list).unwrap();
|
||||||
// previous unifications should not affect a and b
|
// previous unifications should not affect a and b
|
||||||
env.unifier.unify(a, int).unwrap();
|
env.unifier.unify(a, int).unwrap();
|
||||||
|
|
||||||
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
|
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
|
||||||
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).ty;
|
let b = env.unifier.get_fresh_var_with_range(&[boolean, float], None, None).ty;
|
||||||
let a_list = env.unifier.add_ty(TypeEnum::TList { ty: a });
|
let a_list = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
let b_list = env.unifier.add_ty(TypeEnum::TList { ty: b });
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: a }]),
|
||||||
|
});
|
||||||
|
let b_list = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: b }]),
|
||||||
|
});
|
||||||
env.unifier.unify(a_list, b_list).unwrap();
|
env.unifier.unify(a_list, b_list).unwrap();
|
||||||
let int_list = env.unifier.add_ty(TypeEnum::TList { ty: int });
|
let int_list = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: int }]),
|
||||||
|
});
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.unify(a_list, int_list),
|
env.unify(a_list, int_list),
|
||||||
Err("Incompatible types: list[typevar22] and list[0]\
|
Err("Incompatible types: 11[typevar23] and 11[0]\
|
||||||
\n\nNotes:\n typevar22 ∈ {1}"
|
\n\nNotes:\n typevar23 ∈ {1}"
|
||||||
.into())
|
.into())
|
||||||
);
|
);
|
||||||
|
|
||||||
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
|
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).ty;
|
||||||
let b = env.unifier.get_dummy_var().ty;
|
let b = env.unifier.get_dummy_var().ty;
|
||||||
let a_list = env.unifier.add_ty(TypeEnum::TList { ty: a });
|
let a_list = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: a }]),
|
||||||
|
});
|
||||||
let a_list = env.unifier.get_fresh_var_with_range(&[a_list], None, None).ty;
|
let a_list = env.unifier.get_fresh_var_with_range(&[a_list], None, None).ty;
|
||||||
let b_list = env.unifier.add_ty(TypeEnum::TList { ty: b });
|
let b_list = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: b }]),
|
||||||
|
});
|
||||||
env.unifier.unify(a_list, b_list).unwrap();
|
env.unifier.unify(a_list, b_list).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.unify(b, boolean),
|
env.unify(b, boolean),
|
||||||
@ -482,16 +557,25 @@ fn test_rigid_var() {
|
|||||||
let a = env.unifier.get_fresh_rigid_var(None, None).ty;
|
let a = env.unifier.get_fresh_rigid_var(None, None).ty;
|
||||||
let b = env.unifier.get_fresh_rigid_var(None, None).ty;
|
let b = env.unifier.get_fresh_rigid_var(None, None).ty;
|
||||||
let x = env.unifier.get_dummy_var().ty;
|
let x = env.unifier.get_dummy_var().ty;
|
||||||
let list_a = env.unifier.add_ty(TypeEnum::TList { ty: a });
|
let list_elem_tvar = env.unifier.get_fresh_var(Some("list_elem".into()), None);
|
||||||
let list_x = env.unifier.add_ty(TypeEnum::TList { ty: x });
|
let list_a = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: a }]),
|
||||||
|
});
|
||||||
|
let list_x = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: env.type_mapping["list"].obj_id(&env.unifier).unwrap(),
|
||||||
|
fields: Mapping::default(),
|
||||||
|
params: into_var_map([TypeVar { id: list_elem_tvar.id, ty: x }]),
|
||||||
|
});
|
||||||
let int = env.parse("int", &HashMap::new());
|
let int = env.parse("int", &HashMap::new());
|
||||||
let list_int = env.parse("list[int]", &HashMap::new());
|
let list_int = env.parse("list[int]", &HashMap::new());
|
||||||
|
|
||||||
assert_eq!(env.unify(a, b), Err("Incompatible types: typevar3 and typevar2".to_string()));
|
assert_eq!(env.unify(a, b), Err("Incompatible types: typevar4 and typevar3".to_string()));
|
||||||
env.unifier.unify(list_a, list_x).unwrap();
|
env.unifier.unify(list_a, list_x).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.unify(list_x, list_int),
|
env.unify(list_x, list_int),
|
||||||
Err("Incompatible types: list[typevar2] and list[0]".to_string())
|
Err("Incompatible types: 11[typevar3] and 11[0]".to_string())
|
||||||
);
|
);
|
||||||
|
|
||||||
env.unifier.replace_rigid_var(a, int);
|
env.unifier.replace_rigid_var(a, int);
|
||||||
@ -506,10 +590,21 @@ fn test_instantiation() {
|
|||||||
let float = env.parse("float", &HashMap::new());
|
let float = env.parse("float", &HashMap::new());
|
||||||
let list_int = env.parse("list[int]", &HashMap::new());
|
let list_int = env.parse("list[int]", &HashMap::new());
|
||||||
|
|
||||||
let obj_map: HashMap<_, _> = [(0usize, "int"), (1, "float"), (2, "bool")].into();
|
let list_elem_tvar = if let TypeEnum::TObj { params, .. } =
|
||||||
|
&*env.unifier.get_ty_immutable(env.type_mapping["list"])
|
||||||
|
{
|
||||||
|
iter_type_vars(params).next().unwrap()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let obj_map: HashMap<_, _> = [(0usize, "int"), (1, "float"), (2, "bool"), (11, "list")].into();
|
||||||
|
|
||||||
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
|
let v = env.unifier.get_fresh_var_with_range(&[int, boolean], None, None).ty;
|
||||||
let list_v = env.unifier.add_ty(TypeEnum::TList { ty: v });
|
let list_v = env
|
||||||
|
.unifier
|
||||||
|
.subst(env.type_mapping["list"], &into_var_map([TypeVar { id: list_elem_tvar.id, ty: v }]))
|
||||||
|
.unwrap();
|
||||||
let v1 = env.unifier.get_fresh_var_with_range(&[list_v, int], None, None).ty;
|
let v1 = env.unifier.get_fresh_var_with_range(&[list_v, int], None, None).ty;
|
||||||
let v2 = env.unifier.get_fresh_var_with_range(&[list_int, float], None, None).ty;
|
let v2 = env.unifier.get_fresh_var_with_range(&[list_int, float], None, None).ty;
|
||||||
let t = env.unifier.get_dummy_var().ty;
|
let t = env.unifier.get_dummy_var().ty;
|
||||||
@ -536,7 +631,7 @@ fn test_instantiation() {
|
|||||||
tuple[int, list[bool], list[int]]
|
tuple[int, list[bool], list[int]]
|
||||||
tuple[int, list[int], float]
|
tuple[int, list[int], float]
|
||||||
tuple[int, list[int], list[int]]
|
tuple[int, list[int], list[int]]
|
||||||
v5"
|
v6"
|
||||||
}
|
}
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
@extern
|
||||||
|
def output_bool(x: bool):
|
||||||
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32_list(x: list[int32]):
|
def output_int32_list(x: list[int32]):
|
||||||
...
|
...
|
||||||
@ -30,6 +34,32 @@ def run() -> int32:
|
|||||||
|
|
||||||
get_list_slice()
|
get_list_slice()
|
||||||
list_slice_assignment()
|
list_slice_assignment()
|
||||||
|
|
||||||
|
output_int32_list([1, 2, 3] + [4, 5, 6])
|
||||||
|
output_int32_list([1, 2, 3] * 3)
|
||||||
|
output_bool([] == [])
|
||||||
|
output_bool([0] == [])
|
||||||
|
output_bool([0] == [0])
|
||||||
|
output_bool([0, 1] == [0])
|
||||||
|
output_bool([0, 1] == [0, 1])
|
||||||
|
output_bool([] != [])
|
||||||
|
output_bool([0] != [])
|
||||||
|
output_bool([0] != [0])
|
||||||
|
output_bool([0] != [0, 1])
|
||||||
|
output_bool([0, 1] != [0, 1])
|
||||||
|
output_bool([] == [] == [])
|
||||||
|
output_bool([0] == [0] == [0])
|
||||||
|
output_bool([0, 1] == [0] == [0, 1])
|
||||||
|
output_bool([0, 1] == [0, 1] == [0])
|
||||||
|
output_bool([0] == [0, 1] == [0, 1])
|
||||||
|
output_bool([0, 1] == [0, 1] == [0, 1])
|
||||||
|
output_bool([] != [] != [])
|
||||||
|
output_bool([0] != [0] != [0])
|
||||||
|
output_bool([0, 1] != [0] != [0, 1])
|
||||||
|
output_bool([0, 1] != [0, 1] != [0])
|
||||||
|
output_bool([0] != [0, 1] != [0, 1])
|
||||||
|
output_bool([0, 1] != [0, 1] != [0, 1])
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def get_list_slice():
|
def get_list_slice():
|
||||||
|
Loading…
Reference in New Issue
Block a user