forked from M-Labs/nac3
Compare commits
3 Commits
Author | SHA1 | Date |
---|---|---|
wylited | d8caaed2d1 | |
wylited | ef7a7f55ce | |
wylited | ab86bf4591 |
|
@ -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>(
|
||||||
|
|
|
@ -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 {
|
||||||
|
@ -297,8 +298,10 @@ impl TopLevelComposer {
|
||||||
for (_, def, _, _, ast) in class_method_name_def_ids {
|
for (_, def, _, _, ast) in class_method_name_def_ids {
|
||||||
self.definition_ast_list.push((def, Some(ast)));
|
self.definition_ast_list.push((def, Some(ast)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) };
|
||||||
|
|
||||||
let result_ty = if contains_constructor { Some(constructor_ty) } else { None };
|
|
||||||
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();
|
||||||
|
|
|
@ -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>>,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue