Compare commits

..

2 Commits

Author SHA1 Message Date
wylited a5efba75ba nac3core: toplevel | add enumerate as a keyword for functions 2022-04-11 14:41:26 +08:00
wylited eeeccfd656 add extra builtin types for tuples and lists 2022-04-10 11:44:29 +08:00
20 changed files with 257 additions and 414 deletions

16
Cargo.lock generated
View File

@ -422,9 +422,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.122" version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -740,9 +740,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.37" version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [ dependencies = [
"unicode-xid", "unicode-xid",
] ]
@ -797,9 +797,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.18" version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -1035,9 +1035,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.91" version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1649619156, "lastModified": 1649024309,
"narHash": "sha256-p0q4zpuKMwrzGF+5ZU7Thnpac5TinhDI9jr2mBxhV4w=", "narHash": "sha256-AWbvj/NHZXVwAnHaVOFlxg7tcNerEKrKBmgGfztSHWM=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e7d63bd0d50df412f5a1d8acfa3caae75522e347", "rev": "af0a9bc0e5341855518e9c1734d7ef913e5138b9",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -1,4 +1,10 @@
from min_artiq import * from min_artiq import *
from numpy import int32, int64
@extern
def output_int(x: int32):
...
@nac3 @nac3

View File

@ -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, end.custom.unwrap())?; let old_end = self.gen_expr(ctx, &end)?.unwrap().to_basic_value_enum(ctx, self)?;
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, start.custom.unwrap())?; let start_val = self.gen_expr(ctx, &start)?.unwrap().to_basic_value_enum(ctx, self)?;
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, old_start.custom.unwrap())? self.gen_expr(ctx, old_start)?.unwrap().to_basic_value_enum(ctx, self)?
} else { } else {
self.timeline.emit_now_mu(ctx) self.timeline.emit_now_mu(ctx)
}; };
@ -174,10 +174,8 @@ 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 = self let end_val =
.gen_expr(ctx, &end_expr)? self.gen_expr(ctx, &end_expr)?.unwrap().to_basic_value_enum(ctx, self)?;
.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() {
@ -188,7 +186,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, old_end.custom.unwrap())?; .to_basic_value_enum(ctx, self)?;
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();
@ -373,7 +371,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, arg.ty)) .map(|arg| mapping.remove(&arg.name).unwrap().to_basic_value_enum(ctx, generator))
.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 {
@ -513,13 +511,11 @@ 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, obj_id, .. } TypeEnum::TObj { fields, .. } => {
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, ty)?.unwrap(); let obj = inner_resolver.get_obj_value(py, val, ctx, generator)?.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
@ -544,7 +540,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, ty)?.unwrap())); values.push((ty, inner_resolver.get_obj_value(py, val, ctx, generator)?.unwrap()));
} }
}, },
_ => {} _ => {}

View File

@ -65,7 +65,6 @@ 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,
@ -329,9 +328,8 @@ impl Nac3 {
ret: primitive.none, ret: primitive.none,
vars: HashMap::new(), vars: HashMap::new(),
}, },
Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| { Arc::new(GenCall::new(Box::new(move |ctx, _, _, args, generator| {
let arg_ty = fun.0.args[0].ty; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator).unwrap();
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)
}))), }))),
@ -347,9 +345,8 @@ impl Nac3 {
ret: primitive.none, ret: primitive.none,
vars: HashMap::new(), vars: HashMap::new(),
}, },
Arc::new(GenCall::new(Box::new(move |ctx, _, fun, args, generator| { Arc::new(GenCall::new(Box::new(move |ctx, _, _, args, generator| {
let arg_ty = fun.0.args[0].ty; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator).unwrap();
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)
}))), }))),
@ -398,7 +395,6 @@ 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"),

View File

