Compare commits

..

3 Commits

7 changed files with 38 additions and 22 deletions

View File

@ -36,7 +36,7 @@ pub trait CodeGenerator {
} }
/// Generate object constructor and returns the constructed object. /// Generate object constructor and returns the constructed object.
/// - signature: Function signature of the constructor. /// - signature: Function signature of the contructor.
/// - def: Class definition for the constructor class. /// - def: Class definition for the constructor class.
/// - params: Function parameters. /// - params: Function parameters.
fn gen_constructor<'ctx, 'a>( fn gen_constructor<'ctx, 'a>(

View File

@ -228,6 +228,7 @@ impl TopLevelComposer {
// subclass of other exception classes. // subclass of other exception classes.
let mut contains_constructor = bases let mut contains_constructor = bases
.iter().any(|base| matches!(base.node, ast::ExprKind::Name { id, .. } if id == exception_id)); .iter().any(|base| matches!(base.node, ast::ExprKind::Name { id, .. } if id == exception_id));
for b in body { for b in body {
if let ast::StmtKind::FunctionDef { name: method_name, .. } = &b.node { if let ast::StmtKind::FunctionDef { name: method_name, .. } = &b.node {
if method_name == &init_id { if method_name == &init_id {
@ -298,7 +299,9 @@ impl TopLevelComposer {
self.definition_ast_list.push((def, Some(ast))); self.definition_ast_list.push((def, Some(ast)));
} }
let result_ty = if contains_constructor { Some(constructor_ty) } else { None }; // Quick way to fix #221, contains constructor can be used in the future for some implementation if required.
let result_ty = if contains_constructor { Some(constructor_ty) } else { Some(constructor_ty) };
Ok((class_name, DefinitionId(class_def_id), result_ty)) Ok((class_name, DefinitionId(class_def_id), result_ty))
} }
@ -434,11 +437,11 @@ impl TopLevelComposer {
// check if all are unique type vars // check if all are unique type vars
let all_unique_type_var = { let all_unique_type_var = {
let mut occurred_type_var_id: HashSet<u32> = HashSet::new(); let mut occured_type_var_id: HashSet<u32> = HashSet::new();
type_vars.iter().all(|x| { type_vars.iter().all(|x| {
let ty = unifier.get_ty(*x); let ty = unifier.get_ty(*x);
if let TypeEnum::TVar { id, .. } = ty.as_ref() { if let TypeEnum::TVar { id, .. } = ty.as_ref() {
occurred_type_var_id.insert(*id) occured_type_var_id.insert(*id)
} else { } else {
false false
} }
@ -536,7 +539,7 @@ impl TopLevelComposer {
} }
has_base = true; has_base = true;
// the function parse_ast_to make sure that no type var occurred in // the function parse_ast_to make sure that no type var occured in
// bast_ty if it is a CustomClassKind // bast_ty if it is a CustomClassKind
let base_ty = parse_ast_to_type_annotation_kinds( let base_ty = parse_ast_to_type_annotation_kinds(
class_resolver, class_resolver,
@ -696,7 +699,7 @@ impl TopLevelComposer {
return Err(errors.into_iter().sorted().join("\n----------\n")); return Err(errors.into_iter().sorted().join("\n----------\n"));
} }
// handle the inherited methods and fields // handle the inheritanced methods and fields
// Note: we cannot defer error handling til the end of the loop, because there is loop // Note: we cannot defer error handling til the end of the loop, because there is loop
// carried dependency, ignoring the error (temporarily) will cause all assumptions to break // carried dependency, ignoring the error (temporarily) will cause all assumptions to break
// and produce weird error messages // and produce weird error messages
@ -825,9 +828,9 @@ impl TopLevelComposer {
let mut function_var_map: HashMap<u32, Type> = HashMap::new(); let mut function_var_map: HashMap<u32, Type> = HashMap::new();
let arg_types = { let arg_types = {
// make sure no duplicate parameter // make sure no duplicate parameter
let mut defined_parameter_name: HashSet<_> = HashSet::new(); let mut defined_paramter_name: HashSet<_> = HashSet::new();
for x in args.args.iter() { for x in args.args.iter() {
if !defined_parameter_name.insert(x.node.arg) if !defined_paramter_name.insert(x.node.arg)
|| keyword_list.contains(&x.node.arg) || keyword_list.contains(&x.node.arg)
{ {
return Err(format!( return Err(format!(
@ -1074,10 +1077,10 @@ impl TopLevelComposer {
let arg_types: Vec<FuncArg> = { let arg_types: Vec<FuncArg> = {
// check method parameters cannot have same name // check method parameters cannot have same name
let mut defined_parameter_name: HashSet<_> = HashSet::new(); let mut defined_paramter_name: HashSet<_> = HashSet::new();
let zelf: StrRef = "self".into(); let zelf: StrRef = "self".into();
for x in args.args.iter() { for x in args.args.iter() {
if !defined_parameter_name.insert(x.node.arg) if !defined_paramter_name.insert(x.node.arg)
|| (keyword_list.contains(&x.node.arg) && x.node.arg != zelf) || (keyword_list.contains(&x.node.arg) && x.node.arg != zelf)
{ {
return Err(format!( return Err(format!(
@ -1088,13 +1091,13 @@ impl TopLevelComposer {
} }
} }
if name == &"__init__".into() && !defined_parameter_name.contains(&zelf) { if name == &"__init__".into() && !defined_paramter_name.contains(&zelf) {
return Err(format!( return Err(format!(
"__init__ method must have a `self` parameter (at {})", "__init__ method must have a `self` parameter (at {})",
b.location b.location
)); ));
} }
if !defined_parameter_name.contains(&zelf) { if !defined_paramter_name.contains(&zelf) {
return Err(format!( return Err(format!(
"class method must have a `self` parameter (at {})", "class method must have a `self` parameter (at {})",
b.location b.location
@ -1227,7 +1230,7 @@ impl TopLevelComposer {
dummy_return_type dummy_return_type
} else { } else {
// if do not have return annotation, return none // if do not have return annotation, return none
// for uniform handling, still use type annotation // for uniform handling, still use type annoatation
let dummy_return_type = unifier.get_dummy_var().0; let dummy_return_type = unifier.get_dummy_var().0;
type_var_to_concrete_def.insert( type_var_to_concrete_def.insert(
dummy_return_type, dummy_return_type,
@ -1468,9 +1471,9 @@ impl TopLevelComposer {
Ok(()) Ok(())
} }
/// step 5, analyze and call type inferencer to fill the `instance_to_stmt` of topleveldef::function /// step 5, analyze and call type inferecer to fill the `instance_to_stmt` of topleveldef::function
fn analyze_function_instance(&mut self) -> Result<(), String> { fn analyze_function_instance(&mut self) -> Result<(), String> {
// first get the class contructor type correct for the following type check in function body // first get the class constructor type correct for the following type check in function body
// also do class field instantiation check // also do class field instantiation check
let init_str_id = "__init__".into(); let init_str_id = "__init__".into();
let mut definition_extension = Vec::new(); let mut definition_extension = Vec::new();
@ -1581,7 +1584,7 @@ impl TopLevelComposer {
return Ok(()); return Ok(());
} }
let mut init_id: Option<DefinitionId> = None; let mut init_id: Option<DefinitionId> = None;
// get the class contructor type correct // get the class constructor type correct
let (contor_args, contor_type_vars) = { let (contor_args, contor_type_vars) = {
let mut constructor_args: Vec<FuncArg> = Vec::new(); let mut constructor_args: Vec<FuncArg> = Vec::new();
let mut type_vars: HashMap<u32, Type> = HashMap::new(); let mut type_vars: HashMap<u32, Type> = HashMap::new();

View File

@ -149,7 +149,7 @@ impl TopLevelComposer {
} }
/// already include the definition_id of itself inside the ancestors vector /// already include the definition_id of itself inside the ancestors vector
/// when first registering, the type_vars, fields, methods, ancestors are invalid /// when first regitering, the type_vars, fields, methods, ancestors are invalid
pub fn make_top_level_class_def( pub fn make_top_level_class_def(
index: usize, index: usize,
resolver: Option<Arc<dyn SymbolResolver + Send + Sync>>, resolver: Option<Arc<dyn SymbolResolver + Send + Sync>>,

View File

@ -436,7 +436,7 @@ pub fn get_type_from_type_annotation_kinds(
/// the type of `self` should be similar to `A[T, V]`, where `T`, `V` /// the type of `self` should be similar to `A[T, V]`, where `T`, `V`
/// considered to be type variables associated with the class \ /// considered to be type variables associated with the class \
/// \ /// \
/// But note that here we do not make a duplication of `T`, `V`, we directly /// But note that here we do not make a duplication of `T`, `V`, we direclty
/// use them as they are in the TopLevelDef::Class since those in the /// use them as they are in the TopLevelDef::Class since those in the
/// TopLevelDef::Class.type_vars will be substitute later when seeing applications/instantiations /// TopLevelDef::Class.type_vars will be substitute later when seeing applications/instantiations
/// the Type of their fields and methods will also be subst when application/instantiation /// the Type of their fields and methods will also be subst when application/instantiation

View File

@ -16,7 +16,7 @@ use crate::toplevel::{DefinitionId, TopLevelContext, TopLevelDef};
#[cfg(test)] #[cfg(test)]
mod test; mod test;
/// Handle for a type, implemented as a key in the unification table. /// Handle for a type, implementated as a key in the unification table.
pub type Type = UnificationKey; pub type Type = UnificationKey;
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]

View File

@ -309,7 +309,7 @@ fn test_unify(
fn test_invalid_unification( fn test_invalid_unification(
variable_count: u32, variable_count: u32,
unify_pairs: &[(&'static str, &'static str)], unify_pairs: &[(&'static str, &'static str)],
erroneous_pair: ((&'static str, &'static str), &'static str), errornous_pair: ((&'static str, &'static str), &'static str),
) { ) {
let mut env = TestEnvironment::new(); let mut env = TestEnvironment::new();
let mut mapping = HashMap::new(); let mut mapping = HashMap::new();
@ -326,11 +326,11 @@ fn test_invalid_unification(
pairs.push((t1, t2)); pairs.push((t1, t2));
} }
let (t1, t2) = let (t1, t2) =
(env.parse(erroneous_pair.0 .0, &mapping), env.parse(erroneous_pair.0 .1, &mapping)); (env.parse(errornous_pair.0 .0, &mapping), env.parse(errornous_pair.0 .1, &mapping));
for (a, b) in pairs { for (a, b) in pairs {
env.unifier.unify(a, b).unwrap(); env.unifier.unify(a, b).unwrap();
} }
assert_eq!(env.unify(t1, t2), Err(erroneous_pair.1.to_string())); assert_eq!(env.unify(t1, t2), Err(errornous_pair.1.to_string()));
} }
#[test] #[test]

View File

@ -0,0 +1,13 @@
@extern
def output_int32(x: int32):
...
class A:
def foo(self):
output_int32(1)
def run() -> int32:
inst = A()
inst.foo()
output_int32(1)
return 0