forked from M-Labs/nac3
nac3core: change the place to unify constructor type for function body type check
add really basic field initialize check
This commit is contained in:
parent
dd1be541b8
commit
e66693282c
|
@ -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<FuncArg> = Vec::new();
|
||||
let mut type_vars: HashMap<u32, Type> = 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")
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
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
|
||||
|
@ -9,6 +11,15 @@ class 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)
|
||||
output(a.a)
|
||||
|
@ -16,5 +27,6 @@ def run() -> int32:
|
|||
a = A(20)
|
||||
output(a.a)
|
||||
output(a.get_a())
|
||||
output(a.get_b().b)
|
||||
return 0
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue