This commit is contained in:
abdul124 2024-08-28 09:53:28 +08:00
parent 70d033da61
commit 194fbc51ab
9 changed files with 338 additions and 457 deletions

View File

@ -180,7 +180,9 @@
clippy clippy
pre-commit pre-commit
rustfmt rustfmt
rust-analyzer
]; ];
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
shellHook = shellHook =
'' ''
export DEMO_LINALG_STUB=${packages.x86_64-linux.demo-linalg-stub}/lib/liblinalg.a export DEMO_LINALG_STUB=${packages.x86_64-linux.demo-linalg-stub}/lib/liblinalg.a

Binary file not shown.

Binary file not shown.

View File

@ -1,26 +1,87 @@
from min_artiq import * from min_artiq import *
from numpy import int32
# @nac3
# class A:
# a: int32
# core: KernelInvariant[Core]
# def __init__(self, a: int32):
# self.core = Core()
# self.a = a
# @kernel
# def output_all_fields(self):
# #print(self.a)
# pass
# @kernel
# def set_a(self, a: int32):
# self.a = a
# @nac3
# class B(A):
# b: int32
# def __init__(self, b: int32):
# # A.__init__(self, b + 1)
# self.core = Core()
# self.a = b
# self.b = b
# self.set_b(b)
# @kernel
# def output_parent_fields(self):
# # A.output_all_fields(self)
# pass
# @kernel
# def output_all_fields(self):
# # A.output_all_fields(self)
# pass
# #print(self.b)
# @kernel
# def set_b(self, b: int32):
# self.b = b
@nac3 @nac3
class Demo: class C:
c: Kernel[int32]
a: Kernel[int32]
b: Kernel[int32]
core: KernelInvariant[Core] core: KernelInvariant[Core]
led0: KernelInvariant[TTLOut]
led1: KernelInvariant[TTLOut]
def __init__(self): def __init__(self, c: int32):
# B.__init__(self, c + 1)
self.core = Core() self.core = Core()
self.led0 = TTLOut(self.core, 18) self.a = c
self.led1 = TTLOut(self.core, 19) self.b = c
self.c = c
@kernel
def output_parent_fields(self):
# B.output_all_fields(self)
pass
@kernel @kernel
def run(self): def output_all_fields(self):
self.core.reset() # B.output_all_fields(self)
while True: #print(self.c)
with parallel: pass
self.led0.pulse(100.*ms)
self.led1.pulse(100.*ms)
self.core.delay(100.*ms)
@kernel
def set_c(self, c: int32):
self.c = c
@kernel
def run(self):
self.output_all_fields()
# self.set_a(1)
# self.set_b(2)
self.set_c(3)
self.output_all_fields()
if __name__ == "__main__": if __name__ == "__main__":
Demo().run() C(10).run()

BIN
nac3artiq/demo/module.elf Normal file

Binary file not shown.

View File

