forked from M-Labs/nac3
clean up and add duplicate function/parameter/class name test
formatted
This commit is contained in:
parent
7b1fe36e90
commit
39f300b62a
|
@ -61,7 +61,7 @@ pub mod top_level_type_annotation_info {
|
|||
if results.len() == 1 {
|
||||
results[0].clone()
|
||||
} 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)
|
||||
})
|
||||
.collect::<HashMap<String, Type>>();
|
||||
|
||||
tobj_fields.extend(fields.iter().map(|(name, ty)| {
|
||||
let subst_ty = unifier.subst(*ty, &subst).unwrap_or(*ty);
|
||||
(name.clone(), subst_ty)
|
||||
}));
|
||||
|
||||
Ok(unifier.add_ty(TypeEnum::TObj {
|
||||
obj_id: *id,
|
||||
fields: tobj_fields.into(),
|
||||
|
@ -146,8 +146,8 @@ pub mod top_level_type_annotation_info {
|
|||
.iter()
|
||||
.map(|(name, ty, _)| (name.clone(), *ty))
|
||||
.collect::<HashMap<String, Type>>();
|
||||
|
||||
tobj_fields.extend(fields.clone().into_iter());
|
||||
|
||||
Ok(unifier.add_ty(TypeEnum::TObj {
|
||||
obj_id: *obj_id,
|
||||
fields: tobj_fields.into(),
|
||||
|
@ -268,11 +268,11 @@ pub mod top_level_type_annotation_info {
|
|||
Err("function cannot be used as a type".into())
|
||||
}
|
||||
} 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(),
|
||||
)?;
|
||||
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()))
|
||||
}
|
||||
|
@ -315,7 +315,11 @@ pub mod top_level_type_annotation_info {
|
|||
let ty = resolver
|
||||
.get_symbol_type(unifier, primitives, id)
|
||||
.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 {
|
||||
Err("unsupported expression for type variable".into())
|
||||
}
|
||||
|
@ -376,10 +380,7 @@ pub struct TopLevelComposer {
|
|||
pub unifier: Unifier,
|
||||
// primitive store
|
||||
pub primitives_ty: PrimitiveStore,
|
||||
// mangled class method name to def_id
|
||||
// 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>,
|
||||
// keyword list to prevent same custom def class name
|
||||
pub keyword_list: Vec<String>,
|
||||
}
|
||||
|
||||
|
@ -522,11 +523,17 @@ impl TopLevelComposer {
|
|||
ast: ast::Stmt<()>,
|
||||
resolver: Option<Arc<Mutex<dyn SymbolResolver + Send + Sync>>>,
|
||||
) -> 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 {
|
||||
ast::StmtKind::ClassDef { name, body, .. } => {
|
||||
if self.keyword_list.contains(name) {
|
||||
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_def_id = self.definition_ast_list.len();
|
||||
|
@ -556,6 +563,11 @@ impl TopLevelComposer {
|
|||
let mut class_method_index_offset = 0;
|
||||
for b in body {
|
||||
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() + {
|
||||
class_method_index_offset += 1;
|
||||
class_method_index_offset
|
||||
|
@ -566,7 +578,7 @@ impl TopLevelComposer {
|
|||
class_method_name_def_ids.push((
|
||||
method_name.clone(),
|
||||
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
|
||||
dummy_method_type.0,
|
||||
resolver.clone(),
|
||||
|
@ -610,6 +622,9 @@ impl TopLevelComposer {
|
|||
|
||||
ast::StmtKind::FunctionDef { name, .. } => {
|
||||
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
|
||||
self.definition_ast_list.push((
|
||||
|
@ -792,7 +807,7 @@ impl TopLevelComposer {
|
|||
b,
|
||||
)?;
|
||||
|
||||
if let TypeAnnotation::ConcretizedCustomClassKind { .. } = base_ty {
|
||||
if let TypeAnnotation::ConcretizedCustomClassKind { .. } = &base_ty {
|
||||
// TODO: check to prevent cyclic base class
|
||||
class_ancestors.push(base_ty);
|
||||
} else {
|
||||
|
@ -859,6 +874,13 @@ impl TopLevelComposer {
|
|||
let resolver = resolver.deref().lock();
|
||||
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 = {
|
||||
args.args
|
||||
.iter()
|
||||
|
@ -935,7 +957,7 @@ impl TopLevelComposer {
|
|||
) -> Result<(), String> {
|
||||
let mut class_def = class_def.write();
|
||||
let (
|
||||
_class_id,
|
||||
class_id,
|
||||
_class_name,
|
||||
_class_bases_ast,
|
||||
class_body_ast,
|
||||
|
@ -980,59 +1002,90 @@ impl TopLevelComposer {
|
|||
if let ast::StmtKind::FunctionDef { args, returns, name, body, .. } = &b.node {
|
||||
let (method_dummy_ty, ..) =
|
||||
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
|
||||
let arg_type: Vec<FuncArg> = {
|
||||
let mut result = Vec::new();
|
||||
for x in &args.args {
|
||||
let name = x.node.arg.clone();
|
||||
let type_ann = {
|
||||
let annotation_expr = x
|
||||
.node
|
||||
.annotation
|
||||
.as_ref()
|
||||
.ok_or_else(|| "type annotation needed".to_string())?
|
||||
.as_ref();
|
||||
parse_ast_to_type_annotation_kinds(
|
||||
class_resolver,
|
||||
temp_def_list,
|
||||
unifier,
|
||||
primitives,
|
||||
annotation_expr,
|
||||
)?
|
||||
};
|
||||
if let TypeAnnotation::TypeVarKind(_ty) = &type_ann {
|
||||
// TODO: need to handle to different type vars that are
|
||||
// asscosiated with the class and that are not
|
||||
if name != "self" {
|
||||
let type_ann = {
|
||||
let annotation_expr = x
|
||||
.node
|
||||
.annotation
|
||||
.as_ref()
|
||||
.ok_or_else(|| "type annotation needed".to_string())?
|
||||
.as_ref();
|
||||
parse_ast_to_type_annotation_kinds(
|
||||
class_resolver,
|
||||
temp_def_list,
|
||||
unifier,
|
||||
primitives,
|
||||
annotation_expr,
|
||||
)?
|
||||
};
|
||||
if let TypeAnnotation::TypeVarKind(_ty) = &type_ann {
|
||||
// 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
|
||||
};
|
||||
let ret_type = {
|
||||
let result = returns
|
||||
.as_ref()
|
||||
.ok_or_else(|| "method return type annotation needed".to_string())?
|
||||
.as_ref();
|
||||
let annotation = parse_ast_to_type_annotation_kinds(
|
||||
class_resolver,
|
||||
temp_def_list,
|
||||
unifier,
|
||||
primitives,
|
||||
result,
|
||||
)?;
|
||||
let dummy_return_type = unifier.get_fresh_var().0;
|
||||
type_var_to_concrete_def.insert(dummy_return_type, annotation.clone());
|
||||
dummy_return_type
|
||||
if name != "__init__" {
|
||||
let result = returns
|
||||
.as_ref()
|
||||
.ok_or_else(|| "method return type annotation needed".to_string())?
|
||||
.as_ref();
|
||||
let annotation = parse_ast_to_type_annotation_kinds(
|
||||
class_resolver,
|
||||
temp_def_list,
|
||||
unifier,
|
||||
primitives,
|
||||
result,
|
||||
)?;
|
||||
let dummy_return_type = unifier.get_fresh_var().0;
|
||||
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
|
||||
// while tracking the type var associated with class
|
||||
|
|
Loading…
Reference in New Issue