@ -131,7 +131,6 @@ 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 {
@ -151,7 +150,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, expected_ty) .get_obj_value(py, self.value.as_ref(py), ctx, generator)
.map(Option::unwrap) .map(Option::unwrap)
}).map_err(|e| e.to_string()) }).map_err(|e| e.to_string())
} }
@ -170,16 +169,6 @@ 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();
@ -212,28 +201,6 @@ 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 {
@ -302,8 +269,6 @@ 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 {
@ -579,7 +544,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(*ty), &*unifier.get_ty(extracted_ty),
TypeEnum::TVar { fields: None, range, .. } TypeEnum::TVar { fields: None, range, .. }
if range.is_empty() if range.is_empty()
)); ));
@ -727,7 +692,6 @@ 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)?;
@ -757,7 +721,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 || ty_id == self.primitive_ids.float64 { } else if ty_id == self.primitive_ids.float {
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));
@ -770,14 +734,20 @@ impl InnerResolver {
} }
let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?; let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?;
let elem_ty = let ty = if len == 0 {
if let TypeEnum::TList { ty } = ctx.unifier.get_ty_immutable(expected_ty).as_ref() ctx.primitives.int32
{
*ty
} else { } else {
unreachable!("must be list") self.get_list_elem_type(
py,
obj,
len,
&mut ctx.unifier,
&ctx.top_level.definitions.read(),
&ctx.primitives,
)?
.unwrap()
}; };
let ty = ctx.get_llvm_type(generator, elem_ty); let ty = ctx.get_llvm_type(generator, 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
@ -796,13 +766,8 @@ impl InnerResolver {
let arr: Result<Option<Vec<_>>, _> = (0..len) let arr: Result<Option<Vec<_>>, _> = (0..len)
.map(|i| { .map(|i| {
obj obj.get_item(i).and_then(|elem| self.get_obj_value(py, elem, ctx, generator).map_err(
.get_item(i) |e| super::CompileError::new_err(format!("Error getting element {}: {}", i, e))))
.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();
@ -843,48 +808,21 @@ 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 {
if let TypeEnum::TTuple { ty } = ctx.unifier.get_ty_immutable(expected_ty).as_ref() { let elements: &PyTuple = obj.cast_as()?;
let tup_tys = ty.iter(); let val: Result<Option<Vec<_>>, _> =
let elements: &PyTuple = obj.cast_as()?; elements.iter().enumerate().map(|(i, elem)| self.get_obj_value(py, elem, ctx, generator).map_err(|e|
assert_eq!(elements.len(), tup_tys.len()); super::CompileError::new_err(format!("Error getting element {}: {}", i, e)))).collect();
let val: Result<Option<Vec<_>>, _> = let val = val?.unwrap();
elements let val = ctx.ctx.const_struct(&val, false);
.iter() Ok(Some(val.into()))
.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 // for option type, just a null ptr, whose type needs to be casted in codegen
Ok(Some( // according to the type info attached in the ast
ctx.get_llvm_type(generator, option_val_ty) Ok(Some(ctx.ctx.i8_type().ptr_type(AddressSpace::Generic).const_null().into()))
.ptr_type(AddressSpace::Generic)
.const_null()
.into(),
))
} else { } else {
match self match self
.get_obj_value(py, obj.getattr("_nac3_option").unwrap(), ctx, generator, option_val_ty) .get_obj_value(py, obj.getattr("_nac3_option").unwrap(), ctx, generator)
.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: {}",
@ -943,8 +881,23 @@ impl InnerResolver {
let values: Result<Option<Vec<_>>, _> = fields let values: Result<Option<Vec<_>>, _> = fields
.iter() .iter()
.map(|(name, ty, _)| { .map(|(name, ty, _)| {
self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx, generator, *ty) let v = self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx, generator)
.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?;
@ -987,7 +940,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 || ty_id == self.primitive_ids.float64 { } else if ty_id == self.primitive_ids.float {
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 {

View File

@ -150,7 +150,11 @@ 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);
actual_ptr_type.const_null().into() self.builder.build_bitcast(
self.ctx.i8_type().ptr_type(AddressSpace::Generic).const_null(),
actual_ptr_type,
"default_opt_none",
)
} }
} }
} }
@ -639,14 +643,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(), arg.ty)).collect_vec(); fun.0.args.iter().map(|arg| mapping.remove(&arg.name).unwrap()).collect_vec();
if let Some(obj) = &obj { if let Some(obj) = &obj {
real_params.insert(0, (obj.1.clone(), obj.0)); real_params.insert(0, obj.1.clone());
} }
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 {
@ -678,7 +682,7 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
}; };
param_vals = real_params param_vals = real_params
.into_iter() .into_iter()
.map(|(p, t)| p.to_basic_value_enum(ctx, generator, t)) .map(|p| p.to_basic_value_enum(ctx, generator))
.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())
} }
@ -791,7 +795,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, iter.custom.unwrap())?; let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(ctx, generator)?;
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();
@ -896,7 +900,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, cond.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.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);
@ -905,7 +909,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, elt.custom.unwrap())?; let val = elem.to_basic_value_enum(ctx, generator)?;
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"));
@ -930,8 +934,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, left.custom.unwrap())?; let left = generator.gen_expr(ctx, left)?.unwrap().to_basic_value_enum(ctx, generator)?;
let right = generator.gen_expr(ctx, right)?.unwrap().to_basic_value_enum(ctx, generator, right.custom.unwrap())?; let right = generator.gen_expr(ctx, right)?.unwrap().to_basic_value_enum(ctx, generator)?;
// 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
@ -995,7 +999,25 @@ 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();
resolver.get_symbol_value(*id, ctx).unwrap() let val = 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, .. } => {
@ -1006,10 +1028,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( .map_or_else(Err, |v| v.unwrap().to_basic_value_enum(ctx, generator))
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() {
@ -1042,7 +1061,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, x.custom.unwrap())) .map_or_else(Err, |v| v.unwrap().to_basic_value_enum(ctx, generator))
}) })
.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();
@ -1064,7 +1083,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, value.custom.unwrap())?; let v = v.to_basic_value_enum(ctx, generator)?;
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(),
@ -1085,7 +1104,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, values[0].custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.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");
@ -1101,7 +1120,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, values[1].custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.into_int_value(); .into_int_value();
ctx.builder.build_unconditional_branch(cont_bb); ctx.builder.build_unconditional_branch(cont_bb);
(a, b) (a, b)
@ -1111,7 +1130,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, values[1].custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.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);
@ -1129,9 +1148,7 @@ 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)? generator.gen_expr(ctx, operand)?.unwrap().to_basic_value_enum(ctx, generator)?;
.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 {
@ -1191,11 +1208,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, lhs.custom.unwrap())?, .to_basic_value_enum(ctx, generator)?,
generator generator
.gen_expr(ctx, rhs)? .gen_expr(ctx, rhs)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?, .to_basic_value_enum(ctx, generator)?,
) { ) {
(lhs, rhs) (lhs, rhs)
} else { } else {
@ -1219,11 +1236,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, lhs.custom.unwrap())?, .to_basic_value_enum(ctx, generator)?,
generator generator
.gen_expr(ctx, rhs)? .gen_expr(ctx, rhs)?
.unwrap() .unwrap()
.to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?, .to_basic_value_enum(ctx, generator)?,
) { ) {
(lhs, rhs) (lhs, rhs)
} else { } else {
@ -1251,7 +1268,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, test.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.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;
@ -1271,7 +1288,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, body.custom.unwrap())?; let a = a.unwrap().to_basic_value_enum(ctx, generator)?;
Some(ctx.builder.build_store(v, a)) Some(ctx.builder.build_store(v, a))
} }
}; };
@ -1281,7 +1298,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, orelse.custom.unwrap())?; let b = b.unwrap().to_basic_value_enum(ctx, generator)?;
Some(ctx.builder.build_store(v, b)) Some(ctx.builder.build_store(v, b))
} }
}; };
@ -1354,66 +1371,23 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
} }
}; };
// directly generate code for option.unwrap // directly generate code for option.unwrap
// since it needs to return static value to optimize for kernel invariant // since it needs location information from ast
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)
{ {
match val { if let BasicValueEnum::PointerValue(ptr) = val.to_basic_value_enum(ctx, generator)? {
ValueEnum::Static(v) => match v.get_field("_nac3_option".into(), ctx) { let not_null = ctx.builder.build_is_not_null(ptr, "unwrap_not_null");
// if is none, raise exception directly ctx.make_assert(
None => { generator,
let err_msg = ctx.gen_string(generator, ""); not_null,
let current_fun = ctx "0:UnwrapNoneError",
.builder "",
.get_insert_block() [None, None, None],
.unwrap() expr.location,
.get_parent() );
.unwrap(); return Ok(Some(ctx.builder.build_load(ptr, "unwrap_some").into()))
let unreachable_block = ctx.ctx.append_basic_block( } else {
current_fun, unreachable!("option must be ptr")
"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
@ -1433,7 +1407,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, value.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.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();
@ -1480,7 +1454,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, slice.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.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,
@ -1515,39 +1489,26 @@ 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]).into() ctx.build_gep_and_load(arr_ptr, &[index])
} }
} 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");
}; };
let v = generator ctx.builder.build_extract_value(v, index, "tup_elem").unwrap()
.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!(),
})) }))