@ -1,3 +1,4 @@
use indexmap::IndexMap;
use nac3parser::ast::fold::Fold; use nac3parser::ast::fold::Fold;
use std::rc::Rc; use std::rc::Rc;
@ -5,7 +6,7 @@ use crate::{
codegen::{expr::get_subst_key, stmt::exn_constructor}, codegen::{expr::get_subst_key, stmt::exn_constructor},
symbol_resolver::SymbolValue, symbol_resolver::SymbolValue,
typecheck::{ typecheck::{
type_inferencer::{FunctionData, Inferencer}, type_inferencer::{report_error, FunctionData, Inferencer},
typedef::{TypeVar, VarMap}, typedef::{TypeVar, VarMap},
}, },
}; };
@ -389,8 +390,15 @@ impl TopLevelComposer {
} }
pub fn start_analysis(&mut self, inference: bool) -> Result<(), HashSet<String>> { pub fn start_analysis(&mut self, inference: bool) -> Result<(), HashSet<String>> {
self.analyze_top_level_class_type_var()?; let unifier = self.unifier.borrow_mut();
self.analyze_top_level_class_bases()?; let primitives_store = &self.primitives_ty;
let def_list = &self.definition_ast_list;
// Step 1. Analyze type variables within class definitions
Self::analyze_top_level_class_type_var2(def_list, unifier, primitives_store, (&self.keyword_list, &self.core_config))?;
// self.analyze_top_level_class_type_var()?;
// self.analyze_top_level_class_bases()?;
self.analyze_top_level_class_fields_methods()?; self.analyze_top_level_class_fields_methods()?;
self.analyze_top_level_function()?; self.analyze_top_level_function()?;
if inference { if inference {
@ -399,178 +407,70 @@ impl TopLevelComposer {
Ok(()) Ok(())
} }
/// step 1, analyze the type vars associated with top level class fn analyze_bases(
fn analyze_top_level_class_type_var(&mut self) -> Result<(), HashSet<String>> { class_def: &Arc<RwLock<TopLevelDef>>,
let def_list = &self.definition_ast_list; class_ast: &Option<Stmt>,
let temp_def_list = self.extract_def_list(); temp_def_list: &[Arc<RwLock<TopLevelDef>>],
let unifier = self.unifier.borrow_mut(); unifier: &mut Unifier,
let primitives_store = &self.primitives_ty; primitives_store: &PrimitiveStore,
) -> Result<(), HashSet<String>> {
let mut analyze = |class_def: &Arc<RwLock<TopLevelDef>>, class_ast: &Option<Stmt>| { let mut class_def = class_def.write();
// only deal with class def here let (class_def_id, class_ancestors, class_bases_ast, class_type_vars, class_resolver) = {
let mut class_def = class_def.write(); let TopLevelDef::Class { object_id, ancestors, type_vars, resolver, .. } =
let (class_bases_ast, class_def_type_vars, class_resolver) = { &mut *class_def
if let TopLevelDef::Class { type_vars, resolver, .. } = &mut *class_def { else {
let Some(ast::Located { node: ast::StmtKind::ClassDef { bases, .. }, .. }) = unreachable!()
class_ast
else {
unreachable!()
};
(bases, type_vars, resolver)
} else {
return Ok(());
}
}; };
let class_resolver = class_resolver.as_ref().unwrap(); let Some(ast::Located { node: ast::StmtKind::ClassDef { bases, .. }, .. }) = class_ast
let class_resolver = &**class_resolver; else {
unreachable!()
let mut is_generic = false; };
for b in class_bases_ast { (object_id, ancestors, bases, type_vars, resolver.as_ref().unwrap().as_ref())
match &b.node {
// analyze typevars bounded to the class,
// only support things like `class A(Generic[T, V])`,
// things like `class A(Generic[T, V, ImportedModule.T])` is not supported
// i.e. only simple names are allowed in the subscript
// should update the TopLevelDef::Class.typevars and the TypeEnum::TObj.params
ast::ExprKind::Subscript { value, slice, .. }
if {
matches!(
&value.node,
ast::ExprKind::Name { id, .. } if id == &"Generic".into()
)
} =>
{
if is_generic {
return Err(HashSet::from([format!(
"only single Generic[...] is allowed (at {})",
b.location
)]));
}
is_generic = true;
let type_var_list: Vec<&ast::Expr<()>>;
// if `class A(Generic[T, V, G])`
if let ast::ExprKind::Tuple { elts, .. } = &slice.node {
type_var_list = elts.iter().collect_vec();
// `class A(Generic[T])`
} else {
type_var_list = vec![&**slice];
}
// parse the type vars
let type_vars = type_var_list
.into_iter()
.map(|e| {
class_resolver.parse_type_annotation(
&temp_def_list,
unifier,
primitives_store,
e,
)
})
.collect::<Result<Vec<_>, _>>()?;
// check if all are unique type vars
let all_unique_type_var = {
let mut occurred_type_var_id: HashSet<TypeVarId> = HashSet::new();
type_vars.iter().all(|x| {
let ty = unifier.get_ty(*x);
if let TypeEnum::TVar { id, .. } = ty.as_ref() {
occurred_type_var_id.insert(*id)
} else {
false
}
})
};
if !all_unique_type_var {
return Err(HashSet::from([format!(
"duplicate type variable occurs (at {})",
slice.location
)]));
}
// add to TopLevelDef
class_def_type_vars.extend(type_vars);
}
// if others, do nothing in this function
_ => continue,
}
}
Ok(())
}; };
let mut errors = HashSet::new();
for (class_def, class_ast) in def_list.iter().skip(self.builtin_num) {
if class_ast.is_none() {
continue;
}
if let Err(e) = analyze(class_def, class_ast) {
errors.extend(e);
}
}
if !errors.is_empty() {
return Err(errors);
}
Ok(())
}
/// step 2, base classes. let mut is_generic = false;
/// now that the type vars of all classes are done, handle base classes and let mut has_base = false;
/// put Self class into the ancestors list. We only allow single inheritance // Check class bases for typevars
fn analyze_top_level_class_bases(&mut self) -> Result<(), HashSet<String>> { for b in class_bases_ast {
if self.unifier.top_level.is_none() { match &b.node {
let ctx = Arc::new(self.make_top_level_context()); // analyze typevars bounded to the class,
self.unifier.top_level = Some(ctx); // only support things like `class A(Generic[T, V])`,
} // things like `class A(Generic[T, V, ImportedModule.T])` is not supported
// i.e. only simple names are allowed in the subscript
// should update the TopLevelDef::Class.typevars and the TypeEnum::TObj.params
ast::ExprKind::Subscript { value, slice, .. } if matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"Generic".into()) =>
{
if is_generic {
return report_error("only single Generic[...] is allowed", b.location);
}
is_generic = true;
let temp_def_list = self.extract_def_list(); let type_var_list: Vec<&ast::Expr<()>>;
let unifier = self.unifier.borrow_mut(); // if `class A(Generic[T, V, G])`
let primitive_types = self.primitives_ty; if let ast::ExprKind::Tuple { elts, .. } = &slice.node {
type_var_list = elts.iter().collect_vec();
let mut get_direct_parents = // `class A(Generic[T])`
|class_def: &Arc<RwLock<TopLevelDef>>, class_ast: &Option<Stmt>| {
let mut class_def = class_def.write();
let (class_def_id, class_bases, class_ancestors, class_resolver, class_type_vars) = {
if let TopLevelDef::Class {
ancestors, resolver, object_id, type_vars, ..
} = &mut *class_def
{
let Some(ast::Located {
node: ast::StmtKind::ClassDef { bases, .. }, ..
}) = class_ast
else {
unreachable!()
};
(object_id, bases, ancestors, resolver, type_vars)
} else { } else {
return Ok(()); type_var_list = vec![&**slice];
} }
};
let class_resolver = class_resolver.as_ref().unwrap();
let class_resolver = &**class_resolver;
let mut has_base = false; let type_vars = type_var_list
for b in class_bases { .into_iter()
// type vars have already been handled, so skip on `Generic[...]` .map(|e| {
if matches!( class_resolver.parse_type_annotation(
&b.node, temp_def_list,
ast::ExprKind::Subscript { value, .. } unifier,
if matches!( primitives_store,
&value.node, e,
ast::ExprKind::Name { id, .. } if id == &"Generic".into()
) )
) { })
continue; .collect::<Result<Vec<_>, _>>()?;
}
class_type_vars.extend(type_vars);
}
ast::ExprKind::Name { .. } => {
if has_base { if has_base {
return Err(HashSet::from([format!( return report_error("a class definition can only have at most one base class declaration and one generic declaration", b.location);
"a class definition can only have at most one base class \
declaration and one generic declaration (at {})",
b.location
)]));
} }
has_base = true; has_base = true;
@ -578,9 +478,9 @@ impl TopLevelComposer {
// bast_ty if it is a CustomClassKind // bast_ty if it is a CustomClassKind
let base_ty = parse_ast_to_type_annotation_kinds( let base_ty = parse_ast_to_type_annotation_kinds(
class_resolver, class_resolver,
&temp_def_list, temp_def_list,
unifier, unifier,
&primitive_types, primitives_store,
b, b,
vec![(*class_def_id, class_type_vars.clone())] vec![(*class_def_id, class_type_vars.clone())]
.into_iter() .into_iter()
@ -590,123 +490,127 @@ impl TopLevelComposer {
if let TypeAnnotation::CustomClass { .. } = &base_ty { if let TypeAnnotation::CustomClass { .. } = &base_ty {
class_ancestors.push(base_ty); class_ancestors.push(base_ty);
} else { } else {
return Err(HashSet::from([format!( return report_error(
"class base declaration can only be custom class (at {})", "class base declaration can only be custom class",
b.location, b.location,
)])); );
} }
} }
Ok(()) // TODO: Report Error here
}; _ => {
println!("Type was => {}", b.node.name());
}
}
}
// first, only push direct parent into the list Ok(())
}
fn analyze_ancestors(
class_def: &Arc<RwLock<TopLevelDef>>,
temp_def_list: &[Arc<RwLock<TopLevelDef>>],
) {
// Check if class has a direct parent
let mut class_def = class_def.write();
let TopLevelDef::Class { ancestors, type_vars, object_id, .. } = &mut *class_def else {
unreachable!()
};
let mut anc_set = HashMap::new();
if let Some(ancestor) = ancestors.first() {
let TypeAnnotation::CustomClass { id, .. } = ancestor else { unreachable!() };
let TopLevelDef::Class { ancestors: parent_ancestors, .. } =
&*temp_def_list[id.0].read()
else {
unreachable!()
};
for anc in parent_ancestors.iter().skip(1) {
let TypeAnnotation::CustomClass { id, .. } = anc else { unreachable!() };
anc_set.insert(id, anc.clone());
}
ancestors.extend(anc_set.into_iter().map(|f| f.1).collect::<Vec<_>>());
}
ancestors.insert(0, make_self_type_annotation(type_vars.as_slice(), *object_id));
}
/// step 1, analyze the type vars associated with top level class
fn analyze_top_level_class_type_var2(
def_list: &[DefAst],
unifier: &mut Unifier,
primitives_store: &PrimitiveStore,
core_info: (&HashSet<StrRef>, &ComposerConfig),
) -> Result<(), HashSet<String>> {
let mut errors = HashSet::new(); let mut errors = HashSet::new();
for (class_def, class_ast) in self.definition_ast_list.iter_mut().skip(self.builtin_num) { let mut temp_def_list: Vec<Arc<RwLock<TopLevelDef>>> = Vec::default();
if class_ast.is_none() {
continue;
}
if let Err(e) = get_direct_parents(class_def, class_ast) {
errors.extend(e);
}
}
if !errors.is_empty() {
return Err(errors);
}
// second, get all ancestors for (class_def, class_ast) in def_list {
let mut ancestors_store: HashMap<DefinitionId, Vec<TypeAnnotation>> = HashMap::default(); if class_ast.is_some() && matches!(&*class_def.read(), TopLevelDef::Class { .. }) {
let mut get_all_ancestors = // Add type vars and direct parents
|class_def: &Arc<RwLock<TopLevelDef>>| -> Result<(), HashSet<String>> { if let Err(e) = Self::analyze_bases(
let class_def = class_def.read(); class_def,
let (class_ancestors, class_id) = { class_ast,
if let TopLevelDef::Class { ancestors, object_id, .. } = &*class_def { &temp_def_list,
(ancestors, *object_id) unifier,
} else { primitives_store,
return Ok(()); ) {
} errors.extend(e);
};
ancestors_store.insert(
class_id,
// if class has direct parents, get all ancestors of its parents. Else just empty
if class_ancestors.is_empty() {
vec![]
} else {
Self::get_all_ancestors_helper(
&class_ancestors[0],
temp_def_list.as_slice(),
)?
},
);
Ok(())
};
for (class_def, ast) in self.definition_ast_list.iter().skip(self.builtin_num) {
if ast.is_none() {
continue;
}
if let Err(e) = get_all_ancestors(class_def) {
errors.extend(e);
}
}
if !errors.is_empty() {
return Err(errors);
}
// insert the ancestors to the def list
for (class_def, class_ast) in self.definition_ast_list.iter_mut().skip(self.builtin_num) {
if class_ast.is_none() {
continue;
}
let mut class_def = class_def.write();
let (class_ancestors, class_id, class_type_vars) = {
if let TopLevelDef::Class { ancestors, object_id, type_vars, .. } = &mut *class_def
{
(ancestors, *object_id, type_vars)
} else {
continue;
} }
}; // Get class ancestors order matters here. Like python we will only consider classes to be correct if they are in same order
Self::analyze_ancestors(class_def, &temp_def_list);
let ans = ancestors_store.get_mut(&class_id).unwrap(); let mut type_var_to_concrete_def: HashMap<Type, TypeAnnotation> = HashMap::new();
class_ancestors.append(ans); if let Err(e) = Self::analyze_single_class_methods_fields(
class_def,
&class_ast.as_ref().unwrap().node,
&temp_def_list,
unifier,
primitives_store,
&mut type_var_to_concrete_def,
core_info,
) {
errors.extend(e);
}
// insert self type annotation to the front of the vector to maintain the order // special case classes that inherit from Exception
class_ancestors let TopLevelDef::Class { ancestors: class_ancestors, loc, .. } = &*class_def.read()
.insert(0, make_self_type_annotation(class_type_vars.as_slice(), class_id)); else {
// special case classes that inherit from Exception
if class_ancestors
.iter()
.any(|ann| matches!(ann, TypeAnnotation::CustomClass { id, .. } if id.0 == 7))
{
// if inherited from Exception, the body should be a pass
let ast::StmtKind::ClassDef { body, .. } = &class_ast.as_ref().unwrap().node else {
unreachable!() unreachable!()
}; };
if class_ancestors
for stmt in body { .iter()
if matches!( .any(|ann| matches!(ann, TypeAnnotation::CustomClass { id, .. } if id.0 == 7))
stmt.node, {
ast::StmtKind::FunctionDef { .. } | ast::StmtKind::AnnAssign { .. } // if inherited from Exception, the body should be a pass
) { let ast::StmtKind::ClassDef { body, .. } = &class_ast.as_ref().unwrap().node
return Err(HashSet::from([ else {
"Classes inherited from exception should have no custom fields/methods" unreachable!()
.into(), };
])); for stmt in body {
if matches!(
stmt.node,
ast::StmtKind::FunctionDef { .. } | ast::StmtKind::AnnAssign { .. }
) {
errors.extend(report_error("Classes inherited from exception should have no custom fields/methods", loc.unwrap()));
}
} }
} }
} }
// println!("Adding class_def of {name} to the temp_def_list with ID {}", object_id.0);
temp_def_list.push(class_def.clone());
} }
// deal with ancestor of Exception object // deal with ancestor of Exception object
let TopLevelDef::Class { name, ancestors, object_id, .. } = let TopLevelDef::Class { name, ancestors, object_id, .. } = &mut *def_list[7].0.write()
&mut *self.definition_ast_list[7].0.write()
else { else {
unreachable!() unreachable!()
}; };
assert_eq!(*name, "Exception".into()); assert_eq!(*name, "Exception".into());
ancestors.push(make_self_type_annotation(&[], *object_id)); ancestors.push(make_self_type_annotation(&[], *object_id));
if !errors.is_empty() {
return Err(errors);
}
Ok(()) Ok(())
} }
@ -1199,126 +1103,81 @@ impl TopLevelComposer {
let mut method_var_map = VarMap::new(); let mut method_var_map = VarMap::new();
let arg_types: Vec<FuncArg> = { let arg_types: Vec<FuncArg> = {
// check method parameters cannot have same name // Function arguments must have:
// 1) `self` as first argument
// 2) unique names
// 3) names different than keywords
match args.args.first() {
Some(id) if id.node.arg == "self".into() => {},
_ => return report_error("class method must have a `self` parameter", b.location),
}
let mut defined_parameter_name: HashSet<_> = HashSet::new(); let mut defined_parameter_name: HashSet<_> = HashSet::new();
let zelf: StrRef = "self".into(); for arg in args.args.iter().skip(1) {
for x in &args.args { if !defined_parameter_name.insert(arg.node.arg) {
if !defined_parameter_name.insert(x.node.arg) return report_error("class method must have a unique parameter names", b.location)
|| (keyword_list.contains(&x.node.arg) && x.node.arg != zelf) }
{ if keyword_list.contains(&arg.node.arg) {
return Err(HashSet::from([ return report_error("parameter names should not be the same as the keywords", b.location)
format!("top level function must have unique parameter names \
and names should not be the same as the keywords (at {})",
x.location),
]))
} }
} }
if name == &"__init__".into() && !defined_parameter_name.contains(&zelf) { // `self` must not be provided type annotation or default value
return Err(HashSet::from([ if args.args.len() == args.defaults.len() {
format!("__init__ method must have a `self` parameter (at {})", b.location), return report_error("`self` cannot have a default value", b.location)
]))
} }
if !defined_parameter_name.contains(&zelf) { if args.args[0].node.annotation.is_some() {
return Err(HashSet::from([ return report_error("`self` cannot have a type annotation", b.location)
format!("class method must have a `self` parameter (at {})", b.location),
]))
} }
let mut result = Vec::new(); let mut result = Vec::new();
let no_defaults = args.args.len() - args.defaults.len() - 1;
let arg_with_default: Vec<( for (idx, x) in itertools::enumerate(args.args.iter().skip(1)) {
&ast::Located<ast::ArgData<()>>, let type_ann = {
Option<&ast::Expr>, let Some(annotation_expr) = x.node.annotation.as_ref() else {return report_error(format!("type annotation needed for `{}`", x.node.arg).as_str(), x.location)};
)> = args parse_ast_to_type_annotation_kinds(
.args class_resolver,
.iter() temp_def_list,
.rev() unifier,
.zip( primitives,
args.defaults annotation_expr,
.iter() vec![(class_id, class_type_vars_def.clone())]
.rev() .into_iter()
.map(|x| -> Option<&ast::Expr> { Some(x) }) .collect::<HashMap<_, _>>(),
.chain(std::iter::repeat(None)), )?
) };
.collect_vec(); // find type vars within this method parameter type annotation
let type_vars_within = get_type_var_contained_in_type_annotation(&type_ann);
for (x, default) in arg_with_default.into_iter().rev() { // handle the class type var and the method type var
let name = x.node.arg; for type_var_within in type_vars_within {
if name != zelf { let TypeAnnotation::TypeVar(ty) = type_var_within else {
let type_ann = { unreachable!("must be type var annotation")
let annotation_expr = x
.node
.annotation
.as_ref()
.ok_or_else(|| HashSet::from([
format!(
"type annotation needed for `{}` at {}",
x.node.arg, x.location
),
]))?
.as_ref();
parse_ast_to_type_annotation_kinds(
class_resolver,
temp_def_list,
unifier,
primitives,
annotation_expr,
vec![(class_id, class_type_vars_def.clone())]
.into_iter()
.collect::<HashMap<_, _>>(),
)?
}; };
// find type vars within this method parameter type annotation
let type_vars_within =
get_type_var_contained_in_type_annotation(&type_ann);
// handle the class type var and the method type var
for type_var_within in type_vars_within {
let TypeAnnotation::TypeVar(ty) = type_var_within else {
unreachable!("must be type var annotation")
};
let id = Self::get_var_id(ty, unifier)?; let id = Self::get_var_id(ty, unifier)?;
if let Some(prev_ty) = method_var_map.insert(id, ty) { if let Some(prev_ty) = method_var_map.insert(id, ty) {
// if already in the list, make sure they are the same? // if already in the list, make sure they are the same?
assert_eq!(prev_ty, ty); assert_eq!(prev_ty, ty);
}
} }
// finish handling type vars
let dummy_func_arg = FuncArg {
name,
ty: unifier.get_dummy_var().ty,
default_value: match default {
None => None,
Some(default) => {
if name == "self".into() {
return Err(HashSet::from([
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| HashSet::from([
format!("{} (at {})", err, x.location),
]))?;
v
})
}
},
is_vararg: false,
};
// push the dummy type and the type annotation
// into the list for later unification
type_var_to_concrete_def
.insert(dummy_func_arg.ty, type_ann.clone());
result.push(dummy_func_arg);
} }
// finish handling type vars
let dummy_func_arg = FuncArg {
name: x.node.arg,
ty: unifier.get_dummy_var().ty,
default_value: if idx < no_defaults { None } else {
let default_idx = idx - no_defaults;
Some({
let v = Self::parse_parameter_default_value(&args.defaults[default_idx], class_resolver)?;
Self::check_default_param_type(&v, &type_ann, primitives, unifier).map_err(|err| report_error::<()>(err.as_str(), x.location).unwrap_err())?;
v
})
},
is_vararg: false,
};
// push the dummy type and the type annotation
// into the list for later unification
type_var_to_concrete_def
.insert(dummy_func_arg.ty, type_ann.clone());
result.push(dummy_func_arg);
} }
result result
}; };
@ -1440,23 +1299,13 @@ impl TopLevelComposer {
match v { match v {
ast::Constant::Bool(_) | ast::Constant::Str(_) | ast::Constant::Int(_) | ast::Constant::Float(_) => {} ast::Constant::Bool(_) | ast::Constant::Str(_) | ast::Constant::Int(_) | ast::Constant::Float(_) => {}
_ => { _ => {
return Err(HashSet::from([ return report_error("unsupported statement in class definition body", b.location)
format!(
"unsupported statement in class definition body (at {})",
b.location
),
]))
} }
} }
class_attributes_def.push((*attr, dummy_field_type, v.clone())); class_attributes_def.push((*attr, dummy_field_type, v.clone()));
} }
_ => { _ => {
return Err(HashSet::from([ return report_error("unsupported statement in class definition body", b.location)
format!(
"unsupported statement in class definition body (at {})",
b.location
),
]))
} }
} }
annotation annotation
@ -1482,43 +1331,22 @@ impl TopLevelComposer {
}; };
if !class_type_vars_def.contains(&t) { if !class_type_vars_def.contains(&t) {
return Err(HashSet::from([ return report_error("class fields can only use type vars over which the class is generic", b.location)
format!(
"class fields can only use type \
vars over which the class is generic (at {})",
annotation.location
),
]))
} }
} }
type_var_to_concrete_def.insert(dummy_field_type, parsed_annotation); type_var_to_concrete_def.insert(dummy_field_type, parsed_annotation);
} else { } else {
return Err(HashSet::from([ return report_error(format!("same class fields `{}` defined twice", attr).as_str(), target.location)
format!(
"same class fields `{}` defined twice (at {})",
attr, target.location
),
]))
} }
} else { } else {
return Err(HashSet::from([ return report_error("unsupported statement in class definition body", target.location)
format!(
"unsupported statement type in class definition body (at {})",
target.location
),
]))
} }
} }
ast::StmtKind::Assign { .. } // we don't class attributes ast::StmtKind::Assign { .. } // we don't class attributes
| ast::StmtKind::Expr { value: _, .. } // typically a docstring; ignoring all expressions matches CPython behavior | ast::StmtKind::Expr { value: _, .. } // typically a docstring; ignoring all expressions matches CPython behavior
| ast::StmtKind::Pass { .. } => {} | ast::StmtKind::Pass { .. } => {}
_ => { _ => {
return Err(HashSet::from([ return report_error("unsupported statement in class definition body", b.location)
format!(
"unsupported statement in class definition body (at {})",
b.location
),
]))
} }
} }
} }
@ -1570,44 +1398,27 @@ impl TopLevelComposer {
// handle methods override // handle methods override
// since we need to maintain the order, create a new list // since we need to maintain the order, create a new list
let mut new_child_methods: Vec<(StrRef, Type, DefinitionId)> = Vec::new(); let mut new_child_methods: IndexMap<StrRef, (Type, DefinitionId)> = methods.iter().map(|m| (m.0.clone(), (m.1.clone(), m.2.clone()))).collect();
let mut is_override: HashSet<StrRef> = HashSet::new(); // let mut new_child_methods: Vec<(StrRef, Type, DefinitionId)> = methods.clone();
for (anc_method_name, anc_method_ty, anc_method_def_id) in methods { for (class_method_name, class_method_ty, class_method_defid) in &*class_methods_def {
// find if there is a method with same name in the child class if let Some((ty, _ ) ) = new_child_methods.insert(*class_method_name, (*class_method_ty, *class_method_defid)) {
let mut to_be_added = (*anc_method_name, *anc_method_ty, *anc_method_def_id); let ok = class_method_name == &"__init__".into()
for (class_method_name, class_method_ty, class_method_defid) in &*class_methods_def { || Self::check_overload_function_type(
if class_method_name == anc_method_name { *class_method_ty,
// ignore and handle self ty,
// if is __init__ method, no need to check return type unifier,
let ok = class_method_name == &"__init__".into() type_var_to_concrete_def,
|| Self::check_overload_function_type( );
*class_method_ty, if !ok {
*anc_method_ty, return Err(HashSet::from([format!(
unifier, "method {class_method_name} has same name as ancestors' method, but incompatible type"),
type_var_to_concrete_def, ]));
);
if !ok {
return Err(HashSet::from([format!(
"method {class_method_name} has same name as ancestors' method, but incompatible type"),
]));
}
// mark it as added
is_override.insert(*class_method_name);
to_be_added = (*class_method_name, *class_method_ty, *class_method_defid);
break;
} }
} }
new_child_methods.push(to_be_added);
} }
// add those that are not overriding method to the new_child_methods
for (class_method_name, class_method_ty, class_method_defid) in &*class_methods_def {
if !is_override.contains(class_method_name) {
new_child_methods.push((*class_method_name, *class_method_ty, *class_method_defid));
}
}
// use the new_child_methods to replace all the elements in `class_methods_def`
class_methods_def.clear(); class_methods_def.clear();
class_methods_def.extend(new_child_methods); class_methods_def.extend(new_child_methods.iter().map(|f| (f.0.clone(), f.1.0, f.1.1)).collect_vec());
let is_override: HashSet<StrRef> = HashSet::new();
// handle class fields // handle class fields
let mut new_child_fields: Vec<(StrRef, Type, bool)> = Vec::new(); let mut new_child_fields: Vec<(StrRef, Type, bool)> = Vec::new();

