forked from M-Labs/nac3
1
0
Fork 0

clean up and add duplicate function/parameter/class name test

formatted
This commit is contained in:
ychenfo 2021-08-23 14:13:48 +08:00
parent 7b1fe36e90
commit 39f300b62a
1 changed files with 110 additions and 57 deletions

View File

@ -61,7 +61,7 @@ pub mod top_level_type_annotation_info {
if results.len() == 1 { if results.len() == 1 {
results[0].clone() results[0].clone()
} else { } else {
Err("cannot be parsed the type annotation without ambiguity".into()) Err("cannot parsed the type annotation without ambiguity".into())
} }
} }
@ -113,11 +113,11 @@ pub mod top_level_type_annotation_info {
(name.clone(), subst_ty) (name.clone(), subst_ty)
}) })
.collect::<HashMap<String, Type>>(); .collect::<HashMap<String, Type>>();
tobj_fields.extend(fields.iter().map(|(name, ty)| { tobj_fields.extend(fields.iter().map(|(name, ty)| {
let subst_ty = unifier.subst(*ty, &subst).unwrap_or(*ty); let subst_ty = unifier.subst(*ty, &subst).unwrap_or(*ty);
(name.clone(), subst_ty) (name.clone(), subst_ty)
})); }));
Ok(unifier.add_ty(TypeEnum::TObj { Ok(unifier.add_ty(TypeEnum::TObj {
obj_id: *id, obj_id: *id,
fields: tobj_fields.into(), fields: tobj_fields.into(),
@ -146,8 +146,8 @@ pub mod top_level_type_annotation_info {
.iter() .iter()
.map(|(name, ty, _)| (name.clone(), *ty)) .map(|(name, ty, _)| (name.clone(), *ty))
.collect::<HashMap<String, Type>>(); .collect::<HashMap<String, Type>>();
tobj_fields.extend(fields.clone().into_iter()); tobj_fields.extend(fields.clone().into_iter());
Ok(unifier.add_ty(TypeEnum::TObj { Ok(unifier.add_ty(TypeEnum::TObj {
obj_id: *obj_id, obj_id: *obj_id,
fields: tobj_fields.into(), fields: tobj_fields.into(),
@ -268,11 +268,11 @@ pub mod top_level_type_annotation_info {
Err("function cannot be used as a type".into()) Err("function cannot be used as a type".into())
} }
} else { } else {
Err("unsupported expression type".into()) Err("unsupported expression type for class name".into())
} }
} }
_ => Err("unsupported expression type".into()), _ => Err("unsupported expression type for concretized class".into()),
} }
} }
@ -295,7 +295,7 @@ pub mod top_level_type_annotation_info {
slice.as_ref(), slice.as_ref(),
)?; )?;
if !matches!(def, TypeAnnotation::ConcretizedCustomClassKind { .. }) { if !matches!(def, TypeAnnotation::ConcretizedCustomClassKind { .. }) {
unreachable!("should must be concretized custom class kind") unreachable!("must be concretized custom class kind in the virtual")
} }
Ok(TypeAnnotation::VirtualKind(def.into())) Ok(TypeAnnotation::VirtualKind(def.into()))
} }
@ -315,7 +315,11 @@ pub mod top_level_type_annotation_info {
let ty = resolver let ty = resolver
.get_symbol_type(unifier, primitives, id) .get_symbol_type(unifier, primitives, id)
.ok_or_else(|| "unknown type variable name".to_string())?; .ok_or_else(|| "unknown type variable name".to_string())?;
Ok(TypeAnnotation::TypeVarKind(ty)) if let TypeEnum::TVar { .. } = unifier.get_ty(ty).as_ref() {
Ok(TypeAnnotation::TypeVarKind(ty))
} else {
Err("not a type variable identifier".into())
}
} else { } else {
Err("unsupported expression for type variable".into()) Err("unsupported expression for type variable".into())
} }
@ -376,10 +380,7 @@ pub struct TopLevelComposer {
pub unifier: Unifier, pub unifier: Unifier,
// primitive store // primitive store
pub primitives_ty: PrimitiveStore, pub primitives_ty: PrimitiveStore,
// mangled class method name to def_id // keyword list to prevent same custom def class name
// pub class_method_to_def_id: HashMap<String, DefinitionId>,
// record the def id of the classes whoses fields and methods are to be analyzed
// pub to_be_analyzed_class: Vec<DefinitionId>,
pub keyword_list: Vec<String>, pub keyword_list: Vec<String>,
} }
@ -522,11 +523,17 @@ impl TopLevelComposer {
ast: ast::Stmt<()>, ast: ast::Stmt<()>,
resolver: Option<Arc<Mutex<dyn SymbolResolver + Send + Sync>>>, resolver: Option<Arc<Mutex<dyn SymbolResolver + Send + Sync>>>,
) -> Result<(String, DefinitionId), String> { ) -> Result<(String, DefinitionId), String> {
let mut defined_class_name: HashSet<String> = HashSet::new();
let mut defined_class_method_name: HashSet<String> = HashSet::new();
let mut defined_function_name: HashSet<String> = HashSet::new();
match &ast.node { match &ast.node {
ast::StmtKind::ClassDef { name, body, .. } => { ast::StmtKind::ClassDef { name, body, .. } => {
if self.keyword_list.contains(name) { if self.keyword_list.contains(name) {
return Err("cannot use keyword as a class name".into()); return Err("cannot use keyword as a class name".into());
} }
if !defined_class_name.insert(name.clone()) {
return Err("duplicate definition of class".into());
}
let class_name = name.to_string(); let class_name = name.to_string();
let class_def_id = self.definition_ast_list.len(); let class_def_id = self.definition_ast_list.len();
@ -556,6 +563,11 @@ impl TopLevelComposer {
let mut class_method_index_offset = 0; let mut class_method_index_offset = 0;
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 {
let global_class_method_name =
Self::make_class_method_name(class_name.clone(), method_name);
if !defined_class_method_name.insert(global_class_method_name.clone()) {
return Err("duplicate class method definition".into());
}
let method_def_id = self.definition_ast_list.len() + { let method_def_id = self.definition_ast_list.len() + {
class_method_index_offset += 1; class_method_index_offset += 1;
class_method_index_offset class_method_index_offset
@ -566,7 +578,7 @@ impl TopLevelComposer {
class_method_name_def_ids.push(( class_method_name_def_ids.push((
method_name.clone(), method_name.clone(),
RwLock::new(Self::make_top_level_function_def( RwLock::new(Self::make_top_level_function_def(
Self::make_class_method_name(class_name.clone(), method_name), global_class_method_name,
// later unify with parsed type // later unify with parsed type
dummy_method_type.0, dummy_method_type.0,
resolver.clone(), resolver.clone(),
@ -610,6 +622,9 @@ impl TopLevelComposer {
ast::StmtKind::FunctionDef { name, .. } => { ast::StmtKind::FunctionDef { name, .. } => {
let fun_name = name.to_string(); let fun_name = name.to_string();
if !defined_function_name.insert(name.to_string()) {
return Err("duplicate top level function define".into());
}
// add to the definition list // add to the definition list
self.definition_ast_list.push(( self.definition_ast_list.push((
@ -792,7 +807,7 @@ impl TopLevelComposer {
b, b,
)?; )?;
if let TypeAnnotation::ConcretizedCustomClassKind { .. } = base_ty { if let TypeAnnotation::ConcretizedCustomClassKind { .. } = &base_ty {
// TODO: check to prevent cyclic base class // TODO: check to prevent cyclic base class
class_ancestors.push(base_ty); class_ancestors.push(base_ty);
} else { } else {
@ -859,6 +874,13 @@ impl TopLevelComposer {
let resolver = resolver.deref().lock(); let resolver = resolver.deref().lock();
let function_resolver = resolver.deref(); let function_resolver = resolver.deref();
let mut defined_paramter_name: HashSet<String> = HashSet::new();
let have_unique_fuction_parameter_name =
args.args.iter().all(|x| defined_paramter_name.insert(x.node.arg.clone()));
if !have_unique_fuction_parameter_name {
return Err("top level function have duplicate parameter name".into());
}
let arg_types = { let arg_types = {
args.args args.args
.iter() .iter()
@ -935,7 +957,7 @@ impl TopLevelComposer {
) -> Result<(), String> { ) -> Result<(), String> {
let mut class_def = class_def.write(); let mut class_def = class_def.write();
let ( let (
_class_id, class_id,
_class_name, _class_name,
_class_bases_ast, _class_bases_ast,
class_body_ast, class_body_ast,
@ -980,59 +1002,90 @@ impl TopLevelComposer {
if let ast::StmtKind::FunctionDef { args, returns, name, body, .. } = &b.node { if let ast::StmtKind::FunctionDef { args, returns, name, body, .. } = &b.node {
let (method_dummy_ty, ..) = let (method_dummy_ty, ..) =
Self::get_class_method_def_info(class_methods_def, name)?; Self::get_class_method_def_info(class_methods_def, name)?;
// TODO: handle self arg
let mut defined_paramter_name: HashSet<String> = HashSet::new();
let have_unique_fuction_parameter_name =
args.args.iter().all(|x| defined_paramter_name.insert(x.node.arg.clone()));
if !have_unique_fuction_parameter_name {
return Err("class method have duplicate parameter name".into());
}
// TODO: handle parameter with same name // TODO: handle parameter with same name
let arg_type: Vec<FuncArg> = { let arg_type: Vec<FuncArg> = {
let mut result = Vec::new(); let mut result = Vec::new();
for x in &args.args { for x in &args.args {
let name = x.node.arg.clone(); let name = x.node.arg.clone();
let type_ann = { if name != "self" {
let annotation_expr = x let type_ann = {
.node let annotation_expr = x
.annotation .node
.as_ref() .annotation
.ok_or_else(|| "type annotation needed".to_string())? .as_ref()
.as_ref(); .ok_or_else(|| "type annotation needed".to_string())?
parse_ast_to_type_annotation_kinds( .as_ref();
class_resolver, parse_ast_to_type_annotation_kinds(
temp_def_list, class_resolver,
unifier, temp_def_list,
primitives, unifier,
annotation_expr, primitives,
)? annotation_expr,
}; )?
if let TypeAnnotation::TypeVarKind(_ty) = &type_ann { };
// TODO: need to handle to different type vars that are if let TypeAnnotation::TypeVarKind(_ty) = &type_ann {
// asscosiated with the class and that are not // TODO: need to handle to different type vars that are
// asscosiated with the class and that are not
}
let dummy_func_arg = FuncArg {
name,
ty: unifier.get_fresh_var().0,
// TODO: symbol default value?
default_value: None,
};
// 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)
} else {
// if the parameter name is self
// python does not seem to enforce the name
// representing the self class object to be
// `self`, but we do it here
let dummy_func_arg = FuncArg {
name: "self".into(),
ty: unifier.get_fresh_var().0,
default_value: None,
};
type_var_to_concrete_def
.insert(dummy_func_arg.ty, TypeAnnotation::SelfTypeKind(*class_id));
result.push(dummy_func_arg);
} }
let dummy_func_arg = FuncArg {
name,
ty: unifier.get_fresh_var().0,
// TODO: symbol default value?
default_value: None,
};
// 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
}; };
let ret_type = { let ret_type = {
let result = returns if name != "__init__" {
.as_ref() let result = returns
.ok_or_else(|| "method return type annotation needed".to_string())? .as_ref()
.as_ref(); .ok_or_else(|| "method return type annotation needed".to_string())?
let annotation = parse_ast_to_type_annotation_kinds( .as_ref();
class_resolver, let annotation = parse_ast_to_type_annotation_kinds(
temp_def_list, class_resolver,
unifier, temp_def_list,
primitives, unifier,
result, primitives,
)?; result,
let dummy_return_type = unifier.get_fresh_var().0; )?;
type_var_to_concrete_def.insert(dummy_return_type, annotation.clone()); let dummy_return_type = unifier.get_fresh_var().0;
dummy_return_type type_var_to_concrete_def.insert(dummy_return_type, annotation.clone());
dummy_return_type
} else {
// if is the "__init__" function, the return type is self
let dummy_return_type = unifier.get_fresh_var().0;
type_var_to_concrete_def
.insert(dummy_return_type, TypeAnnotation::SelfTypeKind(*class_id));
dummy_return_type
}
}; };
// TODO: handle var map, to create a new copy of type var // TODO: handle var map, to create a new copy of type var
// while tracking the type var associated with class // while tracking the type var associated with class