View File

@ -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 constructor. /// - signature: Function signature of the contructor.
/// - 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>(

View File

@ -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, ctx.primitives.int32)? .to_basic_value_enum(ctx, generator)?
.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, i.custom.unwrap())?; let i = generator.gen_expr(ctx, i)?.unwrap().to_basic_value_enum(ctx, generator)?;
Ok(ctx Ok(ctx
.builder .builder
.build_call(func, &[i.into(), length.into()], "bounded_ind") .build_call(func, &[i.into(), length.into()], "bounded_ind")

View File

@ -54,11 +54,7 @@ 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( let val = generator.gen_expr(ctx, value)?.unwrap().to_basic_value_enum(ctx, generator)?;
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 {
@ -76,58 +72,17 @@ 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, value.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.into_pointer_value(); .into_pointer_value();
let len = ctx let index = generator
.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, slice.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.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()])
@ -147,9 +102,7 @@ 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) = if let BasicValueEnum::StructValue(v) = value.to_basic_value_enum(ctx, generator)? {
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
@ -168,13 +121,11 @@ 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, ls.custom.unwrap())? .to_basic_value_enum(ctx, generator)?
.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 let value = value.to_basic_value_enum(ctx, generator)?.into_pointer_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)
@ -182,7 +133,15 @@ 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(generator, ctx, ty, ls, (start, end, step), value, src_ind) list_slice_assignment(
generator,
ctx,
ty,
ls,
(start, end, step),
value,
src_ind,
)
} else { } else {
unreachable!() unreachable!()
} }
@ -196,7 +155,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, target.custom.unwrap())?; let val = value.to_basic_value_enum(ctx, generator)?;
ctx.builder.build_store(ptr, val); ctx.builder.build_store(ptr, val);
} }
}; };
@ -226,11 +185,7 @@ 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( let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(ctx, generator)?;
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();
@ -343,11 +298,7 @@ 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( let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(ctx, generator)?;
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 {
@ -408,11 +359,7 @@ 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( let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(ctx, generator)?;
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 {
@ -509,7 +456,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, zelf_ty)?.into_pointer_value(); let zelf = zelf.to_basic_value_enum(ctx, generator)?.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 = {
@ -532,14 +479,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, ctx.primitives.str)? args.remove(0).1.to_basic_value_enum(ctx, generator)?
} 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, ctx.primitives.int64)? args.remove(0).1.to_basic_value_enum(ctx, generator)?
} else { } else {
ctx.ctx.i64_type().const_zero().into() ctx.ctx.i64_type().const_zero().into()
}; };
@ -961,11 +908,7 @@ pub fn gen_return<'ctx, 'a, G: CodeGenerator>(
) -> Result<(), String> { ) -> Result<(), String> {
let value = value let value = value
.as_ref() .as_ref()
.map(|v_expr| { .map(|v| generator.gen_expr(ctx, v).and_then(|v| v.unwrap().to_basic_value_enum(ctx, generator)))
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 {
@ -1026,28 +969,20 @@ 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 = generator.gen_expr(ctx, exc)?.unwrap().to_basic_value_enum( let exc =
ctx, generator.gen_expr(ctx, exc)?.unwrap().to_basic_value_enum(ctx, generator)?;
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 = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum( let test =
ctx, generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(ctx, generator)?;
generator,
test.custom.unwrap(),
)?;
let err_msg = match msg { let err_msg = match msg {
Some(msg) => generator.gen_expr(ctx, msg)?.unwrap().to_basic_value_enum( Some(msg) => {
ctx, generator.gen_expr(ctx, msg)?.unwrap().to_basic_value_enum(ctx, generator)?
generator, }
msg.custom.unwrap(),
)?,
None => ctx.gen_string(generator, ""), None => ctx.gen_string(generator, ""),
}; };
ctx.make_assert_impl( ctx.make_assert_impl(

View File

@ -71,7 +71,6 @@ 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>(
@ -79,8 +78,6 @@ 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)]
@ -124,10 +121,9 @@ 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, expected_ty), ValueEnum::Static(v) => v.to_basic_value_enum(ctx, generator),
ValueEnum::Dynamic(v) => Ok(v), ValueEnum::Dynamic(v) => Ok(v),
} }
} }
@ -367,7 +363,7 @@ impl dyn SymbolResolver + Send + Sync {
unreachable!("expected class definition") unreachable!("expected class definition")
} }
}, },
&mut |id| format!("typevar{}", id), &mut |id| format!("var{}", id),
&mut None, &mut None,
) )
} }