View File

@ -1,6 +1,7 @@
use super::*; use super::*;
use crate::symbol_resolver::SymbolValue; use crate::symbol_resolver::SymbolValue;
use crate::toplevel::helper::{PrimDef, PrimDefDetails}; use crate::toplevel::helper::{PrimDef, PrimDefDetails};
use crate::typecheck::type_inferencer::report_error;
use crate::typecheck::typedef::VarMap; use crate::typecheck::typedef::VarMap;
use nac3parser::ast::Constant; use nac3parser::ast::Constant;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
@ -97,7 +98,13 @@ pub fn parse_ast_to_type_annotation_kinds<T, S: std::hash::BuildHasher + Clone>(
Ok(TypeAnnotation::CustomClass { id: PrimDef::Exception.id(), params: Vec::default() }) Ok(TypeAnnotation::CustomClass { id: PrimDef::Exception.id(), params: Vec::default() })
} else if let Ok(obj_id) = resolver.get_identifier_def(*id) { } else if let Ok(obj_id) = resolver.get_identifier_def(*id) {
let type_vars = { let type_vars = {
let def_read = top_level_defs[obj_id.0].try_read(); let Some(top_level_def) = top_level_defs.get(obj_id.0) else {
return report_error(
format!("Name Error undefined name {id}").as_str(),
expr.location,
);
};
let def_read = top_level_def.try_read();
if let Some(def_read) = def_read { if let Some(def_read) = def_read {
if let TopLevelDef::Class { type_vars, .. } = &*def_read { if let TopLevelDef::Class { type_vars, .. } = &*def_read {
type_vars.clone() type_vars.clone()

View File

@ -114,7 +114,7 @@ impl Fold<()> for NaiveFolder {
} }
} }
fn report_error<T>(msg: &str, location: Location) -> Result<T, InferenceError> { pub fn report_error<T>(msg: &str, location: Location) -> Result<T, InferenceError> {
Err(HashSet::from([format!("{msg} at {location}")])) Err(HashSet::from([format!("{msg} at {location}")]))
} }

BIN
pyo3/nac3artiq.so Executable file

Binary file not shown.