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 {
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user