KernelInvariant #114
|
@ -1,2 +0,0 @@
|
||||||
[unstable]
|
|
||||||
extra-link-arg = true
|
|
|
@ -2,16 +2,16 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1636698608,
|
"lastModified": 1637636156,
|
||||||
"narHash": "sha256-sxLLeQmH3UrP3UANqXzMLE0bPDgY5aIt04iBoPffG2E=",
|
"narHash": "sha256-E2ym4Vcpqu9JYoQDXJZR48gVD+LPPbaCoYveIk7Xu3Y=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "92c881b6a72abce5bb2f5db3f903b4871d13aaa9",
|
"rev": "b026e1cf87a108dd06fe521f224fdc72fd0b013d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "master",
|
"ref": "release-21.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
description = "The third-generation ARTIQ compiler";
|
description = "The third-generation ARTIQ compiler";
|
||||||
|
|
||||||
inputs.nixpkgs.url = github:NixOS/nixpkgs/master;
|
inputs.nixpkgs.url = github:NixOS/nixpkgs/release-21.11;
|
||||||
|
|
||||||
outputs = { self, nixpkgs }:
|
outputs = { self, nixpkgs }:
|
||||||
let
|
let
|
||||||
|
|
|
@ -2,14 +2,14 @@ use inkwell::{types::BasicType, values::BasicValueEnum, AddressSpace};
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::CodeGenContext,
|
codegen::CodeGenContext,
|
||||||
location::Location,
|
location::Location,
|
||||||
symbol_resolver::{StaticValue, SymbolResolver, ValueEnum},
|
symbol_resolver::{StaticValue, SymbolResolver, SymbolValue, ValueEnum},
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::PrimitiveStore,
|
type_inferencer::PrimitiveStore,
|
||||||
typedef::{Type, TypeEnum, Unifier},
|
typedef::{Type, TypeEnum, Unifier},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use nac3parser::ast::StrRef;
|
use nac3parser::ast::{self, StrRef};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use pyo3::{
|
use pyo3::{
|
||||||
types::{PyList, PyModule, PyTuple},
|
types::{PyList, PyModule, PyTuple},
|
||||||
|
@ -458,9 +458,80 @@ impl InnerResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_default_param_obj_value(
|
||||||
|
&self,
|
||||||
|
py: Python,
|
||||||
|
obj: &PyAny,
|
||||||
|
) -> PyResult<Result<SymbolValue, String>> {
|
||||||
|
let ty_id: u64 = self
|
||||||
|
.helper
|
||||||
|
.id_fn
|
||||||
|
.call1(py, (self.helper.type_fn.call1(py, (obj,))?,))?
|
||||||
|
.extract(py)?;
|
||||||
|
Ok(
|
||||||
|
if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 {
|
||||||
|
let val: i32 = obj.extract()?;
|
||||||
|
Ok(SymbolValue::I32(val))
|
||||||
|
} else if ty_id == self.primitive_ids.int64 {
|
||||||
|
let val: i64 = obj.extract()?;
|
||||||
|
Ok(SymbolValue::I64(val))
|
||||||
|
} else if ty_id == self.primitive_ids.bool {
|
||||||
|
let val: bool = obj.extract()?;
|
||||||
|
Ok(SymbolValue::Bool(val))
|
||||||
|
} else if ty_id == self.primitive_ids.float {
|
||||||
|
let val: f64 = obj.extract()?;
|
||||||
|
Ok(SymbolValue::Double(val))
|
||||||
|
} else if ty_id == self.primitive_ids.tuple {
|
||||||
|
let elements: &PyTuple = obj.cast_as()?;
|
||||||
|
let elements: Result<Result<Vec<_>, String>, _> = elements
|
||||||
|
.iter()
|
||||||
|
.map(|elem| self.get_default_param_obj_value(py, elem))
|
||||||
|
.collect();
|
||||||
|
let elements = match elements? {
|
||||||
|
Ok(el) => el,
|
||||||
|
Err(err) => return Ok(Err(err)),
|
||||||
|
};
|
||||||
|
Ok(SymbolValue::Tuple(elements))
|
||||||
|
} else {
|
||||||
|
Err("only primitives values and tuple can be default parameter value".into())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SymbolResolver for Resolver {
|
impl SymbolResolver for Resolver {
|
||||||
|
fn get_default_param_value(&self, expr: &ast::Expr) -> Option<SymbolValue> {
|
||||||
|
match &expr.node {
|
||||||
|
ast::ExprKind::Name { id, .. } => {
|
||||||
|
Python::with_gil(|py| -> PyResult<Option<SymbolValue>> {
|
||||||
|
let obj: &PyAny = self.0.module.extract(py)?;
|
||||||
|
let members: &PyList = PyModule::import(py, "inspect")?
|
||||||
|
.getattr("getmembers")?
|
||||||
|
.call1((obj,))?
|
||||||
|
.cast_as()?;
|
||||||
|
let mut sym_value = None;
|
||||||
|
for member in members.iter() {
|
||||||
|
let key: &str = member.get_item(0)?.extract()?;
|
||||||
|
let val = member.get_item(1)?;
|
||||||
|
if key == id.to_string() {
|
||||||
|
sym_value = Some(
|
||||||
|
self.0
|
||||||
|
.get_default_param_obj_value(py, val)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(sym_value)
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
_ => unimplemented!("other type of expr not supported at {}", expr.location),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_symbol_type(
|
fn get_symbol_type(
|
||||||
&self,
|
&self,
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
|
|
|
@ -147,8 +147,15 @@ impl ConcreteTypeStore {
|
||||||
fields: fields
|
fields: fields
|
||||||
.borrow()
|
.borrow()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, ty)| {
|
.filter_map(|(name, ty)| {
|
||||||
(*name, (self.from_unifier_type(unifier, primitives, ty.0, cache), ty.1))
|
// here we should not have type vars, but some partial instantiated
|
||||||
|
// class methods can still have uninstantiated type vars, so
|
||||||
|
// filter out all the methods, as this will not affect codegen
|
||||||
|
if let TypeEnum::TFunc( .. ) = &*unifier.get_ty(ty.0) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((*name, (self.from_unifier_type(unifier, primitives, ty.0, cache), ty.1)))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
params: params
|
params: params
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
symbol_resolver::{SymbolValue, ValueEnum},
|
symbol_resolver::{SymbolValue, ValueEnum},
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum},
|
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
|
||||||
};
|
};
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::{BasicType, BasicTypeEnum},
|
types::{BasicType, BasicTypeEnum},
|
||||||
|
@ -19,6 +19,31 @@ use nac3parser::ast::{self, Boolop, Comprehension, Constant, Expr, ExprKind, Ope
|
||||||
|
|
||||||
use super::CodeGenerator;
|
use super::CodeGenerator;
|
||||||
|
|
||||||
|
pub fn get_subst_key(
|
||||||
|
unifier: &mut Unifier,
|
||||||
|
obj: Option<Type>,
|
||||||
|
fun_vars: &HashMap<u32, Type>,
|
||||||
|
filter: Option<&Vec<u32>>,
|
||||||
|
) -> String {
|
||||||
|
let mut vars = obj
|
||||||
|
.map(|ty| {
|
||||||
|
if let TypeEnum::TObj { params, .. } = &*unifier.get_ty(ty) {
|
||||||
|
params.borrow().clone()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
vars.extend(fun_vars.iter());
|
||||||
|
let sorted =
|
||||||
|
vars.keys().filter(|id| filter.map(|v| v.contains(id)).unwrap_or(true)).sorted();
|
||||||
|
sorted
|
||||||
|
.map(|id| {
|
||||||
|
unifier.stringify(vars[id], &mut |id| id.to_string(), &mut |id| id.to_string())
|
||||||
|
})
|
||||||
|
.join(", ")
|
||||||
|
}
|
||||||
|
|
||||||
impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
pub fn build_gep_and_load(
|
pub fn build_gep_and_load(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -34,23 +59,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
fun: &FunSignature,
|
fun: &FunSignature,
|
||||||
filter: Option<&Vec<u32>>,
|
filter: Option<&Vec<u32>>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut vars = obj
|
get_subst_key(&mut self.unifier, obj, &fun.vars, filter)
|
||||||
.map(|ty| {
|
|
||||||
if let TypeEnum::TObj { params, .. } = &*self.unifier.get_ty(ty) {
|
|
||||||
params.borrow().clone()
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_default();
|
|
||||||
vars.extend(fun.vars.iter());
|
|
||||||
let sorted =
|
|
||||||
vars.keys().filter(|id| filter.map(|v| v.contains(id)).unwrap_or(true)).sorted();
|
|
||||||
sorted
|
|
||||||
.map(|id| {
|
|
||||||
self.unifier.stringify(vars[id], &mut |id| id.to_string(), &mut |id| id.to_string())
|
|
||||||
})
|
|
||||||
.join(", ")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_attr_index(&mut self, ty: Type, attr: StrRef) -> usize {
|
pub fn get_attr_index(&mut self, ty: Type, attr: StrRef) -> usize {
|
||||||
|
|
|
@ -293,7 +293,14 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
// this should be unification between variables and concrete types
|
// this should be unification between variables and concrete types
|
||||||
// and should not cause any problem...
|
// and should not cause any problem...
|
||||||
let b = task.store.to_unifier_type(&mut unifier, &primitives, *b, &mut cache);
|
let b = task.store.to_unifier_type(&mut unifier, &primitives, *b, &mut cache);
|
||||||
unifier.unify(*a, b).unwrap();
|
unifier.unify(*a, b).or_else(|err| {
|
||||||
|
if matches!(&*unifier.get_ty(*a), TypeEnum::TRigidVar { .. }) {
|
||||||
|
unifier.replace_rigid_var(*a, b);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// rebuild primitive store with unique representatives
|
// rebuild primitive store with unique representatives
|
||||||
|
|
|
@ -36,6 +36,10 @@ impl Resolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SymbolResolver for Resolver {
|
impl SymbolResolver for Resolver {
|
||||||
|
fn get_default_param_value(&self, _: &nac3parser::ast::Expr) -> Option<crate::symbol_resolver::SymbolValue> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_symbol_type(
|
fn get_symbol_type(
|
||||||
&self,
|
&self,
|
||||||
_: &mut Unifier,
|
_: &mut Unifier,
|
||||||
|
|
|
@ -102,6 +102,7 @@ pub trait SymbolResolver {
|
||||||
) -> Option<ValueEnum<'ctx>>;
|
) -> Option<ValueEnum<'ctx>>;
|
||||||
|
|
||||||
fn get_symbol_location(&self, str: StrRef) -> Option<Location>;
|
fn get_symbol_location(&self, str: StrRef) -> Option<Location>;
|
||||||
|
fn get_default_param_value(&self, expr: &nac3parser::ast::Expr) -> Option<SymbolValue>;
|
||||||
// handle function call etc.
|
// handle function call etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ use inkwell::FloatPredicate;
|
||||||
use crate::{
|
use crate::{
|
||||||
symbol_resolver::SymbolValue,
|
symbol_resolver::SymbolValue,
|
||||||
typecheck::type_inferencer::{FunctionData, Inferencer},
|
typecheck::type_inferencer::{FunctionData, Inferencer},
|
||||||
|
codegen::expr::get_subst_key,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -194,7 +195,7 @@ impl TopLevelComposer {
|
||||||
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
|
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
|
||||||
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
|
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
|
||||||
ret: float,
|
ret: float,
|
||||||
vars: var_map,
|
vars: var_map.clone(),
|
||||||
}))),
|
}))),
|
||||||
var_id: Default::default(),
|
var_id: Default::default(),
|
||||||
instance_to_symbol: Default::default(),
|
instance_to_symbol: Default::default(),
|
||||||
|
@ -397,7 +398,7 @@ impl TopLevelComposer {
|
||||||
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
|
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
|
||||||
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
|
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
|
||||||
ret: primitives.0.bool,
|
ret: primitives.0.bool,
|
||||||
vars: Default::default(),
|
vars: var_map,
|
||||||
}))),
|
}))),
|
||||||
var_id: Default::default(),
|
var_id: Default::default(),
|
||||||
instance_to_symbol: Default::default(),
|
instance_to_symbol: Default::default(),
|
||||||
|
@ -1066,9 +1067,22 @@ impl TopLevelComposer {
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
args.args
|
let arg_with_default: Vec<(&ast::Located<ast::ArgData<()>>, Option<&ast::Expr>)> = args
|
||||||
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| -> Result<FuncArg, String> {
|
.rev()
|
||||||
|
.zip(args
|
||||||
|
.defaults
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.map(|x| -> Option<&ast::Expr> { Some(x) })
|
||||||
|
.chain(std::iter::repeat(None))
|
||||||
|
).collect_vec();
|
||||||
|
|
||||||
|
arg_with_default
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.map(|(x, default)| -> Result<FuncArg, String> {
|
||||||
let annotation = x
|
let annotation = x
|
||||||
.node
|
.node
|
||||||
.annotation
|
.annotation
|
||||||
|
@ -1120,7 +1134,19 @@ impl TopLevelComposer {
|
||||||
Ok(FuncArg {
|
Ok(FuncArg {
|
||||||
name: x.node.arg,
|
name: x.node.arg,
|
||||||
ty,
|
ty,
|
||||||
default_value: Default::default(),
|
default_value: match default {
|
||||||
|
None => None,
|
||||||
|
Some(default) => Some({
|
||||||
|
let v = Self::parse_parameter_default_value(default, resolver)?;
|
||||||
|
Self::check_default_param_type(
|
||||||
|
&v,
|
||||||
|
&type_annotation,
|
||||||
|
primitives_store,
|
||||||
|
unifier
|
||||||
|
).map_err(|err| format!("{} at {}", err, x.location))?;
|
||||||
|
v
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
|
@ -1170,8 +1196,17 @@ impl TopLevelComposer {
|
||||||
primitives_store.none
|
primitives_store.none
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var_id.extend_from_slice(
|
var_id.extend_from_slice(function_var_map
|
||||||
function_var_map.keys().into_iter().copied().collect_vec().as_slice(),
|
.iter()
|
||||||
|
.filter_map(|(id, ty)| {
|
||||||
|
if matches!(&*unifier.get_ty(*ty), TypeEnum::TVar { range, .. } if range.borrow().is_empty()) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(*id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_vec()
|
||||||
|
.as_slice()
|
||||||
);
|
);
|
||||||
let function_ty = unifier.add_ty(TypeEnum::TFunc(
|
let function_ty = unifier.add_ty(TypeEnum::TFunc(
|
||||||
FunSignature { args: arg_types, ret: return_ty, vars: function_var_map }
|
FunSignature { args: arg_types, ret: return_ty, vars: function_var_map }
|
||||||
|
@ -1272,7 +1307,20 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for x in &args.args {
|
|
||||||
|
let arg_with_default: Vec<(&ast::Located<ast::ArgData<()>>, Option<&ast::Expr>)> = args
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.zip(args
|
||||||
|
.defaults
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.map(|x| -> Option<&ast::Expr> { Some(x) })
|
||||||
|
.chain(std::iter::repeat(None))
|
||||||
|
).collect_vec();
|
||||||
|
|
||||||
|
for (x, default) in arg_with_default.into_iter().rev() {
|
||||||
let name = x.node.arg;
|
let name = x.node.arg;
|
||||||
if name != zelf {
|
if name != zelf {
|
||||||
let type_ann = {
|
let type_ann = {
|
||||||
|
@ -1317,8 +1365,20 @@ impl TopLevelComposer {
|
||||||
let dummy_func_arg = FuncArg {
|
let dummy_func_arg = FuncArg {
|
||||||
name,
|
name,
|
||||||
ty: unifier.get_fresh_var().0,
|
ty: unifier.get_fresh_var().0,
|
||||||
// TODO: default value?
|
default_value: match default {
|
||||||
default_value: None,
|
None => None,
|
||||||
|
Some(default) => {
|
||||||
|
if name == "self".into() {
|
||||||
|
return Err(format!("`self` parameter cannot take default value at {}", x.location));
|
||||||
|
}
|
||||||
|
Some({
|
||||||
|
let v = Self::parse_parameter_default_value(default, class_resolver)?;
|
||||||
|
Self::check_default_param_type(&v, &type_ann, primitives, unifier)
|
||||||
|
.map_err(|err| format!("{} at {}", err, x.location))?;
|
||||||
|
v
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// push the dummy type and the type annotation
|
// push the dummy type and the type annotation
|
||||||
// into the list for later unification
|
// into the list for later unification
|
||||||
|
@ -1374,9 +1434,20 @@ impl TopLevelComposer {
|
||||||
if let TopLevelDef::Function { var_id, .. } =
|
if let TopLevelDef::Function { var_id, .. } =
|
||||||
temp_def_list.get(method_id.0).unwrap().write().deref_mut()
|
temp_def_list.get(method_id.0).unwrap().write().deref_mut()
|
||||||
{
|
{
|
||||||
var_id.extend_from_slice(
|
var_id.extend_from_slice(method_var_map
|
||||||
method_var_map.keys().into_iter().copied().collect_vec().as_slice(),
|
.iter()
|
||||||
|
.filter_map(|(id, ty)| {
|
||||||
|
if matches!(&*unifier.get_ty(*ty), TypeEnum::TVar { range, .. } if range.borrow().is_empty()) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(*id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_vec()
|
||||||
|
.as_slice()
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
}
|
}
|
||||||
let method_type = unifier.add_ty(TypeEnum::TFunc(
|
let method_type = unifier.add_ty(TypeEnum::TFunc(
|
||||||
FunSignature { args: arg_types, ret: ret_type, vars: method_var_map }
|
FunSignature { args: arg_types, ret: ret_type, vars: method_var_map }
|
||||||
|
@ -1625,9 +1696,11 @@ impl TopLevelComposer {
|
||||||
unreachable!("must be init function here")
|
unreachable!("must be init function here")
|
||||||
}
|
}
|
||||||
let all_inited = Self::get_all_assigned_field(body.as_slice())?;
|
let all_inited = Self::get_all_assigned_field(body.as_slice())?;
|
||||||
if fields.iter().any(|x| !all_inited.contains(&x.0)) {
|
for (f, _, _) in fields {
|
||||||
|
if !all_inited.contains(f) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"fields of class {} not fully initialized",
|
"fields `{}` of class `{}` not fully initialized",
|
||||||
|
f,
|
||||||
class_name
|
class_name
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -1635,6 +1708,7 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let ctx = Arc::new(self.make_top_level_context());
|
let ctx = Arc::new(self.make_top_level_context());
|
||||||
// type inference inside function body
|
// type inference inside function body
|
||||||
|
@ -1648,13 +1722,14 @@ impl TopLevelComposer {
|
||||||
simple_name,
|
simple_name,
|
||||||
signature,
|
signature,
|
||||||
resolver,
|
resolver,
|
||||||
|
var_id: insted_vars,
|
||||||
..
|
..
|
||||||
} = &mut *function_def
|
} = &mut *function_def
|
||||||
{
|
{
|
||||||
if let TypeEnum::TFunc(func_sig) = self.unifier.get_ty(*signature).as_ref() {
|
if let TypeEnum::TFunc(func_sig) = self.unifier.get_ty(*signature).as_ref() {
|
||||||
let FunSignature { args, ret, vars } = &*func_sig.borrow();
|
let FunSignature { args, ret, vars } = &*func_sig.borrow();
|
||||||
// None if is not class method
|
// None if is not class method
|
||||||
let self_type = {
|
let uninst_self_type = {
|
||||||
if let Some(class_id) = self.method_class.get(&DefinitionId(id)) {
|
if let Some(class_id) = self.method_class.get(&DefinitionId(id)) {
|
||||||
let class_def = self.definition_ast_list.get(class_id.0).unwrap();
|
let class_def = self.definition_ast_list.get(class_id.0).unwrap();
|
||||||
let class_def = class_def.0.read();
|
let class_def = class_def.0.read();
|
||||||
|
@ -1666,7 +1741,7 @@ impl TopLevelComposer {
|
||||||
&self.primitives_ty,
|
&self.primitives_ty,
|
||||||
&ty_ann,
|
&ty_ann,
|
||||||
)?;
|
)?;
|
||||||
Some(self_ty)
|
Some((self_ty, type_vars.clone()))
|
||||||
} else {
|
} else {
|
||||||
unreachable!("must be class def")
|
unreachable!("must be class def")
|
||||||
}
|
}
|
||||||
|
@ -1674,20 +1749,20 @@ impl TopLevelComposer {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// carefully handle those with bounds, without bounds and no typevars
|
||||||
|
// if class methods, `vars` also contains all class typevars here
|
||||||
let (type_var_subst_comb, no_range_vars) = {
|
let (type_var_subst_comb, no_range_vars) = {
|
||||||
let unifier = &mut self.unifier;
|
let unifier = &mut self.unifier;
|
||||||
let mut no_ranges: Vec<Type> = Vec::new();
|
let mut no_ranges: Vec<Type> = Vec::new();
|
||||||
let var_ids = vars.iter().map(|(id, ty)| {
|
let var_ids = vars.keys().copied().collect_vec();
|
||||||
if matches!(unifier.get_ty(*ty).as_ref(), TypeEnum::TVar { range, .. } if range.borrow().is_empty()) {
|
|
||||||
no_ranges.push(*ty);
|
|
||||||
}
|
|
||||||
*id
|
|
||||||
})
|
|
||||||
.collect_vec();
|
|
||||||
let var_combs = vars
|
let var_combs = vars
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, ty)| {
|
.map(|(_, ty)| {
|
||||||
unifier.get_instantiations(*ty).unwrap_or_else(|| vec![*ty])
|
unifier.get_instantiations(*ty).unwrap_or_else(|| {
|
||||||
|
let rigid = unifier.get_fresh_rigid_var().0;
|
||||||
|
no_ranges.push(rigid);
|
||||||
|
vec![rigid]
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.multi_cartesian_product()
|
.multi_cartesian_product()
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
@ -1717,9 +1792,34 @@ impl TopLevelComposer {
|
||||||
};
|
};
|
||||||
let self_type = {
|
let self_type = {
|
||||||
let unifier = &mut self.unifier;
|
let unifier = &mut self.unifier;
|
||||||
self_type.map(|x| unifier.subst(x, &subst).unwrap_or(x))
|
uninst_self_type
|
||||||
|
.clone()
|
||||||
|
.map(|(self_type, type_vars)| {
|
||||||
|
let subst_for_self = {
|
||||||
|
let class_ty_var_ids = type_vars
|
||||||
|
.iter()
|
||||||
|
.map(|x| {
|
||||||
|
if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*x) {
|
||||||
|
*id
|
||||||
|
} else {
|
||||||
|
unreachable!("must be type var here");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
subst
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(ty_var_id, ty_var_target)| {
|
||||||
|
if class_ty_var_ids.contains(ty_var_id) {
|
||||||
|
Some((*ty_var_id, *ty_var_target))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>()
|
||||||
|
};
|
||||||
|
unifier.subst(self_type, &subst_for_self).unwrap_or(self_type)
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut identifiers = {
|
let mut identifiers = {
|
||||||
// NOTE: none and function args?
|
// NOTE: none and function args?
|
||||||
let mut result: HashSet<_> = HashSet::new();
|
let mut result: HashSet<_> = HashSet::new();
|
||||||
|
@ -1809,22 +1909,12 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
instance_to_stmt.insert(
|
instance_to_stmt.insert(
|
||||||
// NOTE: refer to codegen/expr/get_subst_key function
|
get_subst_key(
|
||||||
{
|
&mut self.unifier,
|
||||||
let unifier = &mut self.unifier;
|
self_type,
|
||||||
subst
|
&subst,
|
||||||
.keys()
|
Some(insted_vars),
|
||||||
.sorted()
|
),
|
||||||
.map(|id| {
|
|
||||||
let ty = subst.get(id).unwrap();
|
|
||||||
unifier.stringify(
|
|
||||||
*ty,
|
|
||||||
&mut |id| id.to_string(),
|
|
||||||
&mut |id| id.to_string(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.join(", ")
|
|
||||||
},
|
|
||||||
FunInstance {
|
FunInstance {
|
||||||
body: Arc::new(fun_body),
|
body: Arc::new(fun_body),
|
||||||
unifier_id: 0,
|
unifier_id: 0,
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
use nac3parser::ast::{Constant, Location};
|
||||||
|
use crate::symbol_resolver::SymbolValue;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl TopLevelDef {
|
impl TopLevelDef {
|
||||||
|
@ -341,4 +346,121 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_parameter_default_value(default: &ast::Expr, resolver: &(dyn SymbolResolver + Send + Sync)) -> Result<SymbolValue, String> {
|
||||||
|
parse_parameter_default_value(default, resolver)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_default_param_type(val: &SymbolValue, ty: &TypeAnnotation, primitive: &PrimitiveStore, unifier: &mut Unifier) -> Result<(), String> {
|
||||||
|
let res = match val {
|
||||||
|
SymbolValue::Bool(..) => {
|
||||||
|
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.bool) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some("bool".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SymbolValue::Double(..) => {
|
||||||
|
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.float) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some("float".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SymbolValue::I32(..) => {
|
||||||
|
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.int32) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some("int32".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SymbolValue::I64(..) => {
|
||||||
|
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.int64) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some("int64".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SymbolValue::Tuple(elts) => {
|
||||||
|
if let TypeAnnotation::Tuple(elts_ty) = ty {
|
||||||
|
for (e, t) in elts.iter().zip(elts_ty.iter()) {
|
||||||
|
Self::check_default_param_type(e, t, primitive, unifier)?
|
||||||
|
}
|
||||||
|
if elts.len() != elts_ty.len() {
|
||||||
|
Some(format!("tuple of length {}", elts.len()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Some("tuple".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(found) = res {
|
||||||
|
Err(format!(
|
||||||
|
"incompatible default parameter type, expect {}, found {}",
|
||||||
|
ty.stringify(unifier),
|
||||||
|
found
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_parameter_default_value(default: &ast::Expr, resolver: &(dyn SymbolResolver + Send + Sync)) -> Result<SymbolValue, String> {
|
||||||
|
fn handle_constant(val: &Constant, loc: &Location) -> Result<SymbolValue, String> {
|
||||||
|
match val {
|
||||||
|
Constant::Int(v) => {
|
||||||
|
if let Ok(v) = v.try_into() {
|
||||||
|
Ok(SymbolValue::I32(v))
|
||||||
|
} else {
|
||||||
|
Err(format!(
|
||||||
|
"integer value out of range at {}",
|
||||||
|
loc
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constant::Float(v) => Ok(SymbolValue::Double(*v)),
|
||||||
|
Constant::Bool(v) => Ok(SymbolValue::Bool(*v)),
|
||||||
|
Constant::Tuple(tuple) => Ok(SymbolValue::Tuple(
|
||||||
|
tuple.iter().map(|x| handle_constant(x, loc)).collect::<Result<Vec<_>, _>>()?
|
||||||
|
)),
|
||||||
|
_ => unimplemented!("this constant is not supported at {}", loc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match &default.node {
|
||||||
|
ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location),
|
||||||
|
ast::ExprKind::Call { func, args, .. } if {
|
||||||
|
match &func.node {
|
||||||
|
ast::ExprKind::Name { id, .. } => *id == "int64".into(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
} => {
|
||||||
|
if args.len() == 1 {
|
||||||
|
match &args[0].node {
|
||||||
|
ast::ExprKind::Constant { value: Constant::Int(v), .. } =>
|
||||||
|
Ok(SymbolValue::I64(v.try_into().unwrap())),
|
||||||
|
_ => Err(format!("only allow constant integer here at {}", default.location))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(format!("only allow constant integer here at {}", default.location))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts
|
||||||
|
.iter()
|
||||||
|
.map(|x| parse_parameter_default_value(x, resolver))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
|
)),
|
||||||
|
ast::ExprKind::Name { id, .. } => {
|
||||||
|
resolver.get_default_param_value(default).ok_or_else(
|
||||||
|
|| format!(
|
||||||
|
"`{}` cannot be used as a default parameter at {} (not primitive type or tuple / not defined?)",
|
||||||
|
id,
|
||||||
|
default.location
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => Err(format!("unsupported default parameter at {}", default.location))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ use inkwell::values::BasicValueEnum;
|
||||||
pub struct DefinitionId(pub usize);
|
pub struct DefinitionId(pub usize);
|
||||||
|
|
||||||
pub mod composer;
|
pub mod composer;
|
||||||
mod helper;
|
pub mod helper;
|
||||||
mod type_annotation;
|
mod type_annotation;
|
||||||
use composer::*;
|
use composer::*;
|
||||||
use type_annotation::*;
|
use type_annotation::*;
|
||||||
|
|
|
@ -9,5 +9,5 @@ expression: res_vec
|
||||||
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a=int32], var4]\",\nvar_id: [4]\n}\n",
|
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a=int32], var4]\",\nvar_id: [4]\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b=var3], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b=var3], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b=var3], none]\",\nvar_id: [3]\n}\n",
|
"Function {\nname: \"B.foo\",\nsig: \"fn[[b=var3], none]\",\nvar_id: []\n}\n",
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,12 +5,12 @@ expression: res_vec
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"var3\\\"]}\"],\nfields: [\"a\", \"b\", \"c\"],\nmethods: [(\"__init__\", \"fn[[t=var3], none]\"), (\"fun\", \"fn[[a=int32, b=var3], list[virtual[B[4->bool]]]]\"), (\"foo\", \"fn[[c=C], none]\")],\ntype_vars: [\"var3\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"var3\\\"]}\"],\nfields: [\"a\", \"b\", \"c\"],\nmethods: [(\"__init__\", \"fn[[t=var3], none]\"), (\"fun\", \"fn[[a=int32, b=var3], list[virtual[B[4->bool]]]]\"), (\"foo\", \"fn[[c=C], none]\")],\ntype_vars: [\"var3\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t=var3], none]\",\nvar_id: [3]\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t=var3], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a=int32, b=var3], list[virtual[B[4->bool]]]]\",\nvar_id: [3]\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a=int32, b=var3], list[virtual[B[4->bool]]]]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[c=C], none]\",\nvar_id: [3]\n}\n",
|
"Function {\nname: \"A.foo\",\nsig: \"fn[[c=C], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: [\\\"var4\\\"]}\", \"{class: A, params: [\\\"float\\\"]}\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a=int32, b=var3], list[virtual[B[4->bool]]]]\"), (\"foo\", \"fn[[c=C], none]\")],\ntype_vars: [\"var4\"]\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: [\\\"var4\\\"]}\", \"{class: A, params: [\\\"float\\\"]}\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a=int32, b=var3], list[virtual[B[4->bool]]]]\"), (\"foo\", \"fn[[c=C], none]\")],\ntype_vars: [\"var4\"]\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: [4]\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: [4]\n}\n",
|
||||||
"Function {\nname: \"B.fun\",\nsig: \"fn[[a=int32, b=var3], list[virtual[B[4->bool]]]]\",\nvar_id: [3, 4]\n}\n",
|
"Function {\nname: \"B.fun\",\nsig: \"fn[[a=int32, b=var3], list[virtual[B[4->bool]]]]\",\nvar_id: [4]\n}\n",
|
||||||
"Class {\nname: \"C\",\nancestors: [\"{class: C, params: []}\", \"{class: B, params: [\\\"bool\\\"]}\", \"{class: A, params: [\\\"float\\\"]}\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a=int32, b=var3], list[virtual[B[4->bool]]]]\"), (\"foo\", \"fn[[c=C], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"C\",\nancestors: [\"{class: C, params: []}\", \"{class: B, params: [\\\"bool\\\"]}\", \"{class: A, params: [\\\"float\\\"]}\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a=int32, b=var3], list[virtual[B[4->bool]]]]\"), (\"foo\", \"fn[[c=C], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,10 +4,10 @@ expression: res_vec
|
||||||
|
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Function {\nname: \"foo\",\nsig: \"fn[[a=list[int32], b=tuple[var3, float]], A[3->B, 4->bool]]\",\nvar_id: [3]\n}\n",
|
"Function {\nname: \"foo\",\nsig: \"fn[[a=list[int32], b=tuple[var3, float]], A[3->B, 4->bool]]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"var3\\\", \\\"var4\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v=var4], none]\"), (\"fun\", \"fn[[a=var3], var4]\")],\ntype_vars: [\"var3\", \"var4\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"var3\\\", \\\"var4\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v=var4], none]\"), (\"fun\", \"fn[[a=var3], var4]\")],\ntype_vars: [\"var3\", \"var4\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v=var4], none]\",\nvar_id: [3, 4]\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v=var4], none]\",\nvar_id: [4]\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a=var3], var4]\",\nvar_id: [3, 4]\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a=var3], var4]\",\nvar_id: [4]\n}\n",
|
||||||
"Function {\nname: \"gfun\",\nsig: \"fn[[a=A[3->list[float], 4->int32]], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"gfun\",\nsig: \"fn[[a=A[3->list[float], 4->int32]], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
|
|
|
@ -5,8 +5,8 @@ expression: res_vec
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"var3\\\", \\\"var4\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a=A[3->float, 4->bool], b=B], none]\"), (\"fun\", \"fn[[a=A[3->float, 4->bool]], A[3->bool, 4->int32]]\")],\ntype_vars: [\"var3\", \"var4\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"var3\\\", \\\"var4\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a=A[3->float, 4->bool], b=B], none]\"), (\"fun\", \"fn[[a=A[3->float, 4->bool]], A[3->bool, 4->int32]]\")],\ntype_vars: [\"var3\", \"var4\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a=A[3->float, 4->bool], b=B], none]\",\nvar_id: [3, 4]\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a=A[3->float, 4->bool], b=B], none]\",\nvar_id: [4]\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a=A[3->float, 4->bool]], A[3->bool, 4->int32]]\",\nvar_id: [3, 4]\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a=A[3->float, 4->bool]], A[3->bool, 4->int32]]\",\nvar_id: [4]\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\", \"{class: A, params: [\\\"int64\\\", \\\"bool\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a=A[3->float, 4->bool]], A[3->bool, 4->int32]]\"), (\"foo\", \"fn[[b=B], B]\"), (\"bar\", \"fn[[a=A[3->list[B], 4->int32]], tuple[A[3->virtual[A[3->B, 4->int32]], 4->bool], B]]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\", \"{class: A, params: [\\\"int64\\\", \\\"bool\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a=A[3->float, 4->bool]], A[3->bool, 4->int32]]\"), (\"foo\", \"fn[[b=B], B]\"), (\"bar\", \"fn[[a=A[3->list[B], 4->int32]], tuple[A[3->virtual[A[3->B, 4->int32]], 4->bool], B]]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b=B], B]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.foo\",\nsig: \"fn[[b=B], B]\",\nvar_id: []\n}\n",
|
||||||
|
|
|
@ -7,12 +7,12 @@ expression: res_vec
|
||||||
"Class {\nname: \"A\",\nancestors: [\"{class: A, params: []}\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b=B], none]\"), (\"foo\", \"fn[[a=var3, b=var4], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"{class: A, params: []}\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b=B], none]\"), (\"foo\", \"fn[[a=var3, b=var4], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[b=B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[b=B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[a=var3, b=var4], none]\",\nvar_id: [3, 4]\n}\n",
|
"Function {\nname: \"A.foo\",\nsig: \"fn[[a=var3, b=var4], none]\",\nvar_id: [4]\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\", \"{class: C, params: []}\", \"{class: A, params: []}\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b=B], none]\"), (\"foo\", \"fn[[a=var3, b=var4], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\", \"{class: C, params: []}\", \"{class: A, params: []}\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b=B], none]\"), (\"foo\", \"fn[[a=var3, b=var4], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"C\",\nancestors: [\"{class: C, params: []}\", \"{class: A, params: []}\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b=B], none]\"), (\"foo\", \"fn[[a=var3, b=var4], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"C\",\nancestors: [\"{class: C, params: []}\", \"{class: A, params: []}\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b=B], none]\"), (\"foo\", \"fn[[a=var3, b=var4], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"C.fun\",\nsig: \"fn[[b=B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"C.fun\",\nsig: \"fn[[b=B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"foo\",\nsig: \"fn[[a=A], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"foo\",\nsig: \"fn[[a=A], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"ff\",\nsig: \"fn[[a=var3], var4]\",\nvar_id: [3, 4]\n}\n",
|
"Function {\nname: \"ff\",\nsig: \"fn[[a=var3], var4]\",\nvar_id: [4]\n}\n",
|
||||||
]
|
]
|
||||||
|
|
|
@ -35,6 +35,10 @@ impl ResolverInternal {
|
||||||
struct Resolver(Arc<ResolverInternal>);
|
struct Resolver(Arc<ResolverInternal>);
|
||||||
|
|
||||||
impl SymbolResolver for Resolver {
|
impl SymbolResolver for Resolver {
|
||||||
|
fn get_default_param_value(&self, _: &nac3parser::ast::Expr) -> Option<crate::symbol_resolver::SymbolValue> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_symbol_type(
|
fn get_symbol_type(
|
||||||
&self,
|
&self,
|
||||||
_: &mut Unifier,
|
_: &mut Unifier,
|
||||||
|
|
|
@ -280,9 +280,11 @@ pub fn get_type_from_type_annotation_kinds(
|
||||||
{
|
{
|
||||||
let ok: bool = {
|
let ok: bool = {
|
||||||
// create a temp type var and unify to check compatibility
|
// create a temp type var and unify to check compatibility
|
||||||
|
p == *tvar || {
|
||||||
let temp =
|
let temp =
|
||||||
unifier.get_fresh_var_with_range(range.borrow().as_slice());
|
unifier.get_fresh_var_with_range(range.borrow().as_slice());
|
||||||
unifier.unify(temp.0, p).is_ok()
|
unifier.unify(temp.0, p).is_ok()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if ok {
|
if ok {
|
||||||
result.insert(*id, p);
|
result.insert(*id, p);
|
||||||
|
|
|
@ -19,6 +19,10 @@ struct Resolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SymbolResolver for Resolver {
|
impl SymbolResolver for Resolver {
|
||||||
|
fn get_default_param_value(&self, _: &nac3parser::ast::Expr) -> Option<crate::symbol_resolver::SymbolValue> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_symbol_type(
|
fn get_symbol_type(
|
||||||
&self,
|
&self,
|
||||||
_: &mut Unifier,
|
_: &mut Unifier,
|
||||||
|
|
|
@ -719,22 +719,19 @@ impl Unifier {
|
||||||
/// Returns Some(T) where T is the instantiated type.
|
/// Returns Some(T) where T is the instantiated type.
|
||||||
/// Returns None if the function is already instantiated.
|
/// Returns None if the function is already instantiated.
|
||||||
fn instantiate_fun(&mut self, ty: Type, fun: &FunSignature) -> Type {
|
fn instantiate_fun(&mut self, ty: Type, fun: &FunSignature) -> Type {
|
||||||
let mut instantiated = false;
|
let mut instantiated = true;
|
||||||
let mut vars = Vec::new();
|
let mut vars = Vec::new();
|
||||||
for (k, v) in fun.vars.iter() {
|
for (k, v) in fun.vars.iter() {
|
||||||
if let TypeEnum::TVar { id, range, .. } =
|
if let TypeEnum::TVar { id, range, .. } =
|
||||||
self.unification_table.probe_value(*v).as_ref()
|
self.unification_table.probe_value(*v).as_ref()
|
||||||
{
|
{
|
||||||
if k != id {
|
// for class methods that contain type vars not in class declaration,
|
||||||
instantiated = true;
|
// as long as there exits one uninstantiated type var, the function is not instantiated,
|
||||||
break;
|
// and need to do substitution on those type vars
|
||||||
}
|
if k == id {
|
||||||
// actually, if the first check succeeded, the function should be uninstatiated.
|
instantiated = false;
|
||||||
// The cloned values must be used and would not be wasted.
|
|
||||||
vars.push((*k, range.clone()));
|
vars.push((*k, range.clone()));
|
||||||
} else {
|
}
|
||||||
instantiated = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if instantiated {
|
if instantiated {
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::CodeGenContext,
|
codegen::CodeGenContext,
|
||||||
location::Location,
|
location::Location,
|
||||||
symbol_resolver::{SymbolResolver, ValueEnum},
|
symbol_resolver::{SymbolResolver, SymbolValue, ValueEnum},
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::PrimitiveStore,
|
type_inferencer::PrimitiveStore,
|
||||||
typedef::{Type, Unifier},
|
typedef::{Type, Unifier},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use nac3parser::ast::StrRef;
|
use nac3parser::ast::{self, StrRef};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ pub struct ResolverInternal {
|
||||||
pub id_to_type: Mutex<HashMap<StrRef, Type>>,
|
pub id_to_type: Mutex<HashMap<StrRef, Type>>,
|
||||||
pub id_to_def: Mutex<HashMap<StrRef, DefinitionId>>,
|
pub id_to_def: Mutex<HashMap<StrRef, DefinitionId>>,
|
||||||
pub class_names: Mutex<HashMap<StrRef, Type>>,
|
pub class_names: Mutex<HashMap<StrRef, Type>>,
|
||||||
|
pub module_globals: Mutex<HashMap<StrRef, SymbolValue>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResolverInternal {
|
impl ResolverInternal {
|
||||||
|
@ -26,11 +27,24 @@ impl ResolverInternal {
|
||||||
pub fn add_id_type(&self, id: StrRef, ty: Type) {
|
pub fn add_id_type(&self, id: StrRef, ty: Type) {
|
||||||
self.id_to_type.lock().insert(id, ty);
|
self.id_to_type.lock().insert(id, ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_module_global(&self, id: StrRef, val: SymbolValue) {
|
||||||
|
self.module_globals.lock().insert(id, val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Resolver(pub Arc<ResolverInternal>);
|
pub struct Resolver(pub Arc<ResolverInternal>);
|
||||||
|
|
||||||
impl SymbolResolver for Resolver {
|
impl SymbolResolver for Resolver {
|
||||||
|
fn get_default_param_value(&self, expr: &ast::Expr) -> Option<SymbolValue> {
|
||||||
|
match &expr.node {
|
||||||
|
ast::ExprKind::Name { id, .. } => {
|
||||||
|
self.0.module_globals.lock().get(id).cloned()
|
||||||
|
}
|
||||||
|
_ => unimplemented!("other type of expr not supported at {}", expr.location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_symbol_type(
|
fn get_symbol_type(
|
||||||
&self,
|
&self,
|
||||||
_: &mut Unifier,
|
_: &mut Unifier,
|
||||||
|
|
|
@ -4,8 +4,8 @@ use inkwell::{
|
||||||
OptimizationLevel,
|
OptimizationLevel,
|
||||||
};
|
};
|
||||||
use nac3core::typecheck::type_inferencer::PrimitiveStore;
|
use nac3core::typecheck::type_inferencer::PrimitiveStore;
|
||||||
use nac3parser::parser;
|
use nac3parser::{ast::{Expr, ExprKind, StmtKind}, parser};
|
||||||
use std::env;
|
use std::{borrow::Borrow, env};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime};
|
use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime};
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ use nac3core::{
|
||||||
WorkerRegistry,
|
WorkerRegistry,
|
||||||
},
|
},
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::SymbolResolver,
|
||||||
toplevel::{composer::TopLevelComposer, TopLevelDef},
|
toplevel::{composer::TopLevelComposer, TopLevelDef, helper::parse_parameter_default_value},
|
||||||
typecheck::typedef::FunSignature,
|
typecheck::typedef::FunSignature,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ fn main() {
|
||||||
id_to_type: builtins_ty.into(),
|
id_to_type: builtins_ty.into(),
|
||||||
id_to_def: builtins_def.into(),
|
id_to_def: builtins_def.into(),
|
||||||
class_names: Default::default(),
|
class_names: Default::default(),
|
||||||
|
module_globals: Default::default(),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
let resolver =
|
let resolver =
|
||||||
|
@ -66,6 +67,61 @@ fn main() {
|
||||||
);
|
);
|
||||||
|
|
||||||
for stmt in parser_result.into_iter() {
|
for stmt in parser_result.into_iter() {
|
||||||
|
if let StmtKind::Assign { targets, value, .. } = &stmt.node {
|
||||||
|
fn handle_assignment_pattern(
|
||||||
|
targets: &[Expr],
|
||||||
|
value: &Expr,
|
||||||
|
resolver: &(dyn SymbolResolver + Send + Sync),
|
||||||
|
internal_resolver: &ResolverInternal,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
if targets.len() == 1 {
|
||||||
|
match &targets[0].node {
|
||||||
|
ExprKind::Name { id, .. } => {
|
||||||
|
let val = parse_parameter_default_value(value.borrow(), resolver)?;
|
||||||
|
internal_resolver.add_module_global(*id, val);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
ExprKind::List { elts, .. }
|
||||||
|
| ExprKind::Tuple { elts, .. } => {
|
||||||
|
handle_assignment_pattern(elts, value, resolver, internal_resolver)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => unreachable!("cannot be assigned")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match &value.node {
|
||||||
|
ExprKind::List { elts, .. }
|
||||||
|
| ExprKind::Tuple { elts, .. } => {
|
||||||
|
if elts.len() != targets.len() {
|
||||||
|
Err(format!(
|
||||||
|
"number of elements to unpack does not match (expect {}, found {}) at {}",
|
||||||
|
targets.len(),
|
||||||
|
elts.len(),
|
||||||
|
value.location
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
for (tar, val) in targets.iter().zip(elts) {
|
||||||
|
handle_assignment_pattern(
|
||||||
|
std::slice::from_ref(tar),
|
||||||
|
val,
|
||||||
|
resolver,
|
||||||
|
internal_resolver
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => Err(format!("unpack of this expression is not supported at {}", value.location))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Err(err) = handle_assignment_pattern(targets, value, resolver.as_ref(), internal_resolver.as_ref()) {
|
||||||
|
eprintln!("{}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let (name, def_id, ty) = composer
|
let (name, def_id, ty) = composer
|
||||||
.register_top_level(stmt, Some(resolver.clone()), "__main__".into())
|
.register_top_level(stmt, Some(resolver.clone()), "__main__".into())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -100,7 +156,11 @@ fn main() {
|
||||||
|
|
||||||
let instance = {
|
let instance = {
|
||||||
let defs = top_level.definitions.read();
|
let defs = top_level.definitions.read();
|
||||||
let mut instance = defs[resolver.get_identifier_def("run".into()).unwrap().0].write();
|
let mut instance =
|
||||||
|
defs[resolver
|
||||||
|
.get_identifier_def("run".into())
|
||||||
|
.unwrap_or_else(|| panic!("cannot find run() entry point")).0
|
||||||
|
].write();
|
||||||
if let TopLevelDef::Function {
|
if let TopLevelDef::Function {
|
||||||
instance_to_stmt,
|
instance_to_stmt,
|
||||||
instance_to_symbol,
|
instance_to_symbol,
|
||||||
|
|
Loading…
Reference in New Issue