TypeVar and virtual support in Symbol Resolver #99

Merged
sb10q merged 12 commits from symbol_resolver_typevar into master 2021-12-01 22:44:53 +08:00
23 changed files with 500 additions and 132 deletions
Showing only changes of commit 34105b4f0e - Show all commits

View File

@ -1,2 +0,0 @@
[unstable]
extra-link-arg = true

8
flake.lock generated
View File

@ -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"
} }

View File

@ -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

View File

@ -2,7 +2,7 @@ use inkwell::{types::BasicType, values::BasicValueEnum, AddressSpace};
use nac3core::{ use nac3core::{
codegen::CodeGenContext, codegen::CodeGenContext,
location::Location, location::Location,
symbol_resolver::SymbolResolver, symbol_resolver::{SymbolResolver, SymbolValue},
toplevel::{DefinitionId, TopLevelDef}, toplevel::{DefinitionId, TopLevelDef},
typecheck::{ typecheck::{
type_inferencer::PrimitiveStore, type_inferencer::PrimitiveStore,
@ -14,7 +14,7 @@ use pyo3::{
types::{PyList, PyModule, PyTuple}, types::{PyList, PyModule, PyTuple},
PyAny, PyObject, PyResult, Python, PyAny, PyObject, PyResult, Python,
}; };
use nac3parser::ast::StrRef; use nac3parser::ast::{self, StrRef};
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
@ -616,9 +616,89 @@ impl Resolver {
} }
} }
} }
fn get_default_param_obj_value(&self, obj: &PyAny, helper: &PythonHelper) -> PyResult<Result<SymbolValue, String>> {
let ty_id: u64 = helper
.id_fn
.call1((helper.type_fn.call1((obj,))?,))?
.extract()?;
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(
elem,
helper
)
})
.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.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() {
let builtins = PyModule::import(py, "builtins")?;
let typings = PyModule::import(py, "typing")?;
let helper = PythonHelper {
id_fn: builtins.getattr("id").unwrap(),
len_fn: builtins.getattr("len").unwrap(),
type_fn: builtins.getattr("type").unwrap(),
origin_ty_fn: typings.getattr("get_origin").unwrap(),
args_ty_fn: typings.getattr("get_args").unwrap(),
};
sym_value = Some(self.get_default_param_obj_value(val, &helper).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,

View File

@ -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

View File

@ -7,7 +7,7 @@ use crate::{
}, },
symbol_resolver::SymbolValue, symbol_resolver::SymbolValue,
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},
@ -21,6 +21,31 @@ use nac3parser::ast::{
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,
@ -36,23 +61,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 {

View File

@ -280,7 +280,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

View File

@ -37,6 +37,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,

View File

@ -44,6 +44,7 @@ pub trait SymbolResolver {
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
) -> Option<BasicValueEnum<'ctx>>; ) -> Option<BasicValueEnum<'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.
} }

View File

@ -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::*;
@ -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,

View File

@ -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))
}
} }

View File

@ -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::*;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -282,9 +282,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);

View File

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

View File

@ -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 {

View File

@ -2,7 +2,7 @@ use inkwell::values::BasicValueEnum;
use nac3core::{ use nac3core::{
codegen::CodeGenContext, codegen::CodeGenContext,
location::Location, location::Location,
symbol_resolver::SymbolResolver, symbol_resolver::{SymbolResolver, SymbolValue},
toplevel::{DefinitionId, TopLevelDef}, toplevel::{DefinitionId, TopLevelDef},
typecheck::{ typecheck::{
type_inferencer::PrimitiveStore, type_inferencer::PrimitiveStore,
@ -10,13 +10,14 @@ use nac3core::{
}, },
}; };
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use nac3parser::ast::StrRef; use nac3parser::ast::{self, StrRef};
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
pub struct ResolverInternal { 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 {
@ -27,11 +28,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,

View File

@ -4,8 +4,8 @@ use inkwell::{
OptimizationLevel, OptimizationLevel,
}; };
use nac3core::typecheck::type_inferencer::PrimitiveStore; use nac3core::typecheck::type_inferencer::PrimitiveStore;
use nac3parser::{ast::{ExprKind, StmtKind}, 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,36 +67,60 @@ fn main() {
); );
for stmt in parser_result.into_iter() { for stmt in parser_result.into_iter() {
// handle type vars in toplevel if let StmtKind::Assign { targets, value, .. } = &stmt.node {
if let StmtKind::Assign { value, targets, .. } = &stmt.node { fn handle_assignment_pattern(
Outdated
Review

Again, is it difficult to iterate?

Again, is it difficult to iterate?
assert_eq!(targets.len(), 1, "only support single assignment for now, at {}", targets[0].location); targets: &[Expr],
if let ExprKind::Call { func, args, .. } = &value.node { value: &Expr,
if matches!(&func.node, ExprKind::Name { id, .. } if id == &"TypeVar".into()) { resolver: &(dyn SymbolResolver + Send + Sync),
Outdated
Review

Remove print. If we want this sort of debug output we should use the logger crate.

Remove print. If we want this sort of debug output we should use the logger crate.
let constraints = args internal_resolver: &ResolverInternal,
.iter() ) -> Result<(), String> {
.skip(1) if targets.len() == 1 {
.map(|x| { match &targets[0].node {
let def_list = &composer.extract_def_list(); ExprKind::Name { id, .. } => {
let unifier = &mut composer.unifier; let val = parse_parameter_default_value(value.borrow(), resolver)?;
resolver.parse_type_annotation( internal_resolver.add_module_global(*id, val);
def_list, Ok(())
unifier, }
&primitive, ExprKind::List { elts, .. }
x | ExprKind::Tuple { elts, .. } => {
).unwrap() handle_assignment_pattern(elts, value, resolver, internal_resolver)?;
}) Ok(())
.collect::<Vec<_>>(); }
let res_ty = composer.unifier.get_fresh_var_with_range(&constraints).0; _ => unreachable!("cannot be assigned")
internal_resolver.add_id_type( }
Outdated
Review

same

same
if let ExprKind::Name { id, .. } = &targets[0].node { *id } else { } else {
Outdated
Review

Do not call panic from errors in user code. Proper error message and Python exceptions are required here.

Do not call panic from errors in user code. Proper error message and Python exceptions are required here.

Thanks for pointing this out, yes this and the previous issue about iterating over assignment should be resolved. Sorry that I forgot to handle these earlier..

Since this is basically the same place in the code as the default default parameter support (in nac3standalone/src/main.rs), maybe I will wait for that one to be mereged first and then modify this PR?

Thanks for pointing this out, yes this and the previous issue about iterating over assignment should be resolved. Sorry that I forgot to handle these earlier.. Since this is basically the same place in the code as the default default parameter support (in `nac3standalone/src/main.rs`), maybe I will wait for that one to be mereged first and then modify this PR?
Outdated
Review

Other PR merged.

Other PR merged.

Hi, the new commits resolves the conflict, and support iteration over multiple typevar assignments in the same line. I will also see if my previous PRs introduce the bug newly found..

Hi, the new commits resolves the conflict, and support iteration over multiple typevar assignments in the same line. I will also see if my previous PRs introduce the bug newly found..
panic!("must assign simple name variable as type variable") 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(())
}
}, },
res_ty _ => 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; 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())
@ -131,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,