forked from M-Labs/nac3
Compare commits
15 Commits
Author | SHA1 | Date |
---|---|---|
wylited | 35b6459c58 | |
wylited | e94b25f544 | |
Sebastien Bourdeauducq | 6972689469 | |
Sebastien Bourdeauducq | 3fb22c9182 | |
Sebastien Bourdeauducq | 1e7abf0268 | |
Sebastien Bourdeauducq | f5a6d29106 | |
Sebastien Bourdeauducq | ca07cb66cd | |
Sebastien Bourdeauducq | 93e9a6a38a | |
ychenfo | 722e3df086 | |
ychenfo | ad9ad22cb8 | |
ychenfo | f66f66b3a4 | |
ychenfo | 6c485bc9dc | |
ychenfo | 089bba96a3 | |
ychenfo | 0e0871bc38 | |
ychenfo | 26187bff0b |
|
@ -422,9 +422,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.121"
|
version = "0.2.122"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
|
checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
|
@ -740,9 +740,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.36"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
@ -797,9 +797,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.17"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
|
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
@ -1035,9 +1035,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.90"
|
version = "1.0.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f"
|
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1649024309,
|
"lastModified": 1649619156,
|
||||||
"narHash": "sha256-AWbvj/NHZXVwAnHaVOFlxg7tcNerEKrKBmgGfztSHWM=",
|
"narHash": "sha256-p0q4zpuKMwrzGF+5ZU7Thnpac5TinhDI9jr2mBxhV4w=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "af0a9bc0e5341855518e9c1734d7ef913e5138b9",
|
"rev": "e7d63bd0d50df412f5a1d8acfa3caae75522e347",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
from min_artiq import *
|
from min_artiq import *
|
||||||
from numpy import int32, int64
|
|
||||||
|
|
||||||
|
|
||||||
@extern
|
|
||||||
def output_int(x: int32):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
@nac3
|
@nac3
|
||||||
|
|
|
@ -68,7 +68,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
||||||
let result = gen_call(self, ctx, obj, fun, params)?;
|
let result = gen_call(self, ctx, obj, fun, params)?;
|
||||||
if let Some(end) = self.end.clone() {
|
if let Some(end) = self.end.clone() {
|
||||||
let old_end = self.gen_expr(ctx, &end)?.unwrap().to_basic_value_enum(ctx, self)?;
|
let old_end = self.gen_expr(ctx, &end)?.unwrap().to_basic_value_enum(ctx, self, end.custom.unwrap())?;
|
||||||
let now = self.timeline.emit_now_mu(ctx);
|
let now = self.timeline.emit_now_mu(ctx);
|
||||||
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
||||||
let i64 = ctx.ctx.i64_type();
|
let i64 = ctx.ctx.i64_type();
|
||||||
|
@ -88,7 +88,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
ctx.builder.build_store(end_store, max);
|
ctx.builder.build_store(end_store, max);
|
||||||
}
|
}
|
||||||
if let Some(start) = self.start.clone() {
|
if let Some(start) = self.start.clone() {
|
||||||
let start_val = self.gen_expr(ctx, &start)?.unwrap().to_basic_value_enum(ctx, self)?;
|
let start_val = self.gen_expr(ctx, &start)?.unwrap().to_basic_value_enum(ctx, self, start.custom.unwrap())?;
|
||||||
self.timeline.emit_at_mu(ctx, start_val);
|
self.timeline.emit_at_mu(ctx, start_val);
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
@ -120,7 +120,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
let old_start = self.start.take();
|
let old_start = self.start.take();
|
||||||
let old_end = self.end.take();
|
let old_end = self.end.take();
|
||||||
let now = if let Some(old_start) = &old_start {
|
let now = if let Some(old_start) = &old_start {
|
||||||
self.gen_expr(ctx, old_start)?.unwrap().to_basic_value_enum(ctx, self)?
|
self.gen_expr(ctx, old_start)?.unwrap().to_basic_value_enum(ctx, self, old_start.custom.unwrap())?
|
||||||
} else {
|
} else {
|
||||||
self.timeline.emit_now_mu(ctx)
|
self.timeline.emit_now_mu(ctx)
|
||||||
};
|
};
|
||||||
|
@ -174,8 +174,10 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
};
|
};
|
||||||
// set duration
|
// set duration
|
||||||
let end_expr = self.end.take().unwrap();
|
let end_expr = self.end.take().unwrap();
|
||||||
let end_val =
|
let end_val = self
|
||||||
self.gen_expr(ctx, &end_expr)?.unwrap().to_basic_value_enum(ctx, self)?;
|
.gen_expr(ctx, &end_expr)?
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, self, end_expr.custom.unwrap())?;
|
||||||
|
|
||||||
// inside a sequential block
|
// inside a sequential block
|
||||||
if old_start.is_none() {
|
if old_start.is_none() {
|
||||||
|
@ -186,7 +188,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
let outer_end_val = self
|
let outer_end_val = self
|
||||||
.gen_expr(ctx, old_end)?
|
.gen_expr(ctx, old_end)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, self)?;
|
.to_basic_value_enum(ctx, self, old_end.custom.unwrap())?;
|
||||||
let smax =
|
let smax =
|
||||||
ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
||||||
let i64 = ctx.ctx.i64_type();
|
let i64 = ctx.ctx.i64_type();
|
||||||
|
@ -371,7 +373,7 @@ fn rpc_codegen_callback_fn<'ctx, 'a>(
|
||||||
.0
|
.0
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| mapping.remove(&arg.name).unwrap().to_basic_value_enum(ctx, generator))
|
.map(|arg| mapping.remove(&arg.name).unwrap().to_basic_value_enum(ctx, generator, arg.ty))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
if let Some(obj) = obj {
|
if let Some(obj) = obj {
|
||||||
if let ValueEnum::Static(obj) = obj.1 {
|
if let ValueEnum::Static(obj) = obj.1 {
|
||||||
|
@ -511,11 +513,13 @@ pub fn attributes_writeback<'ctx, 'a>(
|
||||||
}
|
}
|
||||||
let ty = ty.unwrap();
|
let ty = ty.unwrap();
|
||||||
match &*ctx.unifier.get_ty(ty) {
|
match &*ctx.unifier.get_ty(ty) {
|
||||||
TypeEnum::TObj { fields, .. } => {
|
TypeEnum::TObj { fields, obj_id, .. }
|
||||||
|
if *obj_id != ctx.primitives.option.get_obj_id(&ctx.unifier) =>
|
||||||
|
{
|
||||||
// we only care about primitive attributes
|
// we only care about primitive attributes
|
||||||
// for non-primitive attributes, they should be in another global
|
// for non-primitive attributes, they should be in another global
|
||||||
let mut attributes = Vec::new();
|
let mut attributes = Vec::new();
|
||||||
let obj = inner_resolver.get_obj_value(py, val, ctx, generator)?.unwrap();
|
let obj = inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap();
|
||||||
for (name, (field_ty, is_mutable)) in fields.iter() {
|
for (name, (field_ty, is_mutable)) in fields.iter() {
|
||||||
if !is_mutable {
|
if !is_mutable {
|
||||||
continue
|
continue
|
||||||
|
@ -540,7 +544,7 @@ pub fn attributes_writeback<'ctx, 'a>(
|
||||||
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)?;
|
||||||
values.push((ty, inner_resolver.get_obj_value(py, val, ctx, generator)?.unwrap()));
|
values.push((ty, inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -65,6 +65,7 @@ pub struct PrimitivePythonId {
|
||||||
uint32: u64,
|
uint32: u64,
|
||||||
uint64: u64,
|
uint64: u64,
|
||||||
float: u64,
|
float: u64,
|
||||||
|
float64: u64,
|
||||||
bool: u64,
|
bool: u64,
|
||||||
list: u64,
|
list: u64,
|
||||||
tuple: u64,
|
tuple: u64,
|
||||||
|
@ -328,8 +329,9 @@ impl Nac3 {
|
||||||
ret: primitive.none,
|
ret: primitive.none,
|
||||||
vars: HashMap::new(),
|
vars: HashMap::new(),
|
||||||
},
|
},
|
||||||
Arc::new(GenCall::new(Box::new(move |ctx, _, _, args, generator| {
|
Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| {
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator).unwrap();
|
let arg_ty = fun.0.args[0].ty;
|
||||||
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty).unwrap();
|
||||||
time_fns.emit_at_mu(ctx, arg);
|
time_fns.emit_at_mu(ctx, arg);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}))),
|
}))),
|
||||||
|
@ -345,8 +347,9 @@ impl Nac3 {
|
||||||
ret: primitive.none,
|
ret: primitive.none,
|
||||||
vars: HashMap::new(),
|
vars: HashMap::new(),
|
||||||
},
|
},
|
||||||
Arc::new(GenCall::new(Box::new(move |ctx, _, _, args, generator| {
|
Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| {
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator).unwrap();
|
let arg_ty = fun.0.args[0].ty;
|
||||||
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty).unwrap();
|
||||||
time_fns.emit_delay_mu(ctx, arg);
|
time_fns.emit_delay_mu(ctx, arg);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}))),
|
}))),
|
||||||
|
@ -395,6 +398,7 @@ impl Nac3 {
|
||||||
uint64: get_attr_id(numpy_mod, "uint64"),
|
uint64: get_attr_id(numpy_mod, "uint64"),
|
||||||
bool: get_attr_id(builtins_mod, "bool"),
|
bool: get_attr_id(builtins_mod, "bool"),
|
||||||
float: get_attr_id(builtins_mod, "float"),
|
float: get_attr_id(builtins_mod, "float"),
|
||||||
|
float64: get_attr_id(numpy_mod, "float64"),
|
||||||
list: get_attr_id(builtins_mod, "list"),
|
list: get_attr_id(builtins_mod, "list"),
|
||||||
tuple: get_attr_id(builtins_mod, "tuple"),
|
tuple: get_attr_id(builtins_mod, "tuple"),
|
||||||
exception: get_attr_id(builtins_mod, "Exception"),
|
exception: get_attr_id(builtins_mod, "Exception"),
|
||||||
|
|
|
@ -131,6 +131,7 @@ impl StaticValue for PythonValue {
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
|
expected_ty: Type,
|
||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
if let Some(val) = self.resolver.id_to_primitive.read().get(&self.id) {
|
if let Some(val) = self.resolver.id_to_primitive.read().get(&self.id) {
|
||||||
return Ok(match val {
|
return Ok(match val {
|
||||||
|
@ -150,7 +151,7 @@ impl StaticValue for PythonValue {
|
||||||
|
|
||||||
Python::with_gil(|py| -> PyResult<BasicValueEnum<'ctx>> {
|
Python::with_gil(|py| -> PyResult<BasicValueEnum<'ctx>> {
|
||||||
self.resolver
|
self.resolver
|
||||||
.get_obj_value(py, self.value.as_ref(py), ctx, generator)
|
.get_obj_value(py, self.value.as_ref(py), ctx, generator, expected_ty)
|
||||||
.map(Option::unwrap)
|
.map(Option::unwrap)
|
||||||
}).map_err(|e| e.to_string())
|
}).map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
@ -169,6 +170,16 @@ impl StaticValue for PythonValue {
|
||||||
let helper = &self.resolver.helper;
|
let helper = &self.resolver.helper;
|
||||||
let ty = helper.type_fn.call1(py, (&self.value,))?;
|
let ty = helper.type_fn.call1(py, (&self.value,))?;
|
||||||
let ty_id: u64 = helper.id_fn.call1(py, (ty,))?.extract(py)?;
|
let ty_id: u64 = helper.id_fn.call1(py, (ty,))?.extract(py)?;
|
||||||
|
// for optimizing unwrap KernelInvariant
|
||||||
|
if ty_id == self.resolver.primitive_ids.option && name == "_nac3_option".into() {
|
||||||
|
let obj = self.value.getattr(py, &name.to_string())?;
|
||||||
|
let id = self.resolver.helper.id_fn.call1(py, (&obj,))?.extract(py)?;
|
||||||
|
if self.id == self.resolver.primitive_ids.none {
|
||||||
|
return Ok(None)
|
||||||
|
} else {
|
||||||
|
return Ok(Some((id, obj)))
|
||||||
|
}
|
||||||
|
}
|
||||||
let def_id = { *self.resolver.pyid_to_def.read().get(&ty_id).unwrap() };
|
let def_id = { *self.resolver.pyid_to_def.read().get(&ty_id).unwrap() };
|
||||||
let mut mutable = true;
|
let mut mutable = true;
|
||||||
let defs = ctx.top_level.definitions.read();
|
let defs = ctx.top_level.definitions.read();
|
||||||
|
@ -201,6 +212,28 @@ impl StaticValue for PythonValue {
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_tuple_element<'ctx>(&self, index: u32) -> Option<ValueEnum<'ctx>> {
|
||||||
|
Python::with_gil(|py| -> PyResult<Option<(u64, PyObject)>> {
|
||||||
|
let helper = &self.resolver.helper;
|
||||||
|
let ty = helper.type_fn.call1(py, (&self.value,))?;
|
||||||
|
let ty_id: u64 = helper.id_fn.call1(py, (ty,))?.extract(py)?;
|
||||||
|
assert_eq!(ty_id, self.resolver.primitive_ids.tuple);
|
||||||
|
let tup: &PyTuple = self.value.extract(py)?;
|
||||||
|
let elem = tup.get_item(index as usize);
|
||||||
|
let id = self.resolver.helper.id_fn.call1(py, (elem,))?.extract(py)?;
|
||||||
|
Ok(Some((id, elem.into())))
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.map(|(id, obj)| {
|
||||||
|
ValueEnum::Static(Arc::new(PythonValue {
|
||||||
|
id,
|
||||||
|
value: obj,
|
||||||
|
store_obj: self.store_obj.clone(),
|
||||||
|
resolver: self.resolver.clone(),
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerResolver {
|
impl InnerResolver {
|
||||||
|
@ -269,6 +302,8 @@ impl InnerResolver {
|
||||||
Ok(Ok((primitives.bool, true)))
|
Ok(Ok((primitives.bool, true)))
|
||||||
} else if ty_id == self.primitive_ids.float {
|
} else if ty_id == self.primitive_ids.float {
|
||||||
Ok(Ok((primitives.float, true)))
|
Ok(Ok((primitives.float, true)))
|
||||||
|
} else if ty_id == self.primitive_ids.float64 {
|
||||||
|
Ok(Ok((primitives.float, true)))
|
||||||
} else if ty_id == self.primitive_ids.exception {
|
} else if ty_id == self.primitive_ids.exception {
|
||||||
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 {
|
||||||
|
@ -544,7 +579,7 @@ 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)?;
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&*unifier.get_ty(extracted_ty),
|
&*unifier.get_ty(*ty),
|
||||||
TypeEnum::TVar { fields: None, range, .. }
|
TypeEnum::TVar { fields: None, range, .. }
|
||||||
if range.is_empty()
|
if range.is_empty()
|
||||||
));
|
));
|
||||||
|
@ -692,6 +727,7 @@ impl InnerResolver {
|
||||||
obj: &PyAny,
|
obj: &PyAny,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
|
expected_ty: Type,
|
||||||
) -> PyResult<Option<BasicValueEnum<'ctx>>> {
|
) -> PyResult<Option<BasicValueEnum<'ctx>>> {
|
||||||
let ty_id: u64 =
|
let ty_id: u64 =
|
||||||
self.helper.id_fn.call1(py, (self.helper.type_fn.call1(py, (obj,))?,))?.extract(py)?;
|
self.helper.id_fn.call1(py, (self.helper.type_fn.call1(py, (obj,))?,))?.extract(py)?;
|
||||||
|
@ -721,7 +757,7 @@ impl InnerResolver {
|
||||||
format!("{} is not in the range of bool", obj)))?;
|
format!("{} is not in the range of bool", obj)))?;
|
||||||
self.id_to_primitive.write().insert(id, PrimitiveValue::Bool(val));
|
self.id_to_primitive.write().insert(id, PrimitiveValue::Bool(val));
|
||||||
Ok(Some(ctx.ctx.bool_type().const_int(val as u64, false).into()))
|
Ok(Some(ctx.ctx.bool_type().const_int(val as u64, false).into()))
|
||||||
} else if ty_id == self.primitive_ids.float {
|
} else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 {
|
||||||
let val: f64 = obj.extract().map_err(|_| super::CompileError::new_err(
|
let val: f64 = obj.extract().map_err(|_| super::CompileError::new_err(
|
||||||
format!("{} is not in the range of float64", obj)))?;
|
format!("{} is not in the range of float64", obj)))?;
|
||||||
self.id_to_primitive.write().insert(id, PrimitiveValue::F64(val));
|
self.id_to_primitive.write().insert(id, PrimitiveValue::F64(val));
|
||||||
|
@ -734,20 +770,14 @@ 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 ty = if len == 0 {
|
let elem_ty =
|
||||||
ctx.primitives.int32
|
if let TypeEnum::TList { ty } = ctx.unifier.get_ty_immutable(expected_ty).as_ref()
|
||||||
|
{
|
||||||
|
*ty
|
||||||
} else {
|
} else {
|
||||||
self.get_list_elem_type(
|
unreachable!("must be list")
|
||||||
py,
|
|
||||||
obj,
|
|
||||||
len,
|
|
||||||
&mut ctx.unifier,
|
|
||||||
&ctx.top_level.definitions.read(),
|
|
||||||
&ctx.primitives,
|
|
||||||
)?
|
|
||||||
.unwrap()
|
|
||||||
};
|
};
|
||||||
let ty = ctx.get_llvm_type(generator, 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);
|
||||||
let arr_ty = ctx
|
let arr_ty = ctx
|
||||||
.ctx
|
.ctx
|
||||||
|
@ -766,8 +796,13 @@ impl InnerResolver {
|
||||||
|
|
||||||
let arr: Result<Option<Vec<_>>, _> = (0..len)
|
let arr: Result<Option<Vec<_>>, _> = (0..len)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
obj.get_item(i).and_then(|elem| self.get_obj_value(py, elem, ctx, generator).map_err(
|
obj
|
||||||
|e| super::CompileError::new_err(format!("Error getting element {}: {}", i, e))))
|
.get_item(i)
|
||||||
|
.and_then(|elem| self.get_obj_value(py, elem, ctx, generator, elem_ty)
|
||||||
|
.map_err(
|
||||||
|
|e| super::CompileError::new_err(
|
||||||
|
format!("Error getting element {}: {}", i, e))
|
||||||
|
))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let arr = arr?.unwrap();
|
let arr = arr?.unwrap();
|
||||||
|
@ -808,21 +843,48 @@ impl InnerResolver {
|
||||||
|
|
||||||
Ok(Some(global.as_pointer_value().into()))
|
Ok(Some(global.as_pointer_value().into()))
|
||||||
} else if ty_id == self.primitive_ids.tuple {
|
} else if ty_id == self.primitive_ids.tuple {
|
||||||
let elements: &PyTuple = obj.cast_as()?;
|
if let TypeEnum::TTuple { ty } = ctx.unifier.get_ty_immutable(expected_ty).as_ref() {
|
||||||
let val: Result<Option<Vec<_>>, _> =
|
let tup_tys = ty.iter();
|
||||||
elements.iter().enumerate().map(|(i, elem)| self.get_obj_value(py, elem, ctx, generator).map_err(|e|
|
let elements: &PyTuple = obj.cast_as()?;
|
||||||
super::CompileError::new_err(format!("Error getting element {}: {}", i, e)))).collect();
|
assert_eq!(elements.len(), tup_tys.len());
|
||||||
let val = val?.unwrap();
|
let val: Result<Option<Vec<_>>, _> =
|
||||||
let val = ctx.ctx.const_struct(&val, false);
|
elements
|
||||||
Ok(Some(val.into()))
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.zip(tup_tys)
|
||||||
|
.map(|((i, elem), ty)| self
|
||||||
|
.get_obj_value(py, elem, ctx, generator, *ty).map_err(|e|
|
||||||
|
super::CompileError::new_err(
|
||||||
|
format!("Error getting element {}: {}", i, e)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).collect();
|
||||||
|
let val = val?.unwrap();
|
||||||
|
let val = ctx.ctx.const_struct(&val, false);
|
||||||
|
Ok(Some(val.into()))
|
||||||
|
} else {
|
||||||
|
unreachable!("must expect tuple type")
|
||||||
|
}
|
||||||
} else if ty_id == self.primitive_ids.option {
|
} else if ty_id == self.primitive_ids.option {
|
||||||
|
let option_val_ty = match ctx.unifier.get_ty_immutable(expected_ty).as_ref() {
|
||||||
|
TypeEnum::TObj { obj_id, params, .. }
|
||||||
|
if *obj_id == ctx.primitives.option.get_obj_id(&ctx.unifier) =>
|
||||||
|
{
|
||||||
|
*params.iter().next().unwrap().1
|
||||||
|
}
|
||||||
|
_ => unreachable!("must be option type")
|
||||||
|
};
|
||||||
if id == self.primitive_ids.none {
|
if id == self.primitive_ids.none {
|
||||||
// for option type, just a null ptr, whose type needs to be casted in codegen
|
// for option type, just a null ptr
|
||||||
// according to the type info attached in the ast
|
Ok(Some(
|
||||||
Ok(Some(ctx.ctx.i8_type().ptr_type(AddressSpace::Generic).const_null().into()))
|
ctx.get_llvm_type(generator, option_val_ty)
|
||||||
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
.const_null()
|
||||||
|
.into(),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
match self
|
match self
|
||||||
.get_obj_value(py, obj.getattr("_nac3_option").unwrap(), ctx, generator)
|
.get_obj_value(py, obj.getattr("_nac3_option").unwrap(), ctx, generator, option_val_ty)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
super::CompileError::new_err(format!(
|
super::CompileError::new_err(format!(
|
||||||
"Error getting value of Option object: {}",
|
"Error getting value of Option object: {}",
|
||||||
|
@ -881,23 +943,8 @@ impl InnerResolver {
|
||||||
let values: Result<Option<Vec<_>>, _> = fields
|
let values: Result<Option<Vec<_>>, _> = fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, ty, _)| {
|
.map(|(name, ty, _)| {
|
||||||
let v = self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx, generator)
|
self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx, generator, *ty)
|
||||||
.map_err(|e| super::CompileError::new_err(format!("Error getting field {}: {}", name, e)));
|
.map_err(|e| super::CompileError::new_err(format!("Error getting field {}: {}", name, e)))
|
||||||
match (v, ctx.unifier.get_ty_immutable(*ty).as_ref()) {
|
|
||||||
(Ok(Some(v)), TypeEnum::TObj { obj_id, params, .. })
|
|
||||||
if *obj_id == ctx.primitives.option.get_obj_id(&ctx.unifier) =>
|
|
||||||
{
|
|
||||||
let actual_ptr_ty = ctx
|
|
||||||
.get_llvm_type(generator, *params.iter().next().unwrap().1)
|
|
||||||
.ptr_type(AddressSpace::Generic);
|
|
||||||
Ok(Some(ctx.builder.build_bitcast(
|
|
||||||
v,
|
|
||||||
actual_ptr_ty,
|
|
||||||
"option_none_ptr_cast",
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
(v, _) => v,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let values = values?;
|
let values = values?;
|
||||||
|
@ -940,7 +987,7 @@ impl InnerResolver {
|
||||||
} else if ty_id == self.primitive_ids.bool {
|
} else if ty_id == self.primitive_ids.bool {
|
||||||
let val: bool = obj.extract()?;
|
let val: bool = obj.extract()?;
|
||||||
Ok(SymbolValue::Bool(val))
|
Ok(SymbolValue::Bool(val))
|
||||||
} else if ty_id == self.primitive_ids.float {
|
} else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 {
|
||||||
let val: f64 = obj.extract()?;
|
let val: f64 = obj.extract()?;
|
||||||
Ok(SymbolValue::Double(val))
|
Ok(SymbolValue::Double(val))
|
||||||
} else if ty_id == self.primitive_ids.tuple {
|
} else if ty_id == self.primitive_ids.tuple {
|
||||||
|
|
|
@ -150,11 +150,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
};
|
};
|
||||||
let actual_ptr_type =
|
let actual_ptr_type =
|
||||||
self.get_llvm_type(generator, ty).ptr_type(AddressSpace::Generic);
|
self.get_llvm_type(generator, ty).ptr_type(AddressSpace::Generic);
|
||||||
self.builder.build_bitcast(
|
actual_ptr_type.const_null().into()
|
||||||
self.ctx.i8_type().ptr_type(AddressSpace::Generic).const_null(),
|
|
||||||
actual_ptr_type,
|
|
||||||
"default_opt_none",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -643,14 +639,14 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
// reorder the parameters
|
// reorder the parameters
|
||||||
let mut real_params =
|
let mut real_params =
|
||||||
fun.0.args.iter().map(|arg| mapping.remove(&arg.name).unwrap()).collect_vec();
|
fun.0.args.iter().map(|arg| (mapping.remove(&arg.name).unwrap(), arg.ty)).collect_vec();
|
||||||
if let Some(obj) = &obj {
|
if let Some(obj) = &obj {
|
||||||
real_params.insert(0, obj.1.clone());
|
real_params.insert(0, (obj.1.clone(), obj.0));
|
||||||
}
|
}
|
||||||
let static_params = real_params
|
let static_params = real_params
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(i, v)| {
|
.filter_map(|(i, (v, _))| {
|
||||||
if let ValueEnum::Static(s) = v {
|
if let ValueEnum::Static(s) = v {
|
||||||
Some((i, s.clone()))
|
Some((i, s.clone()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -682,7 +678,7 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
|
||||||
};
|
};
|
||||||
param_vals = real_params
|
param_vals = real_params
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|p| p.to_basic_value_enum(ctx, generator))
|
.map(|(p, t)| p.to_basic_value_enum(ctx, generator, t))
|
||||||
.collect::<Result<Vec<_>, String>>()?;
|
.collect::<Result<Vec<_>, String>>()?;
|
||||||
instance_to_symbol.get(&key).cloned().ok_or_else(|| "".into())
|
instance_to_symbol.get(&key).cloned().ok_or_else(|| "".into())
|
||||||
}
|
}
|
||||||
|
@ -795,7 +791,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
||||||
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
||||||
|
|
||||||
let Comprehension { target, iter, ifs, .. } = &generators[0];
|
let Comprehension { target, iter, ifs, .. } = &generators[0];
|
||||||
let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(ctx, generator, iter.custom.unwrap())?;
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let size_t = generator.get_size_type(ctx.ctx);
|
let size_t = generator.get_size_type(ctx.ctx);
|
||||||
let zero_size_t = size_t.const_zero();
|
let zero_size_t = size_t.const_zero();
|
||||||
|
@ -900,7 +896,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
||||||
let result = generator
|
let result = generator
|
||||||
.gen_expr(ctx, cond)?
|
.gen_expr(ctx, cond)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, cond.custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let succ = ctx.ctx.append_basic_block(current, "then");
|
let succ = ctx.ctx.append_basic_block(current, "then");
|
||||||
ctx.builder.build_conditional_branch(result, succ, test_bb);
|
ctx.builder.build_conditional_branch(result, succ, test_bb);
|
||||||
|
@ -909,7 +905,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
||||||
let elem = generator.gen_expr(ctx, elt)?.unwrap();
|
let elem = generator.gen_expr(ctx, elt)?.unwrap();
|
||||||
let i = ctx.builder.build_load(index, "i").into_int_value();
|
let i = ctx.builder.build_load(index, "i").into_int_value();
|
||||||
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
|
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
|
||||||
let val = elem.to_basic_value_enum(ctx, generator)?;
|
let val = elem.to_basic_value_enum(ctx, generator, elt.custom.unwrap())?;
|
||||||
ctx.builder.build_store(elem_ptr, val);
|
ctx.builder.build_store(elem_ptr, val);
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_store(index, ctx.builder.build_int_add(i, size_t.const_int(1, false), "inc"));
|
.build_store(index, ctx.builder.build_int_add(i, size_t.const_int(1, false), "inc"));
|
||||||
|
@ -934,8 +930,8 @@ pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
) -> Result<ValueEnum<'ctx>, String> {
|
) -> Result<ValueEnum<'ctx>, String> {
|
||||||
let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
|
let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
|
||||||
let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
|
let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
|
||||||
let left = generator.gen_expr(ctx, left)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
let left = generator.gen_expr(ctx, left)?.unwrap().to_basic_value_enum(ctx, generator, left.custom.unwrap())?;
|
||||||
let right = generator.gen_expr(ctx, right)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
let right = generator.gen_expr(ctx, right)?.unwrap().to_basic_value_enum(ctx, generator, right.custom.unwrap())?;
|
||||||
|
|
||||||
// we can directly compare the types, because we've got their representatives
|
// we can directly compare the types, because we've got their representatives
|
||||||
// which would be unchanged until further unification, which we would never do
|
// which would be unchanged until further unification, which we would never do
|
||||||
|
@ -999,25 +995,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
Some((_, Some(static_value), _)) => ValueEnum::Static(static_value.clone()),
|
Some((_, Some(static_value), _)) => ValueEnum::Static(static_value.clone()),
|
||||||
None => {
|
None => {
|
||||||
let resolver = ctx.resolver.clone();
|
let resolver = ctx.resolver.clone();
|
||||||
let val = resolver.get_symbol_value(*id, ctx).unwrap();
|
resolver.get_symbol_value(*id, ctx).unwrap()
|
||||||
// if is option, need to cast pointer to handle None
|
|
||||||
match &*ctx.unifier.get_ty(expr.custom.unwrap()) {
|
|
||||||
TypeEnum::TObj { obj_id, params, .. }
|
|
||||||
if *obj_id == ctx.primitives.option.get_obj_id(&ctx.unifier) =>
|
|
||||||
{
|
|
||||||
if let BasicValueEnum::PointerValue(ptr) = val.to_basic_value_enum(ctx, generator)? {
|
|
||||||
let actual_ptr_ty = ctx.get_llvm_type(
|
|
||||||
generator,
|
|
||||||
*params.iter().next().unwrap().1,
|
|
||||||
)
|
|
||||||
.ptr_type(AddressSpace::Generic);
|
|
||||||
ctx.builder.build_bitcast(ptr, actual_ptr_ty, "option_ptr_cast").into()
|
|
||||||
} else {
|
|
||||||
unreachable!("option obj must be ptr")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => val,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ExprKind::List { elts, .. } => {
|
ExprKind::List { elts, .. } => {
|
||||||
|
@ -1028,7 +1006,10 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
generator
|
generator
|
||||||
.gen_expr(ctx, x)
|
.gen_expr(ctx, x)
|
||||||
.map_or_else(Err, |v| v.unwrap().to_basic_value_enum(ctx, generator))
|
.map_or_else(
|
||||||
|
Err,
|
||||||
|
|v| v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap())
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let ty = if elements.is_empty() {
|
let ty = if elements.is_empty() {
|
||||||
|
@ -1061,7 +1042,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
generator
|
generator
|
||||||
.gen_expr(ctx, x)
|
.gen_expr(ctx, x)
|
||||||
.map_or_else(Err, |v| v.unwrap().to_basic_value_enum(ctx, generator))
|
.map_or_else(Err, |v| v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap()))
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec();
|
let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec();
|
||||||
|
@ -1083,7 +1064,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
// note that we would handle class methods directly in calls
|
// note that we would handle class methods directly in calls
|
||||||
match generator.gen_expr(ctx, value)?.unwrap() {
|
match generator.gen_expr(ctx, value)?.unwrap() {
|
||||||
ValueEnum::Static(v) => v.get_field(*attr, ctx).map_or_else(|| {
|
ValueEnum::Static(v) => v.get_field(*attr, ctx).map_or_else(|| {
|
||||||
let v = v.to_basic_value_enum(ctx, generator)?;
|
let v = v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?;
|
||||||
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
Ok(ValueEnum::Dynamic(ctx.build_gep_and_load(
|
Ok(ValueEnum::Dynamic(ctx.build_gep_and_load(
|
||||||
v.into_pointer_value(),
|
v.into_pointer_value(),
|
||||||
|
@ -1104,7 +1085,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
let left = generator
|
let left = generator
|
||||||
.gen_expr(ctx, &values[0])?
|
.gen_expr(ctx, &values[0])?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, values[0].custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
||||||
|
@ -1120,7 +1101,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
let b = generator
|
let b = generator
|
||||||
.gen_expr(ctx, &values[1])?
|
.gen_expr(ctx, &values[1])?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
(a, b)
|
(a, b)
|
||||||
|
@ -1130,7 +1111,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
let a = generator
|
let a = generator
|
||||||
.gen_expr(ctx, &values[1])?
|
.gen_expr(ctx, &values[1])?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(b_bb);
|
ctx.builder.position_at_end(b_bb);
|
||||||
|
@ -1148,7 +1129,9 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
ExprKind::UnaryOp { op, operand } => {
|
ExprKind::UnaryOp { op, operand } => {
|
||||||
let ty = ctx.unifier.get_representative(operand.custom.unwrap());
|
let ty = ctx.unifier.get_representative(operand.custom.unwrap());
|
||||||
let val =
|
let val =
|
||||||
generator.gen_expr(ctx, operand)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
generator.gen_expr(ctx, operand)?
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator, operand.custom.unwrap())?;
|
||||||
if ty == ctx.primitives.bool {
|
if ty == ctx.primitives.bool {
|
||||||
let val = val.into_int_value();
|
let val = val.into_int_value();
|
||||||
match op {
|
match op {
|
||||||
|
@ -1208,11 +1191,11 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator
|
generator
|
||||||
.gen_expr(ctx, lhs)?
|
.gen_expr(ctx, lhs)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?,
|
.to_basic_value_enum(ctx, generator, lhs.custom.unwrap())?,
|
||||||
generator
|
generator
|
||||||
.gen_expr(ctx, rhs)?
|
.gen_expr(ctx, rhs)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?,
|
.to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?,
|
||||||
) {
|
) {
|
||||||
(lhs, rhs)
|
(lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1236,11 +1219,11 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator
|
generator
|
||||||
.gen_expr(ctx, lhs)?
|
.gen_expr(ctx, lhs)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?,
|
.to_basic_value_enum(ctx, generator, lhs.custom.unwrap())?,
|
||||||
generator
|
generator
|
||||||
.gen_expr(ctx, rhs)?
|
.gen_expr(ctx, rhs)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?,
|
.to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?,
|
||||||
) {
|
) {
|
||||||
(lhs, rhs)
|
(lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1268,7 +1251,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
let test = generator
|
let test = generator
|
||||||
.gen_expr(ctx, test)?
|
.gen_expr(ctx, test)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, test.custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let body_ty = body.custom.unwrap();
|
let body_ty = body.custom.unwrap();
|
||||||
let is_none = ctx.unifier.get_representative(body_ty) == ctx.primitives.none;
|
let is_none = ctx.unifier.get_representative(body_ty) == ctx.primitives.none;
|
||||||
|
@ -1288,7 +1271,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
match result {
|
match result {
|
||||||
None => None,
|
None => None,
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
let a = a.unwrap().to_basic_value_enum(ctx, generator)?;
|
let a = a.unwrap().to_basic_value_enum(ctx, generator, body.custom.unwrap())?;
|
||||||
Some(ctx.builder.build_store(v, a))
|
Some(ctx.builder.build_store(v, a))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1298,7 +1281,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
match result {
|
match result {
|
||||||
None => None,
|
None => None,
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
let b = b.unwrap().to_basic_value_enum(ctx, generator)?;
|
let b = b.unwrap().to_basic_value_enum(ctx, generator, orelse.custom.unwrap())?;
|
||||||
Some(ctx.builder.build_store(v, b))
|
Some(ctx.builder.build_store(v, b))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1371,23 +1354,66 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// directly generate code for option.unwrap
|
// directly generate code for option.unwrap
|
||||||
// since it needs location information from ast
|
// since it needs to return static value to optimize for kernel invariant
|
||||||
if attr == &"unwrap".into()
|
if attr == &"unwrap".into()
|
||||||
&& id == ctx.primitives.option.get_obj_id(&ctx.unifier)
|
&& id == ctx.primitives.option.get_obj_id(&ctx.unifier)
|
||||||
{
|
{
|
||||||
if let BasicValueEnum::PointerValue(ptr) = val.to_basic_value_enum(ctx, generator)? {
|
match val {
|
||||||
let not_null = ctx.builder.build_is_not_null(ptr, "unwrap_not_null");
|
ValueEnum::Static(v) => match v.get_field("_nac3_option".into(), ctx) {
|
||||||
ctx.make_assert(
|
// if is none, raise exception directly
|
||||||
generator,
|
None => {
|
||||||
not_null,
|
let err_msg = ctx.gen_string(generator, "");
|
||||||
"0:UnwrapNoneError",
|
let current_fun = ctx
|
||||||
"",
|
.builder
|
||||||
[None, None, None],
|
.get_insert_block()
|
||||||
expr.location,
|
.unwrap()
|
||||||
);
|
.get_parent()
|
||||||
return Ok(Some(ctx.builder.build_load(ptr, "unwrap_some").into()))
|
.unwrap();
|
||||||
} else {
|
let unreachable_block = ctx.ctx.append_basic_block(
|
||||||
unreachable!("option must be ptr")
|
current_fun,
|
||||||
|
"unwrap_none_unreachable"
|
||||||
|
);
|
||||||
|
let exn_block = ctx.ctx.append_basic_block(
|
||||||
|
current_fun,
|
||||||
|
"unwrap_none_exception"
|
||||||
|
);
|
||||||
|
ctx.builder.build_unconditional_branch(exn_block);
|
||||||
|
ctx.builder.position_at_end(exn_block);
|
||||||
|
ctx.raise_exn(
|
||||||
|
generator,
|
||||||
|
"0:UnwrapNoneError",
|
||||||
|
err_msg,
|
||||||
|
[None, None, None],
|
||||||
|
ctx.current_loc
|
||||||
|
);
|
||||||
|
ctx.builder.position_at_end(unreachable_block);
|
||||||
|
let ptr = ctx
|
||||||
|
.get_llvm_type(generator, value.custom.unwrap())
|
||||||
|
.into_pointer_type()
|
||||||
|
.const_null();
|
||||||
|
return Ok(Some(ctx.builder.build_load(
|
||||||
|
ptr,
|
||||||
|
"unwrap_none_unreachable_load"
|
||||||
|
).into()));
|
||||||
|
}
|
||||||
|
Some(v) => return Ok(Some(v)),
|
||||||
|
}
|
||||||
|
ValueEnum::Dynamic(BasicValueEnum::PointerValue(ptr)) => {
|
||||||
|
let not_null = ctx.builder.build_is_not_null(ptr, "unwrap_not_null");
|
||||||
|
ctx.make_assert(
|
||||||
|
generator,
|
||||||
|
not_null,
|
||||||
|
"0:UnwrapNoneError",
|
||||||
|
"",
|
||||||
|
[None, None, None],
|
||||||
|
expr.location,
|
||||||
|
);
|
||||||
|
return Ok(Some(ctx.builder.build_load(
|
||||||
|
ptr,
|
||||||
|
"unwrap_some_load"
|
||||||
|
).into()))
|
||||||
|
}
|
||||||
|
_ => unreachable!("option must be static or ptr")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(generator
|
return Ok(generator
|
||||||
|
@ -1407,7 +1433,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
let v = generator
|
let v = generator
|
||||||
.gen_expr(ctx, value)?
|
.gen_expr(ctx, value)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let ty = ctx.get_llvm_type(generator, *ty);
|
let ty = ctx.get_llvm_type(generator, *ty);
|
||||||
let arr_ptr = ctx.build_gep_and_load(v, &[zero, zero]).into_pointer_value();
|
let arr_ptr = ctx.build_gep_and_load(v, &[zero, zero]).into_pointer_value();
|
||||||
|
@ -1454,7 +1480,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
let raw_index = generator
|
let raw_index = generator
|
||||||
.gen_expr(ctx, slice)?
|
.gen_expr(ctx, slice)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let raw_index = ctx.builder.build_int_s_extend(
|
let raw_index = ctx.builder.build_int_s_extend(
|
||||||
raw_index,
|
raw_index,
|
||||||
|
@ -1489,26 +1515,39 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
[Some(raw_index), Some(len), None],
|
[Some(raw_index), Some(len), None],
|
||||||
expr.location,
|
expr.location,
|
||||||
);
|
);
|
||||||
ctx.build_gep_and_load(arr_ptr, &[index])
|
ctx.build_gep_and_load(arr_ptr, &[index]).into()
|
||||||
}
|
}
|
||||||
} else if let TypeEnum::TTuple { .. } = &*ctx.unifier.get_ty(value.custom.unwrap()) {
|
} else if let TypeEnum::TTuple { .. } = &*ctx.unifier.get_ty(value.custom.unwrap()) {
|
||||||
let v = generator
|
|
||||||
.gen_expr(ctx, value)?
|
|
||||||
.unwrap()
|
|
||||||
.to_basic_value_enum(ctx, generator)?
|
|
||||||
.into_struct_value();
|
|
||||||
let index: u32 =
|
let index: u32 =
|
||||||
if let ExprKind::Constant { value: ast::Constant::Int(v), .. } = &slice.node {
|
if let ExprKind::Constant { value: ast::Constant::Int(v), .. } = &slice.node {
|
||||||
(*v).try_into().unwrap()
|
(*v).try_into().unwrap()
|
||||||
} else {
|
} else {
|
||||||
unreachable!("tuple subscript must be const int after type check");
|
unreachable!("tuple subscript must be const int after type check");
|
||||||
};
|
};
|
||||||
ctx.builder.build_extract_value(v, index, "tup_elem").unwrap()
|
let v = generator
|
||||||
|
.gen_expr(ctx, value)?
|
||||||
|
.unwrap();
|
||||||
|
match v {
|
||||||
|
ValueEnum::Dynamic(v) => {
|
||||||
|
let v = v.into_struct_value();
|
||||||
|
ctx.builder.build_extract_value(v, index, "tup_elem").unwrap().into()
|
||||||
|
}
|
||||||
|
ValueEnum::Static(v) => {
|
||||||
|
match v.get_tuple_element(index) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
let tup = v
|
||||||
|
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
||||||
|
.into_struct_value();
|
||||||
|
ctx.builder.build_extract_value(tup, index, "tup_elem").unwrap().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!("should not be other subscriptable types after type check");
|
unreachable!("should not be other subscriptable types after type check");
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
.into(),
|
|
||||||
ExprKind::ListComp { .. } => gen_comprehension(generator, ctx, expr)?.into(),
|
ExprKind::ListComp { .. } => gen_comprehension(generator, ctx, expr)?.into(),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub trait CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate object constructor and returns the constructed object.
|
/// Generate object constructor and returns the constructed object.
|
||||||
/// - signature: Function signature of the contructor.
|
/// - signature: Function signature of the constructor.
|
||||||
/// - def: Class definition for the constructor class.
|
/// - def: Class definition for the constructor class.
|
||||||
/// - params: Function parameters.
|
/// - params: Function parameters.
|
||||||
fn gen_constructor<'ctx, 'a>(
|
fn gen_constructor<'ctx, 'a>(
|
||||||
|
|
|
@ -183,7 +183,7 @@ pub fn handle_slice_indices<'a, 'ctx, G: CodeGenerator>(
|
||||||
let step = generator
|
let step = generator
|
||||||
.gen_expr(ctx, step)?
|
.gen_expr(ctx, step)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, ctx.primitives.int32)?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
// assert step != 0, throw exception if not
|
// assert step != 0, throw exception if not
|
||||||
let not_zero = ctx.builder.build_int_compare(
|
let not_zero = ctx.builder.build_int_compare(
|
||||||
|
@ -261,7 +261,7 @@ pub fn handle_slice_index_bound<'a, 'ctx, G: CodeGenerator>(
|
||||||
ctx.module.add_function(SYMBOL, fn_t, None)
|
ctx.module.add_function(SYMBOL, fn_t, None)
|
||||||
});
|
});
|
||||||
|
|
||||||
let i = generator.gen_expr(ctx, i)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
let i = generator.gen_expr(ctx, i)?.unwrap().to_basic_value_enum(ctx, generator, i.custom.unwrap())?;
|
||||||
Ok(ctx
|
Ok(ctx
|
||||||
.builder
|
.builder
|
||||||
.build_call(func, &[i.into(), length.into()], "bounded_ind")
|
.build_call(func, &[i.into(), length.into()], "bounded_ind")
|
||||||
|
|
|
@ -54,7 +54,11 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
ExprKind::Attribute { value, attr, .. } => {
|
ExprKind::Attribute { value, attr, .. } => {
|
||||||
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
let val = generator.gen_expr(ctx, value)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
let val = generator.gen_expr(ctx, value)?.unwrap().to_basic_value_enum(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
value.custom.unwrap(),
|
||||||
|
)?;
|
||||||
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
|
@ -72,17 +76,58 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Subscript { value, slice, .. } => {
|
ExprKind::Subscript { value, slice, .. } => {
|
||||||
|
assert!(matches!(
|
||||||
|
ctx.unifier.get_ty_immutable(value.custom.unwrap()).as_ref(),
|
||||||
|
TypeEnum::TList { .. },
|
||||||
|
));
|
||||||
let i32_type = ctx.ctx.i32_type();
|
let i32_type = ctx.ctx.i32_type();
|
||||||
|
let zero = i32_type.const_zero();
|
||||||
let v = generator
|
let v = generator
|
||||||
.gen_expr(ctx, value)?
|
.gen_expr(ctx, value)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let index = generator
|
let len = ctx
|
||||||
|
.build_gep_and_load(v, &[zero, i32_type.const_int(1, false)])
|
||||||
|
.into_int_value();
|
||||||
|
let raw_index = generator
|
||||||
.gen_expr(ctx, slice)?
|
.gen_expr(ctx, slice)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
|
let raw_index = ctx.builder.build_int_s_extend(
|
||||||
|
raw_index,
|
||||||
|
generator.get_size_type(ctx.ctx),
|
||||||
|
"sext",
|
||||||
|
);
|
||||||
|
// handle negative index
|
||||||
|
let is_negative = ctx.builder.build_int_compare(
|
||||||
|
inkwell::IntPredicate::SLT,
|
||||||
|
raw_index,
|
||||||
|
generator.get_size_type(ctx.ctx).const_zero(),
|
||||||
|
"is_neg",
|
||||||
|
);
|
||||||
|
let adjusted = ctx.builder.build_int_add(raw_index, len, "adjusted");
|
||||||
|
let index = ctx
|
||||||
|
.builder
|
||||||
|
.build_select(is_negative, adjusted, raw_index, "index")
|
||||||
|
.into_int_value();
|
||||||
|
// unsigned less than is enough, because negative index after adjustment is
|
||||||
|
// bigger than the length (for unsigned cmp)
|
||||||
|
let bound_check = ctx.builder.build_int_compare(
|
||||||
|
inkwell::IntPredicate::ULT,
|
||||||
|
index,
|
||||||
|
len,
|
||||||
|
"inbound",
|
||||||
|
);
|
||||||
|
ctx.make_assert(
|
||||||
|
generator,
|
||||||
|
bound_check,
|
||||||
|
"0:IndexError",
|
||||||
|
"index {0} out of bounds 0:{1}",
|
||||||
|
[Some(raw_index), Some(len), None],
|
||||||
|
slice.location,
|
||||||
|
);
|
||||||
unsafe {
|
unsafe {
|
||||||
let arr_ptr = ctx
|
let arr_ptr = ctx
|
||||||
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_zero()])
|
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_zero()])
|
||||||
|
@ -102,7 +147,9 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
match &target.node {
|
match &target.node {
|
||||||
ExprKind::Tuple { elts, .. } => {
|
ExprKind::Tuple { elts, .. } => {
|
||||||
if let BasicValueEnum::StructValue(v) = value.to_basic_value_enum(ctx, generator)? {
|
if let BasicValueEnum::StructValue(v) =
|
||||||
|
value.to_basic_value_enum(ctx, generator, target.custom.unwrap())?
|
||||||
|
{
|
||||||
for (i, elt) in elts.iter().enumerate() {
|
for (i, elt) in elts.iter().enumerate() {
|
||||||
let v = ctx
|
let v = ctx
|
||||||
.builder
|
.builder
|
||||||
|
@ -121,11 +168,13 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
||||||
let ls = generator
|
let ls = generator
|
||||||
.gen_expr(ctx, ls)?
|
.gen_expr(ctx, ls)?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator, ls.custom.unwrap())?
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let (start, end, step) =
|
let (start, end, step) =
|
||||||
handle_slice_indices(lower, upper, step, ctx, generator, ls)?;
|
handle_slice_indices(lower, upper, step, ctx, generator, ls)?;
|
||||||
let value = value.to_basic_value_enum(ctx, generator)?.into_pointer_value();
|
let value = value
|
||||||
|
.to_basic_value_enum(ctx, generator, target.custom.unwrap())?
|
||||||
|
.into_pointer_value();
|
||||||
let ty =
|
let ty =
|
||||||
if let TypeEnum::TList { ty } = &*ctx.unifier.get_ty(target.custom.unwrap()) {
|
if let TypeEnum::TList { ty } = &*ctx.unifier.get_ty(target.custom.unwrap()) {
|
||||||
ctx.get_llvm_type(generator, *ty)
|
ctx.get_llvm_type(generator, *ty)
|
||||||
|
@ -133,15 +182,7 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let src_ind = handle_slice_indices(&None, &None, &None, ctx, generator, value)?;
|
let src_ind = handle_slice_indices(&None, &None, &None, ctx, generator, value)?;
|
||||||
list_slice_assignment(
|
list_slice_assignment(generator, ctx, ty, ls, (start, end, step), value, src_ind)
|
||||||
generator,
|
|
||||||
ctx,
|
|
||||||
ty,
|
|
||||||
ls,
|
|
||||||
(start, end, step),
|
|
||||||
value,
|
|
||||||
src_ind,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -155,7 +196,7 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
||||||
*static_value = Some(s.clone());
|
*static_value = Some(s.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let val = value.to_basic_value_enum(ctx, generator)?;
|
let val = value.to_basic_value_enum(ctx, generator, target.custom.unwrap())?;
|
||||||
ctx.builder.build_store(ptr, val);
|
ctx.builder.build_store(ptr, val);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -185,7 +226,11 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
||||||
// store loop bb information and restore it later
|
// store loop bb information and restore it later
|
||||||
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
|
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
|
||||||
|
|
||||||
let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
iter.custom.unwrap(),
|
||||||
|
)?;
|
||||||
if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) {
|
if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) {
|
||||||
// setup
|
// setup
|
||||||
let iter_val = iter_val.into_pointer_value();
|
let iter_val = iter_val.into_pointer_value();
|
||||||
|
@ -298,7 +343,11 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
|
||||||
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
|
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
test.custom.unwrap(),
|
||||||
|
)?;
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
||||||
} else {
|
} else {
|
||||||
|
@ -359,7 +408,11 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
|
||||||
};
|
};
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
test.custom.unwrap(),
|
||||||
|
)?;
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
||||||
} else {
|
} else {
|
||||||
|
@ -456,7 +509,7 @@ pub fn exn_constructor<'ctx, 'a>(
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
||||||
let (zelf_ty, zelf) = obj.unwrap();
|
let (zelf_ty, zelf) = obj.unwrap();
|
||||||
let zelf = zelf.to_basic_value_enum(ctx, generator)?.into_pointer_value();
|
let zelf = zelf.to_basic_value_enum(ctx, generator, zelf_ty)?.into_pointer_value();
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let zero = int32.const_zero();
|
let zero = int32.const_zero();
|
||||||
let zelf_id = {
|
let zelf_id = {
|
||||||
|
@ -479,14 +532,14 @@ pub fn exn_constructor<'ctx, 'a>(
|
||||||
let ptr =
|
let ptr =
|
||||||
ctx.builder.build_in_bounds_gep(zelf, &[zero, int32.const_int(5, false)], "exn.msg");
|
ctx.builder.build_in_bounds_gep(zelf, &[zero, int32.const_int(5, false)], "exn.msg");
|
||||||
let msg = if !args.is_empty() {
|
let msg = if !args.is_empty() {
|
||||||
args.remove(0).1.to_basic_value_enum(ctx, generator)?
|
args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.str)?
|
||||||
} else {
|
} else {
|
||||||
empty_string
|
empty_string
|
||||||
};
|
};
|
||||||
ctx.builder.build_store(ptr, msg);
|
ctx.builder.build_store(ptr, msg);
|
||||||
for i in [6, 7, 8].iter() {
|
for i in [6, 7, 8].iter() {
|
||||||
let value = if !args.is_empty() {
|
let value = if !args.is_empty() {
|
||||||
args.remove(0).1.to_basic_value_enum(ctx, generator)?
|
args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.int64)?
|
||||||
} else {
|
} else {
|
||||||
ctx.ctx.i64_type().const_zero().into()
|
ctx.ctx.i64_type().const_zero().into()
|
||||||
};
|
};
|
||||||
|
@ -908,7 +961,11 @@ pub fn gen_return<'ctx, 'a, G: CodeGenerator>(
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let value = value
|
let value = value
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|v| generator.gen_expr(ctx, v).and_then(|v| v.unwrap().to_basic_value_enum(ctx, generator)))
|
.map(|v_expr| {
|
||||||
|
generator.gen_expr(ctx, v_expr).and_then(|v| {
|
||||||
|
v.unwrap().to_basic_value_enum(ctx, generator, v_expr.custom.unwrap())
|
||||||
|
})
|
||||||
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
if let Some(return_target) = ctx.return_target {
|
if let Some(return_target) = ctx.return_target {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
|
@ -969,20 +1026,28 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
|
||||||
StmtKind::Try { .. } => gen_try(generator, ctx, stmt)?,
|
StmtKind::Try { .. } => gen_try(generator, ctx, stmt)?,
|
||||||
StmtKind::Raise { exc, .. } => {
|
StmtKind::Raise { exc, .. } => {
|
||||||
if let Some(exc) = exc {
|
if let Some(exc) = exc {
|
||||||
let exc =
|
let exc = generator.gen_expr(ctx, exc)?.unwrap().to_basic_value_enum(
|
||||||
generator.gen_expr(ctx, exc)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
ctx,
|
||||||
|
generator,
|
||||||
|
exc.custom.unwrap(),
|
||||||
|
)?;
|
||||||
gen_raise(generator, ctx, Some(&exc), stmt.location);
|
gen_raise(generator, ctx, Some(&exc), stmt.location);
|
||||||
} else {
|
} else {
|
||||||
gen_raise(generator, ctx, None, stmt.location);
|
gen_raise(generator, ctx, None, stmt.location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Assert { test, msg, .. } => {
|
StmtKind::Assert { test, msg, .. } => {
|
||||||
let test =
|
let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(
|
||||||
generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
ctx,
|
||||||
|
generator,
|
||||||
|
test.custom.unwrap(),
|
||||||
|
)?;
|
||||||
let err_msg = match msg {
|
let err_msg = match msg {
|
||||||
Some(msg) => {
|
Some(msg) => generator.gen_expr(ctx, msg)?.unwrap().to_basic_value_enum(
|
||||||
generator.gen_expr(ctx, msg)?.unwrap().to_basic_value_enum(ctx, generator)?
|
ctx,
|
||||||
}
|
generator,
|
||||||
|
msg.custom.unwrap(),
|
||||||
|
)?,
|
||||||
None => ctx.gen_string(generator, ""),
|
None => ctx.gen_string(generator, ""),
|
||||||
};
|
};
|
||||||
ctx.make_assert_impl(
|
ctx.make_assert_impl(
|
||||||
|
|
|
@ -71,6 +71,7 @@ pub trait StaticValue {
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
|
expected_ty: Type,
|
||||||
) -> Result<BasicValueEnum<'ctx>, String>;
|
) -> Result<BasicValueEnum<'ctx>, String>;
|
||||||
|
|
||||||
fn get_field<'ctx, 'a>(
|
fn get_field<'ctx, 'a>(
|
||||||
|
@ -78,6 +79,8 @@ pub trait StaticValue {
|
||||||
name: StrRef,
|
name: StrRef,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
) -> Option<ValueEnum<'ctx>>;
|
) -> Option<ValueEnum<'ctx>>;
|
||||||
|
|
||||||
|
fn get_tuple_element<'ctx>(&self, index: u32) -> Option<ValueEnum<'ctx>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -121,9 +124,10 @@ impl<'ctx> ValueEnum<'ctx> {
|
||||||
self,
|
self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
|
expected_ty: Type,
|
||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
match self {
|
match self {
|
||||||
ValueEnum::Static(v) => v.to_basic_value_enum(ctx, generator),
|
ValueEnum::Static(v) => v.to_basic_value_enum(ctx, generator, expected_ty),
|
||||||
ValueEnum::Dynamic(v) => Ok(v),
|
ValueEnum::Dynamic(v) => Ok(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,7 +367,7 @@ impl dyn SymbolResolver + Send + Sync {
|
||||||
unreachable!("expected class definition")
|
unreachable!("expected class definition")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&mut |id| format!("var{}", id),
|
&mut |id| format!("typevar{}", id),
|
||||||
&mut None,
|
&mut None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,7 +224,12 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, obj, _, _, generator| {
|
|ctx, obj, _, _, generator| {
|
||||||
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
|
let expect_ty = obj.clone().unwrap().0;
|
||||||
|
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
expect_ty,
|
||||||
|
)?;
|
||||||
if let BasicValueEnum::PointerValue(ptr) = obj_val {
|
if let BasicValueEnum::PointerValue(ptr) = obj_val {
|
||||||
Ok(Some(ctx.builder.build_is_not_null(ptr, "is_some").into()))
|
Ok(Some(ctx.builder.build_is_not_null(ptr, "is_some").into()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -244,7 +249,12 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, obj, _, _, generator| {
|
|ctx, obj, _, _, generator| {
|
||||||
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
|
let expect_ty = obj.clone().unwrap().0;
|
||||||
|
let obj_val = obj.unwrap().1.clone().to_basic_value_enum(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
expect_ty,
|
||||||
|
)?;
|
||||||
if let BasicValueEnum::PointerValue(ptr) = obj_val {
|
if let BasicValueEnum::PointerValue(ptr) = obj_val {
|
||||||
Ok(Some(ctx.builder.build_is_null(ptr, "is_none").into()))
|
Ok(Some(ctx.builder.build_is_null(ptr, "is_none").into()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -290,7 +300,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let float = ctx.primitives.float;
|
let float = ctx.primitives.float;
|
||||||
let boolean = ctx.primitives.bool;
|
let boolean = ctx.primitives.bool;
|
||||||
let arg_ty = fun.0.args[0].ty;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
Ok(if ctx.unifier.unioned(arg_ty, boolean) {
|
Ok(if ctx.unifier.unioned(arg_ty, boolean) {
|
||||||
Some(
|
Some(
|
||||||
ctx.builder
|
ctx.builder
|
||||||
|
@ -355,7 +365,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let float = ctx.primitives.float;
|
let float = ctx.primitives.float;
|
||||||
let boolean = ctx.primitives.bool;
|
let boolean = ctx.primitives.bool;
|
||||||
let arg_ty = fun.0.args[0].ty;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
Ok(
|
Ok(
|
||||||
if ctx.unifier.unioned(arg_ty, boolean)
|
if ctx.unifier.unioned(arg_ty, boolean)
|
||||||
|| ctx.unifier.unioned(arg_ty, uint32)
|
|| ctx.unifier.unioned(arg_ty, uint32)
|
||||||
|
@ -422,7 +432,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let float = ctx.primitives.float;
|
let float = ctx.primitives.float;
|
||||||
let boolean = ctx.primitives.bool;
|
let boolean = ctx.primitives.bool;
|
||||||
let arg_ty = fun.0.args[0].ty;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
let res = if ctx.unifier.unioned(arg_ty, boolean) {
|
let res = if ctx.unifier.unioned(arg_ty, boolean) {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_int_z_extend(arg.into_int_value(), ctx.ctx.i64_type(), "zext")
|
.build_int_z_extend(arg.into_int_value(), ctx.ctx.i64_type(), "zext")
|
||||||
|
@ -474,7 +484,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let float = ctx.primitives.float;
|
let float = ctx.primitives.float;
|
||||||
let boolean = ctx.primitives.bool;
|
let boolean = ctx.primitives.bool;
|
||||||
let arg_ty = fun.0.args[0].ty;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
let res = if ctx.unifier.unioned(arg_ty, int32)
|
let res = if ctx.unifier.unioned(arg_ty, int32)
|
||||||
|| ctx.unifier.unioned(arg_ty, uint32)
|
|| ctx.unifier.unioned(arg_ty, uint32)
|
||||||
|| ctx.unifier.unioned(arg_ty, boolean)
|
|| ctx.unifier.unioned(arg_ty, boolean)
|
||||||
|
@ -521,7 +531,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let boolean = ctx.primitives.bool;
|
let boolean = ctx.primitives.bool;
|
||||||
let float = ctx.primitives.float;
|
let float = ctx.primitives.float;
|
||||||
let arg_ty = fun.0.args[0].ty;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
Ok(
|
Ok(
|
||||||
if ctx.unifier.unioned(arg_ty, boolean)
|
if ctx.unifier.unioned(arg_ty, boolean)
|
||||||
|| ctx.unifier.unioned(arg_ty, int32)
|
|| ctx.unifier.unioned(arg_ty, int32)
|
||||||
|
@ -557,7 +567,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, _, args, generator| {
|
|ctx, _, _, args, generator| {
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
|
||||||
let round_intrinsic =
|
let round_intrinsic =
|
||||||
ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| {
|
ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| {
|
||||||
let float = ctx.ctx.f64_type();
|
let float = ctx.ctx.f64_type();
|
||||||
|
@ -597,7 +607,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, _, args, generator| {
|
|ctx, _, _, args, generator| {
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
|
||||||
let round_intrinsic =
|
let round_intrinsic =
|
||||||
ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| {
|
ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| {
|
||||||
let float = ctx.ctx.f64_type();
|
let float = ctx.ctx.f64_type();
|
||||||
|
@ -655,19 +665,20 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let mut step = None;
|
let mut step = None;
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let zero = int32.const_zero();
|
let zero = int32.const_zero();
|
||||||
|
let ty_i32 = ctx.primitives.int32;
|
||||||
for (i, arg) in args.iter().enumerate() {
|
for (i, arg) in args.iter().enumerate() {
|
||||||
if arg.0 == Some("start".into()) {
|
if arg.0 == Some("start".into()) {
|
||||||
start = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
|
start = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||||
} else if arg.0 == Some("stop".into()) {
|
} else if arg.0 == Some("stop".into()) {
|
||||||
stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
|
stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||||
} else if arg.0 == Some("step".into()) {
|
} else if arg.0 == Some("step".into()) {
|
||||||
step = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
|
step = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||||
} else if i == 0 {
|
} else if i == 0 {
|
||||||
start = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
|
start = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||||
} else if i == 1 {
|
} else if i == 1 {
|
||||||
stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
|
stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||||
} else if i == 2 {
|
} else if i == 2 {
|
||||||
step = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
|
step = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let step = match step {
|
let step = match step {
|
||||||
|
@ -734,8 +745,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
instance_to_stmt: Default::default(),
|
instance_to_stmt: Default::default(),
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, _, args, generator| {
|
|ctx, _, fun, args, generator| {
|
||||||
Ok(Some(args[0].1.clone().to_basic_value_enum(ctx, generator)?))
|
let arg_ty = fun.0.args[0].ty;
|
||||||
|
Ok(Some(args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?))
|
||||||
},
|
},
|
||||||
)))),
|
)))),
|
||||||
loc: None,
|
loc: None,
|
||||||
|
@ -759,7 +771,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let float = ctx.primitives.float;
|
let float = ctx.primitives.float;
|
||||||
let boolean = ctx.primitives.bool;
|
let boolean = ctx.primitives.bool;
|
||||||
let arg_ty = fun.0.args[0].ty;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
Ok(if ctx.unifier.unioned(arg_ty, boolean) {
|
Ok(if ctx.unifier.unioned(arg_ty, boolean) {
|
||||||
Some(arg)
|
Some(arg)
|
||||||
} else if ctx.unifier.unioned(arg_ty, int32) {
|
} else if ctx.unifier.unioned(arg_ty, int32) {
|
||||||
|
@ -817,7 +829,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, _, args, generator| {
|
|ctx, _, _, args, generator| {
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
|
||||||
let floor_intrinsic =
|
let floor_intrinsic =
|
||||||
ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| {
|
ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| {
|
||||||
let float = ctx.ctx.f64_type();
|
let float = ctx.ctx.f64_type();
|
||||||
|
@ -857,7 +869,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, _, args, generator| {
|
|ctx, _, _, args, generator| {
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
|
||||||
let floor_intrinsic =
|
let floor_intrinsic =
|
||||||
ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| {
|
ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| {
|
||||||
let float = ctx.ctx.f64_type();
|
let float = ctx.ctx.f64_type();
|
||||||
|
@ -897,7 +909,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, _, args, generator| {
|
|ctx, _, _, args, generator| {
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
|
||||||
let ceil_intrinsic =
|
let ceil_intrinsic =
|
||||||
ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| {
|
ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| {
|
||||||
let float = ctx.ctx.f64_type();
|
let float = ctx.ctx.f64_type();
|
||||||
|
@ -937,7 +949,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, _, args, generator| {
|
|ctx, _, _, args, generator| {
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, ctx.primitives.float)?;
|
||||||
let ceil_intrinsic =
|
let ceil_intrinsic =
|
||||||
ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| {
|
ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| {
|
||||||
let float = ctx.ctx.f64_type();
|
let float = ctx.ctx.f64_type();
|
||||||
|
@ -989,7 +1001,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
|ctx, _, fun, args, generator| {
|
|ctx, _, fun, args, generator| {
|
||||||
let range_ty = ctx.primitives.range;
|
let range_ty = ctx.primitives.range;
|
||||||
let arg_ty = fun.0.args[0].ty;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
Ok(if ctx.unifier.unioned(arg_ty, range_ty) {
|
Ok(if ctx.unifier.unioned(arg_ty, range_ty) {
|
||||||
let arg = arg.into_pointer_value();
|
let arg = arg.into_pointer_value();
|
||||||
let (start, end, step) = destructure_range(ctx, arg);
|
let (start, end, step) = destructure_range(ctx, arg);
|
||||||
|
@ -1043,8 +1055,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
|
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
|
||||||
let m_ty = fun.0.args[0].ty;
|
let m_ty = fun.0.args[0].ty;
|
||||||
let n_ty = fun.0.args[1].ty;
|
let n_ty = fun.0.args[1].ty;
|
||||||
let m_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let m_val = args[0].1.clone().to_basic_value_enum(ctx, generator, m_ty)?;
|
||||||
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator)?;
|
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator, n_ty)?;
|
||||||
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
|
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
|
||||||
let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) {
|
let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) {
|
||||||
("llvm.umin.i1", llvm_i1)
|
("llvm.umin.i1", llvm_i1)
|
||||||
|
@ -1105,8 +1117,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
|
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
|
||||||
let m_ty = fun.0.args[0].ty;
|
let m_ty = fun.0.args[0].ty;
|
||||||
let n_ty = fun.0.args[1].ty;
|
let n_ty = fun.0.args[1].ty;
|
||||||
let m_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let m_val = args[0].1.clone().to_basic_value_enum(ctx, generator, m_ty)?;
|
||||||
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator)?;
|
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator, n_ty)?;
|
||||||
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
|
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
|
||||||
let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) {
|
let (fun_name, arg_ty) = if is_type(m_ty, n_ty) && is_type(n_ty, boolean) {
|
||||||
("llvm.umax.i1", llvm_i1)
|
("llvm.umax.i1", llvm_i1)
|
||||||
|
@ -1163,7 +1175,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
let llvm_i64 = ctx.ctx.i64_type().as_basic_type_enum();
|
let llvm_i64 = ctx.ctx.i64_type().as_basic_type_enum();
|
||||||
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
|
let llvm_f64 = ctx.ctx.f64_type().as_basic_type_enum();
|
||||||
let n_ty = fun.0.args[0].ty;
|
let n_ty = fun.0.args[0].ty;
|
||||||
let n_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let n_val = args[0].1.clone().to_basic_value_enum(ctx, generator, n_ty)?;
|
||||||
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
|
let mut is_type = |a: Type, b: Type| ctx.unifier.unioned(a, b);
|
||||||
let mut is_float = false;
|
let mut is_float = false;
|
||||||
let (fun_name, arg_ty) =
|
let (fun_name, arg_ty) =
|
||||||
|
@ -1220,8 +1232,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
instance_to_stmt: Default::default(),
|
instance_to_stmt: Default::default(),
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, _, _fun, args, generator| {
|
|ctx, _, fun, args, generator| {
|
||||||
let arg_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
|
let arg_val = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
let alloca = ctx.builder.build_alloca(arg_val.get_type(), "alloca_some");
|
let alloca = ctx.builder.build_alloca(arg_val.get_type(), "alloca_some");
|
||||||
ctx.builder.build_store(alloca, arg_val);
|
ctx.builder.build_store(alloca, arg_val);
|
||||||
Ok(Some(alloca.into()))
|
Ok(Some(alloca.into()))
|
||||||
|
|
|
@ -434,11 +434,11 @@ impl TopLevelComposer {
|
||||||
|
|
||||||
// check if all are unique type vars
|
// check if all are unique type vars
|
||||||
let all_unique_type_var = {
|
let all_unique_type_var = {
|
||||||
let mut occured_type_var_id: HashSet<u32> = HashSet::new();
|
let mut occurred_type_var_id: HashSet<u32> = HashSet::new();
|
||||||
type_vars.iter().all(|x| {
|
type_vars.iter().all(|x| {
|
||||||
let ty = unifier.get_ty(*x);
|
let ty = unifier.get_ty(*x);
|
||||||
if let TypeEnum::TVar { id, .. } = ty.as_ref() {
|
if let TypeEnum::TVar { id, .. } = ty.as_ref() {
|
||||||
occured_type_var_id.insert(*id)
|
occurred_type_var_id.insert(*id)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -536,7 +536,7 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
has_base = true;
|
has_base = true;
|
||||||
|
|
||||||
// the function parse_ast_to make sure that no type var occured in
|
// the function parse_ast_to make sure that no type var occurred in
|
||||||
// bast_ty if it is a CustomClassKind
|
// bast_ty if it is a CustomClassKind
|
||||||
let base_ty = parse_ast_to_type_annotation_kinds(
|
let base_ty = parse_ast_to_type_annotation_kinds(
|
||||||
class_resolver,
|
class_resolver,
|
||||||
|
@ -696,7 +696,7 @@ impl TopLevelComposer {
|
||||||
return Err(errors.into_iter().sorted().join("\n----------\n"));
|
return Err(errors.into_iter().sorted().join("\n----------\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle the inheritanced methods and fields
|
// handle the inherited methods and fields
|
||||||
// Note: we cannot defer error handling til the end of the loop, because there is loop
|
// Note: we cannot defer error handling til the end of the loop, because there is loop
|
||||||
// carried dependency, ignoring the error (temporarily) will cause all assumptions to break
|
// carried dependency, ignoring the error (temporarily) will cause all assumptions to break
|
||||||
// and produce weird error messages
|
// and produce weird error messages
|
||||||
|
@ -825,9 +825,9 @@ impl TopLevelComposer {
|
||||||
let mut function_var_map: HashMap<u32, Type> = HashMap::new();
|
let mut function_var_map: HashMap<u32, Type> = HashMap::new();
|
||||||
let arg_types = {
|
let arg_types = {
|
||||||
// make sure no duplicate parameter
|
// make sure no duplicate parameter
|
||||||
let mut defined_paramter_name: HashSet<_> = HashSet::new();
|
let mut defined_parameter_name: HashSet<_> = HashSet::new();
|
||||||
for x in args.args.iter() {
|
for x in args.args.iter() {
|
||||||
if !defined_paramter_name.insert(x.node.arg)
|
if !defined_parameter_name.insert(x.node.arg)
|
||||||
|| keyword_list.contains(&x.node.arg)
|
|| keyword_list.contains(&x.node.arg)
|
||||||
{
|
{
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
|
@ -1074,10 +1074,10 @@ impl TopLevelComposer {
|
||||||
|
|
||||||
let arg_types: Vec<FuncArg> = {
|
let arg_types: Vec<FuncArg> = {
|
||||||
// check method parameters cannot have same name
|
// check method parameters cannot have same name
|
||||||
let mut defined_paramter_name: HashSet<_> = HashSet::new();
|
let mut defined_parameter_name: HashSet<_> = HashSet::new();
|
||||||
let zelf: StrRef = "self".into();
|
let zelf: StrRef = "self".into();
|
||||||
for x in args.args.iter() {
|
for x in args.args.iter() {
|
||||||
if !defined_paramter_name.insert(x.node.arg)
|
if !defined_parameter_name.insert(x.node.arg)
|
||||||
|| (keyword_list.contains(&x.node.arg) && x.node.arg != zelf)
|
|| (keyword_list.contains(&x.node.arg) && x.node.arg != zelf)
|
||||||
{
|
{
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
|
@ -1088,13 +1088,13 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if name == &"__init__".into() && !defined_paramter_name.contains(&zelf) {
|
if name == &"__init__".into() && !defined_parameter_name.contains(&zelf) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"__init__ method must have a `self` parameter (at {})",
|
"__init__ method must have a `self` parameter (at {})",
|
||||||
b.location
|
b.location
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if !defined_paramter_name.contains(&zelf) {
|
if !defined_parameter_name.contains(&zelf) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"class method must have a `self` parameter (at {})",
|
"class method must have a `self` parameter (at {})",
|
||||||
b.location
|
b.location
|
||||||
|
@ -1227,7 +1227,7 @@ impl TopLevelComposer {
|
||||||
dummy_return_type
|
dummy_return_type
|
||||||
} else {
|
} else {
|
||||||
// if do not have return annotation, return none
|
// if do not have return annotation, return none
|
||||||
// for uniform handling, still use type annoatation
|
// for uniform handling, still use type annotation
|
||||||
let dummy_return_type = unifier.get_dummy_var().0;
|
let dummy_return_type = unifier.get_dummy_var().0;
|
||||||
type_var_to_concrete_def.insert(
|
type_var_to_concrete_def.insert(
|
||||||
dummy_return_type,
|
dummy_return_type,
|
||||||
|
@ -1468,7 +1468,7 @@ impl TopLevelComposer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// step 5, analyze and call type inferecer to fill the `instance_to_stmt` of topleveldef::function
|
/// step 5, analyze and call type inferencer to fill the `instance_to_stmt` of topleveldef::function
|
||||||
fn analyze_function_instance(&mut self) -> Result<(), String> {
|
fn analyze_function_instance(&mut self) -> Result<(), String> {
|
||||||
// first get the class contructor type correct for the following type check in function body
|
// first get the class contructor type correct for the following type check in function body
|
||||||
// also do class field instantiation check
|
// also do class field instantiation check
|
||||||
|
@ -1906,7 +1906,7 @@ impl TopLevelComposer {
|
||||||
unreachable!("must be class id here")
|
unreachable!("must be class id here")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&mut |id| format!("tvar{}", id),
|
&mut |id| format!("typevar{}", id),
|
||||||
&mut None,
|
&mut None,
|
||||||
);
|
);
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
|
|
|
@ -149,7 +149,7 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// already include the definition_id of itself inside the ancestors vector
|
/// already include the definition_id of itself inside the ancestors vector
|
||||||
/// when first regitering, the type_vars, fields, methods, ancestors are invalid
|
/// when first registering, the type_vars, fields, methods, ancestors are invalid
|
||||||
pub fn make_top_level_class_def(
|
pub fn make_top_level_class_def(
|
||||||
index: usize,
|
index: usize,
|
||||||
resolver: Option<Arc<dyn SymbolResolver + Send + Sync>>,
|
resolver: Option<Arc<dyn SymbolResolver + Send + Sync>>,
|
||||||
|
|
|
@ -9,7 +9,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[var7]\", \"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: [\"var7\"]\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B[typevar7]\", \"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: [\"typevar7\"]\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,7 +5,7 @@ expression: res_vec
|
||||||
|
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A[var6, var7]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[bool, float], b:B], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\")],\ntype_vars: [\"var6\", \"var7\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A[typevar6, typevar7]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[bool, float], b:B], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\")],\ntype_vars: [\"typevar6\", \"typevar7\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[bool, float], b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[bool, float], b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[bool, float]], A[bool, int32]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[bool, float]], 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[bool, float]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[int32, list[B]]], tuple[A[bool, virtual[A[B, int32]]], B]]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[int32, list[B]]], tuple[A[bool, virtual[A[B, int32]]], B]]\")],\ntype_vars: []\n}\n",
|
||||||
|
|
|
@ -763,7 +763,7 @@ fn make_internal_resolver_with_tvar(
|
||||||
(name, {
|
(name, {
|
||||||
let (ty, id) = unifier.get_fresh_var_with_range(range.as_slice(), None, None);
|
let (ty, id) = unifier.get_fresh_var_with_range(range.as_slice(), None, None);
|
||||||
if print {
|
if print {
|
||||||
println!("{}: {:?}, tvar{}", name, ty, id);
|
println!("{}: {:?}, typevar{}", name, ty, id);
|
||||||
}
|
}
|
||||||
ty
|
ty
|
||||||
})
|
})
|
||||||
|
@ -791,7 +791,7 @@ impl<'a> Fold<Option<Type>> for TypeToStringFolder<'a> {
|
||||||
self.unifier.internal_stringify(
|
self.unifier.internal_stringify(
|
||||||
ty,
|
ty,
|
||||||
&mut |id| format!("class{}", id.to_string()),
|
&mut |id| format!("class{}", id.to_string()),
|
||||||
&mut |id| format!("tvar{}", id.to_string()),
|
&mut |id| format!("typevar{}", id.to_string()),
|
||||||
&mut None,
|
&mut None,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -356,7 +356,7 @@ pub fn get_type_from_type_annotation_kinds(
|
||||||
unifier.internal_stringify(
|
unifier.internal_stringify(
|
||||||
p,
|
p,
|
||||||
&mut |id| format!("class{}", id),
|
&mut |id| format!("class{}", id),
|
||||||
&mut |id| format!("tvar{}", id),
|
&mut |id| format!("typevar{}", id),
|
||||||
&mut None
|
&mut None
|
||||||
),
|
),
|
||||||
*id
|
*id
|
||||||
|
@ -436,7 +436,7 @@ pub fn get_type_from_type_annotation_kinds(
|
||||||
/// the type of `self` should be similar to `A[T, V]`, where `T`, `V`
|
/// the type of `self` should be similar to `A[T, V]`, where `T`, `V`
|
||||||
/// considered to be type variables associated with the class \
|
/// considered to be type variables associated with the class \
|
||||||
/// \
|
/// \
|
||||||
/// But note that here we do not make a duplication of `T`, `V`, we direclty
|
/// But note that here we do not make a duplication of `T`, `V`, we directly
|
||||||
/// use them as they are in the TopLevelDef::Class since those in the
|
/// use them as they are in the TopLevelDef::Class since those in the
|
||||||
/// TopLevelDef::Class.type_vars will be substitute later when seeing applications/instantiations
|
/// TopLevelDef::Class.type_vars will be substitute later when seeing applications/instantiations
|
||||||
/// the Type of their fields and methods will also be subst when application/instantiation
|
/// the Type of their fields and methods will also be subst when application/instantiation
|
||||||
|
|
|
@ -16,7 +16,7 @@ use crate::toplevel::{DefinitionId, TopLevelContext, TopLevelDef};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
/// Handle for a type, implementated as a key in the unification table.
|
/// Handle for a type, implemented as a key in the unification table.
|
||||||
pub type Type = UnificationKey;
|
pub type Type = UnificationKey;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
@ -830,7 +830,7 @@ impl Unifier {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
&mut |id| format!("var{}", id),
|
&mut |id| format!("typevar{}", id),
|
||||||
notes,
|
notes,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,14 +302,14 @@ fn test_unify(
|
||||||
("v1", "Record[a=float,b=int]"),
|
("v1", "Record[a=float,b=int]"),
|
||||||
("v2", "Foo[v3]"),
|
("v2", "Foo[v3]"),
|
||||||
],
|
],
|
||||||
(("v1", "v2"), "`3[var4]::b` field/method does not exist")
|
(("v1", "v2"), "`3[typevar4]::b` field/method does not exist")
|
||||||
; "record obj merge"
|
; "record obj merge"
|
||||||
)]
|
)]
|
||||||
/// Test cases for invalid unifications.
|
/// Test cases for invalid unifications.
|
||||||
fn test_invalid_unification(
|
fn test_invalid_unification(
|
||||||
variable_count: u32,
|
variable_count: u32,
|
||||||
unify_pairs: &[(&'static str, &'static str)],
|
unify_pairs: &[(&'static str, &'static str)],
|
||||||
errornous_pair: ((&'static str, &'static str), &'static str),
|
erroneous_pair: ((&'static str, &'static str), &'static str),
|
||||||
) {
|
) {
|
||||||
let mut env = TestEnvironment::new();
|
let mut env = TestEnvironment::new();
|
||||||
let mut mapping = HashMap::new();
|
let mut mapping = HashMap::new();
|
||||||
|
@ -326,11 +326,11 @@ fn test_invalid_unification(
|
||||||
pairs.push((t1, t2));
|
pairs.push((t1, t2));
|
||||||
}
|
}
|
||||||
let (t1, t2) =
|
let (t1, t2) =
|
||||||
(env.parse(errornous_pair.0 .0, &mapping), env.parse(errornous_pair.0 .1, &mapping));
|
(env.parse(erroneous_pair.0 .0, &mapping), env.parse(erroneous_pair.0 .1, &mapping));
|
||||||
for (a, b) in pairs {
|
for (a, b) in pairs {
|
||||||
env.unifier.unify(a, b).unwrap();
|
env.unifier.unify(a, b).unwrap();
|
||||||
}
|
}
|
||||||
assert_eq!(env.unify(t1, t2), Err(errornous_pair.1.to_string()));
|
assert_eq!(env.unify(t1, t2), Err(erroneous_pair.1.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -445,7 +445,7 @@ fn test_typevar_range() {
|
||||||
// where v in (int, list[v1]), v1 in (int, bool)
|
// where v in (int, list[v1]), v1 in (int, bool)
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.unify(float_list, v),
|
env.unify(float_list, v),
|
||||||
Err("Expected any one of these types: 0, list[var5], but got list[1]\n\nNotes:\n var5 ∈ {0, 2}".to_string())
|
Err("Expected any one of these types: 0, list[typevar5], but got list[1]\n\nNotes:\n typevar5 ∈ {0, 2}".to_string())
|
||||||
);
|
);
|
||||||
|
|
||||||
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).0;
|
let a = env.unifier.get_fresh_var_with_range(&[int, float], None, None).0;
|
||||||
|
@ -504,9 +504,9 @@ fn test_rigid_var() {
|
||||||
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: var3 and var2".to_string()));
|
assert_eq!(env.unify(a, b), Err("Incompatible types: typevar3 and typevar2".to_string()));
|
||||||
env.unifier.unify(list_a, list_x).unwrap();
|
env.unifier.unify(list_a, list_x).unwrap();
|
||||||
assert_eq!(env.unify(list_x, list_int), Err("Incompatible types: 0 and var2".to_string()));
|
assert_eq!(env.unify(list_x, list_int), Err("Incompatible types: 0 and typevar2".to_string()));
|
||||||
|
|
||||||
env.unifier.replace_rigid_var(a, int);
|
env.unifier.replace_rigid_var(a, int);
|
||||||
env.unifier.unify(list_x, list_int).unwrap();
|
env.unifier.unify(list_x, list_int).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue