From e66693282c500dccacc1b5d182258a688eb5cc7d Mon Sep 17 00:00:00 2001 From: ychenfo Date: Mon, 20 Sep 2021 23:26:04 +0800 Subject: [PATCH] nac3core: change the place to unify constructor type for function body type check add really basic field initialize check --- nac3core/src/toplevel/composer.rs | 70 +++++++++++++++++++++++++------ nac3standalone/demo.c | 5 ++- nac3standalone/mandelbrot.py | 12 ++++++ nac3standalone/src/main.rs | 7 +--- 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 959676b3..9dd980d2 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -1160,13 +1160,69 @@ impl TopLevelComposer { /// step 5, analyze and call type inferecer to fill the `instance_to_stmt` of topleveldef::function fn analyze_function_instance(&mut self) -> Result<(), String> { + // first get the class contructor type correct for the following type check in function body + // also do class field instantiation check + for (def, _) in self.definition_ast_list.iter().skip(self.built_in_num) { + let class_def = def.read(); + if let TopLevelDef::Class { + constructor, + methods, + fields, + type_vars, + name, + object_id, + resolver: _, + .. + } = &*class_def + { + let mut has_init = false; + // get the class contructor type correct + let (contor_args, contor_type_vars) = { + let mut constructor_args: Vec = Vec::new(); + let mut type_vars: HashMap = HashMap::new(); + for (name, func_sig, ..) in methods { + if name == "__init__" { + has_init = true; + if let TypeEnum::TFunc(sig) = self.unifier.get_ty(*func_sig).as_ref() { + let FunSignature { args, vars, .. } = &*sig.borrow(); + constructor_args.extend_from_slice(args); + type_vars.extend(vars); + } else { + unreachable!("must be typeenum::tfunc") + } + } + } + (constructor_args, type_vars) + }; + let self_type = get_type_from_type_annotation_kinds( + self.extract_def_list().as_slice(), + &mut self.unifier, + &self.primitives_ty, + &make_self_type_annotation(type_vars, *object_id), + )?; + let contor_type = self.unifier.add_ty(TypeEnum::TFunc( + FunSignature { args: contor_args, ret: self_type, vars: contor_type_vars } + .into(), + )); + self.unifier.unify(constructor.unwrap(), contor_type)?; + + // class field instantiation check + // TODO: this is a really simple one, more check later + if !has_init && !fields.is_empty() { + return Err(format!("fields of class {} not fully initialized", name)) + } + + } + } + + // type inference inside function body for (id, (def, ast)) in self.definition_ast_list.iter().enumerate().skip(self.built_in_num) { let mut function_def = def.write(); if let TopLevelDef::Function { instance_to_stmt, name, - simple_name, + simple_name: _, signature, resolver, .. @@ -1179,7 +1235,7 @@ impl TopLevelComposer { 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 = class_def.0.read(); - if let TopLevelDef::Class { type_vars, constructor, .. } = &*class_def { + if let TopLevelDef::Class { type_vars, .. } = &*class_def { let ty_ann = make_self_type_annotation(type_vars, *class_id); let self_ty = get_type_from_type_annotation_kinds( self.extract_def_list().as_slice(), @@ -1187,16 +1243,6 @@ impl TopLevelComposer { &self.primitives_ty, &ty_ann, )?; - if simple_name == "__init__" { - let fn_type = self.unifier.add_ty(TypeEnum::TFunc( - RefCell::new(FunSignature { - args: args.clone(), - ret: self_ty, - vars: vars.clone(), - }), - )); - self.unifier.unify(fn_type, constructor.unwrap())?; - } Some(self_ty) } else { unreachable!("must be class def") diff --git a/nac3standalone/demo.c b/nac3standalone/demo.c index cdd6d39b..59a39037 100644 --- a/nac3standalone/demo.c +++ b/nac3standalone/demo.c @@ -9,10 +9,11 @@ int output(int x) { putchar('\n'); } else { if(x < strlen(chars)) { - putchar(chars[x]); + // putchar(chars[x]); + printf("%d\n", x); } else { // printf("ERROR\n"); - printf("%d", x); + printf("%d\n", x); } } return 0; diff --git a/nac3standalone/mandelbrot.py b/nac3standalone/mandelbrot.py index 07d0bcbf..bc8f242b 100644 --- a/nac3standalone/mandelbrot.py +++ b/nac3standalone/mandelbrot.py @@ -1,13 +1,24 @@ class A: a: int32 + b: B def __init__(self, a: int32): self.a = a + self.b = B(a + 1) def get_a(self) -> int32: return self.a def get_self(self) -> A: return self + + def get_b(self) -> B: + return self.b + +class B: + b: int32 + def __init__(self, a: int32): + self.b = a + def run() -> int32: a = A(10) @@ -16,5 +27,6 @@ def run() -> int32: a = A(20) output(a.a) output(a.get_a()) + output(a.get_b().b) return 0 diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index acbfb00d..f45b864d 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -5,7 +5,7 @@ use inkwell::{ OptimizationLevel, }; use nac3core::typecheck::type_inferencer::PrimitiveStore; -use rustpython_parser::{parser, ast::StmtKind}; +use rustpython_parser::parser; use std::{collections::HashMap, path::Path, sync::Arc}; use nac3core::{ @@ -52,17 +52,12 @@ fn main() { ); for stmt in parser::parse_program(&program).unwrap().into_iter() { - let is_class = matches!(stmt.node, StmtKind::ClassDef{ .. }); let (name, def_id, ty) = composer.register_top_level( stmt, Some(resolver.clone()), "__main__".into(), ).unwrap(); - if is_class { - internal_resolver.add_id_type(name.clone(), ty.unwrap()); - } - internal_resolver.add_id_def(name.clone(), def_id); if let Some(ty) = ty { internal_resolver.add_id_type(name, ty);