View File

@ -92,6 +92,18 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
Some("N".into()), Some("N".into()),
None, None,
); );
let any_ty = primitives.1.get_fresh_var_with_range(
&[int32, int64, float, boolean, uint32, uint64, string, range, boolean],
Some("A".into()),
None,
);
let tuple_ty = primitives.1.add_ty(TypeEnum::TTuple {ty: vec![num_ty.0, any_ty.0]});
let any_tuple_ty = primitives.1.get_fresh_var_with_range(
&[int32, int64, float, boolean, uint32, uint64, string, tuple_ty, range, boolean],
Some("A".into()),
None,
);
let list_ty = primitives.1.add_ty(TypeEnum::TList {ty: any_ty.0});
let var_map: HashMap<_, _> = vec![(num_ty.1, num_ty.0)].into_iter().collect(); let var_map: HashMap<_, _> = vec![(num_ty.1, num_ty.0)].into_iter().collect();
let exception_fields = vec![ let exception_fields = vec![
("__name__".into(), int32, true), ("__name__".into(), int32, true),
@ -224,12 +236,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, obj, _, _, generator| { |ctx, obj, _, _, generator| {
let expect_ty = obj.clone().unwrap().0; let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
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 {
@ -249,12 +256,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, obj, _, _, generator| { |ctx, obj, _, _, generator| {
let expect_ty = obj.clone().unwrap().0; let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?;
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 {
@ -300,7 +302,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, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
Ok(if ctx.unifier.unioned(arg_ty, boolean) { Ok(if ctx.unifier.unioned(arg_ty, boolean) {
Some( Some(
ctx.builder ctx.builder
@ -365,7 +367,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, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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)
@ -432,7 +434,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, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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")
@ -484,7 +486,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, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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)
@ -531,7 +533,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, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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)
@ -567,7 +569,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, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -607,7 +609,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, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -665,20 +667,19 @@ 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, ty_i32)?); start = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
} 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, ty_i32)?); stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
} 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, ty_i32)?); step = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
} else if i == 0 { } else if i == 0 {
start = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?); start = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
} else if i == 1 { } else if i == 1 {
stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?); stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
} else if i == 2 { } else if i == 2 {
step = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?); step = Some(arg.1.clone().to_basic_value_enum(ctx, generator)?);
} }
} }
let step = match step { let step = match step {
@ -745,9 +746,8 @@ 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, _, _, args, generator| {
let arg_ty = fun.0.args[0].ty; Ok(Some(args[0].1.clone().to_basic_value_enum(ctx, generator)?))
Ok(Some(args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?))
}, },
)))), )))),
loc: None, loc: None,
@ -771,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, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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) {
@ -829,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, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -869,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, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -909,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, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -949,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, ctx.primitives.float)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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();
@ -1001,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, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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);
@ -1055,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, m_ty)?; let m_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator, n_ty)?; let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator)?;
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)
@ -1117,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, m_ty)?; let m_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator, n_ty)?; let n_val = args[1].1.clone().to_basic_value_enum(ctx, generator)?;
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)
@ -1175,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, n_ty)?; let n_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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) =
@ -1232,9 +1232,8 @@ 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_ty = fun.0.args[0].ty; let arg_val = args[0].1.clone().to_basic_value_enum(ctx, generator)?;
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()))

View File

@ -70,6 +70,7 @@ impl TopLevelComposer {
"none".into(), "none".into(),
"None".into(), "None".into(),
"range".into(), "range".into(),
"enumerate".into(),
"str".into(), "str".into(),
"self".into(), "self".into(),
"Kernel".into(), "Kernel".into(),
@ -434,11 +435,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 occurred_type_var_id: HashSet<u32> = HashSet::new(); let mut occured_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() {
occurred_type_var_id.insert(*id) occured_type_var_id.insert(*id)
} else { } else {
false false
} }
@ -536,7 +537,7 @@ impl TopLevelComposer {
} }
has_base = true; has_base = true;
// the function parse_ast_to make sure that no type var occurred in // the function parse_ast_to make sure that no type var occured 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 +697,7 @@ impl TopLevelComposer {
return Err(errors.into_iter().sorted().join("\n----------\n")); return Err(errors.into_iter().sorted().join("\n----------\n"));
} }
// handle the inherited methods and fields // handle the inheritanced 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 +826,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_parameter_name: HashSet<_> = HashSet::new(); let mut defined_paramter_name: HashSet<_> = HashSet::new();
for x in args.args.iter() { for x in args.args.iter() {
if !defined_parameter_name.insert(x.node.arg) if !defined_paramter_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 +1075,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_parameter_name: HashSet<_> = HashSet::new(); let mut defined_paramter_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_parameter_name.insert(x.node.arg) if !defined_paramter_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 +1089,13 @@ impl TopLevelComposer {
} }
} }
if name == &"__init__".into() && !defined_parameter_name.contains(&zelf) { if name == &"__init__".into() && !defined_paramter_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_parameter_name.contains(&zelf) { if !defined_paramter_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 +1228,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 annotation // for uniform handling, still use type annoatation
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 +1469,7 @@ impl TopLevelComposer {
Ok(()) Ok(())
} }
/// step 5, analyze and call type inferencer to fill the `instance_to_stmt` of topleveldef::function /// step 5, analyze and call type inferecer 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 +1907,7 @@ impl TopLevelComposer {
unreachable!("must be class id here") unreachable!("must be class id here")
} }
}, },
&mut |id| format!("typevar{}", id), &mut |id| format!("tvar{}", id),
&mut None, &mut None,
); );
return Err(format!( return Err(format!(

View File

@ -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 registering, the type_vars, fields, methods, ancestors are invalid /// when first regitering, 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>>,

View File

@ -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[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", "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",
"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",

View File

@ -5,7 +5,7 @@ expression: res_vec
--- ---
[ [
"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", "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",
"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",

View File

@ -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!("{}: {:?}, typevar{}", name, ty, id); println!("{}: {:?}, tvar{}", 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!("typevar{}", id.to_string()), &mut |id| format!("tvar{}", id.to_string()),
&mut None, &mut None,
) )
} else { } else {

View File

@ -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!("typevar{}", id), &mut |id| format!("tvar{}", 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 directly /// But note that here we do not make a duplication of `T`, `V`, we direclty
/// 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

View File

@ -16,7 +16,7 @@ use crate::toplevel::{DefinitionId, TopLevelContext, TopLevelDef};
#[cfg(test)] #[cfg(test)]
mod test; mod test;
/// Handle for a type, implemented as a key in the unification table. /// Handle for a type, implementated 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!("typevar{}", id), &mut |id| format!("var{}", id),
notes, notes,
) )
} }

View File

@ -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[typevar4]::b` field/method does not exist") (("v1", "v2"), "`3[var4]::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)],
erroneous_pair: ((&'static str, &'static str), &'static str), errornous_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(erroneous_pair.0 .0, &mapping), env.parse(erroneous_pair.0 .1, &mapping)); (env.parse(errornous_pair.0 .0, &mapping), env.parse(errornous_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(erroneous_pair.1.to_string())); assert_eq!(env.unify(t1, t2), Err(errornous_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[typevar5], but got list[1]\n\nNotes:\n typevar5 ∈ {0, 2}".to_string()) Err("Expected any one of these types: 0, list[var5], but got list[1]\n\nNotes:\n var5 ∈ {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: typevar3 and typevar2".to_string())); assert_eq!(env.unify(a, b), Err("Incompatible types: var3 and var2".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 typevar2".to_string())); assert_eq!(env.unify(list_x, list_int), Err("Incompatible types: 0 and var2".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();