forked from M-Labs/nac3
top level: top level function type var handled
top level: class methods/fields type var handling
This commit is contained in:
parent
935e7410fd
commit
018d6643e1
|
@ -526,8 +526,10 @@ impl TopLevelComposer {
|
||||||
for type_ann in type_var_occured_in_base {
|
for type_ann in type_var_occured_in_base {
|
||||||
if let TypeAnnotation::TypeVarKind(id, ty) = type_ann {
|
if let TypeAnnotation::TypeVarKind(id, ty) = type_ann {
|
||||||
for (ty_id, class_typvar_ty) in class_type_vars.iter() {
|
for (ty_id, class_typvar_ty) in class_type_vars.iter() {
|
||||||
|
// if they refer to the same top level defined type var, we unify them together
|
||||||
if id == *ty_id {
|
if id == *ty_id {
|
||||||
// if they refer to the same top level defined type var, we unify them together
|
// assert to make sure
|
||||||
|
assert!(matches!(self.unifier.get_ty(ty).as_ref(), TypeEnum::TVar{ .. }));
|
||||||
self.unifier.unify(ty, *class_typvar_ty)?;
|
self.unifier.unify(ty, *class_typvar_ty)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -560,6 +562,7 @@ impl TopLevelComposer {
|
||||||
let def_ast_list = &self.definition_ast_list;
|
let def_ast_list = &self.definition_ast_list;
|
||||||
|
|
||||||
let mut type_var_to_concrete_def: HashMap<Type, TypeAnnotation> = HashMap::new();
|
let mut type_var_to_concrete_def: HashMap<Type, TypeAnnotation> = HashMap::new();
|
||||||
|
|
||||||
for (class_def, class_ast) in def_ast_list {
|
for (class_def, class_ast) in def_ast_list {
|
||||||
Self::analyze_single_class(
|
Self::analyze_single_class(
|
||||||
class_def.clone(),
|
class_def.clone(),
|
||||||
|
@ -597,17 +600,17 @@ impl TopLevelComposer {
|
||||||
let function_ast = if let Some(function_ast) = function_ast {
|
let function_ast = if let Some(function_ast) = function_ast {
|
||||||
function_ast
|
function_ast
|
||||||
} else {
|
} else {
|
||||||
|
// no ast, class method, continue
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let TopLevelDef::Function { signature: dummy_ty, resolver, .. } = function_def {
|
if let TopLevelDef::Function { signature: dummy_ty, resolver, .. } = function_def {
|
||||||
if let ast::StmtKind::FunctionDef { args, returns, .. } = &function_ast.node {
|
if let ast::StmtKind::FunctionDef { args, returns, .. } = &function_ast.node {
|
||||||
let resolver = resolver.as_ref();
|
let resolver = resolver.as_ref();
|
||||||
let resolver = resolver.unwrap();
|
let resolver = resolver.unwrap();
|
||||||
let resolver = resolver.deref();
|
let resolver = resolver.deref();
|
||||||
let function_resolver = resolver.deref();
|
|
||||||
|
|
||||||
// occured type vars should not be handled separately
|
// occured type vars should not be handled separately
|
||||||
// TODO: type vars occured as applications of generic classes is not handled
|
|
||||||
let mut occured_type_var: HashMap<u32, Type> = HashMap::new();
|
let mut occured_type_var: HashMap<u32, Type> = HashMap::new();
|
||||||
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 = {
|
||||||
|
@ -633,27 +636,55 @@ impl TopLevelComposer {
|
||||||
})?
|
})?
|
||||||
.as_ref();
|
.as_ref();
|
||||||
|
|
||||||
let mut ty = function_resolver.parse_type_annotation(
|
|
||||||
|
let type_annotation = parse_ast_to_type_annotation_kinds(
|
||||||
|
resolver,
|
||||||
temp_def_list.as_slice(),
|
temp_def_list.as_slice(),
|
||||||
unifier,
|
unifier,
|
||||||
primitives_store,
|
primitives_store,
|
||||||
annotation,
|
annotation
|
||||||
)?;
|
)?;
|
||||||
if let TypeEnum::TVar { id, .. } =
|
let ty = get_type_from_type_annotation_kinds(
|
||||||
unifier.get_ty(ty).as_ref()
|
temp_def_list.as_ref(),
|
||||||
{
|
unifier,
|
||||||
if let Some(occured_ty) = occured_type_var.get(id) {
|
primitives_store,
|
||||||
// if already occured
|
&type_annotation
|
||||||
ty = *occured_ty;
|
)?;
|
||||||
|
|
||||||
|
// if there are same type variables appears, we only need to copy them once
|
||||||
|
let type_vars_within =
|
||||||
|
get_type_var_contained_in_type_annotation(&type_annotation)
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| {
|
||||||
|
if let TypeAnnotation::TypeVarKind(id, ty) = x {
|
||||||
|
// assert here to make sure the ty is TypeEnum::TVar
|
||||||
|
assert!(matches!(unifier.get_ty(ty).as_ref(), TypeEnum::TVar{ .. }));
|
||||||
|
(id, ty)
|
||||||
|
} else {
|
||||||
|
unreachable!("must be type var annotation kind")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
for (top_level_var_id, ty) in type_vars_within {
|
||||||
|
if let Some(occured_ty) = occured_type_var.get(&top_level_var_id) {
|
||||||
|
// if already occured, we unify this two duplicated
|
||||||
|
// type var of the same top level type var
|
||||||
|
unifier.unify(ty, *occured_ty)?;
|
||||||
} else {
|
} else {
|
||||||
// if not, create a duplicate
|
// if not, put it into the occured type var hashmap,
|
||||||
let ty_copy = duplicate_type_var(unifier, ty);
|
// since parse_ast_to_type_var already duplicated it
|
||||||
ty = ty_copy.0;
|
// we do not need to duplicate it again
|
||||||
occured_type_var.insert(*id, ty);
|
occured_type_var.insert(top_level_var_id, ty);
|
||||||
function_var_map.insert(ty_copy.1, ty_copy.0);
|
// the type var map to it self
|
||||||
|
if let TypeEnum::TVar { id: self_id, .. } = unifier.get_ty(ty).as_ref() {
|
||||||
|
function_var_map.insert(*self_id, ty);
|
||||||
|
} else {
|
||||||
|
unreachable!("must be type var");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: default value?
|
||||||
Ok(FuncArg {
|
Ok(FuncArg {
|
||||||
name: x.node.arg.clone(),
|
name: x.node.arg.clone(),
|
||||||
ty,
|
ty,
|
||||||
|
@ -663,18 +694,40 @@ impl TopLevelComposer {
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
};
|
};
|
||||||
|
|
||||||
let return_ty = {
|
let return_ty_annotation = {
|
||||||
let return_annotation = returns
|
let return_annotation = returns
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or_else(|| "function return type needed".to_string())?
|
.ok_or_else(|| "function return type needed".to_string())?
|
||||||
.as_ref();
|
.as_ref();
|
||||||
function_resolver.parse_type_annotation(
|
parse_ast_to_type_annotation_kinds(resolver, &temp_def_list, unifier, primitives_store, return_annotation)?
|
||||||
temp_def_list.as_slice(),
|
};
|
||||||
|
let return_ty =
|
||||||
|
get_type_from_type_annotation_kinds(
|
||||||
|
&temp_def_list,
|
||||||
unifier,
|
unifier,
|
||||||
primitives_store,
|
primitives_store,
|
||||||
return_annotation,
|
&return_ty_annotation
|
||||||
)?
|
)?;
|
||||||
};
|
|
||||||
|
let type_vars_within =
|
||||||
|
get_type_var_contained_in_type_annotation(&return_ty_annotation)
|
||||||
|
.into_iter()
|
||||||
|
.map(|x|
|
||||||
|
if let TypeAnnotation::TypeVarKind(id, ty) = x {
|
||||||
|
(id, ty)
|
||||||
|
} else {
|
||||||
|
unreachable!("must be type var here")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.collect_vec();
|
||||||
|
for (top_level_var_id, ty) in type_vars_within {
|
||||||
|
if let Some(existing_ty) = occured_type_var.get(&top_level_var_id) {
|
||||||
|
// should not return err here
|
||||||
|
unifier.unify(ty, *existing_ty)?;
|
||||||
|
} else {
|
||||||
|
occured_type_var.insert(top_level_var_id, ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let function_ty = unifier.add_ty(TypeEnum::TFunc(
|
let function_ty = unifier.add_ty(TypeEnum::TFunc(
|
||||||
FunSignature { args: arg_types, ret: return_ty, vars: function_var_map }
|
FunSignature { args: arg_types, ret: return_ty, vars: function_var_map }
|
||||||
|
@ -745,7 +798,7 @@ impl TopLevelComposer {
|
||||||
unreachable!("here must be class def ast");
|
unreachable!("here must be class def ast");
|
||||||
};
|
};
|
||||||
let class_resolver = class_resolver.as_ref().unwrap();
|
let class_resolver = class_resolver.as_ref().unwrap();
|
||||||
let class_resolver = class_resolver;
|
let class_resolver = class_resolver.as_ref();
|
||||||
|
|
||||||
for b in class_body_ast {
|
for b in class_body_ast {
|
||||||
if let ast::StmtKind::FunctionDef { args, returns, name, body, .. } = &b.node {
|
if let ast::StmtKind::FunctionDef { args, returns, name, body, .. } = &b.node {
|
||||||
|
@ -756,7 +809,7 @@ impl TopLevelComposer {
|
||||||
// while tracking the type var associated with class
|
// while tracking the type var associated with class
|
||||||
// TODO: type vars occured as applications of generic classes is not handled
|
// TODO: type vars occured as applications of generic classes is not handled
|
||||||
let mut method_var_map: HashMap<u32, Type> = HashMap::new();
|
let mut method_var_map: HashMap<u32, Type> = HashMap::new();
|
||||||
let arg_type: Vec<FuncArg> = {
|
let arg_types: Vec<FuncArg> = {
|
||||||
// check method parameters cannot have same name
|
// check method parameters cannot have same name
|
||||||
let mut defined_paramter_name: HashSet<String> = HashSet::new();
|
let mut defined_paramter_name: HashSet<String> = HashSet::new();
|
||||||
let have_unique_fuction_parameter_name =
|
let have_unique_fuction_parameter_name =
|
||||||
|
@ -786,36 +839,55 @@ impl TopLevelComposer {
|
||||||
};
|
};
|
||||||
// handle to differentiate type vars that are
|
// handle to differentiate type vars that are
|
||||||
// asscosiated with the class and that are not
|
// asscosiated with the class and that are not
|
||||||
// TODO: type vars occured as applications of generic classes is not handled
|
|
||||||
if let TypeAnnotation::TypeVarKind(id, ty) = &type_ann {
|
|
||||||
let associated = class_type_vars_def
|
|
||||||
.iter()
|
|
||||||
.filter(|(class_type_var_id, _)| *class_type_var_id == *id)
|
|
||||||
.collect_vec();
|
|
||||||
match associated.len() {
|
|
||||||
// 0, do nothing, this is not a type var
|
|
||||||
// associated with the method's class
|
|
||||||
// TODO: but this type var can occur multiple times in this
|
|
||||||
// method's param list, still need to keep track of type vars
|
|
||||||
// associated with this function
|
|
||||||
0 => {}
|
|
||||||
// is type var associated with class, do the unification here
|
|
||||||
1 => {
|
|
||||||
unifier.unify(*ty, associated[0].1)?;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!("there should not be duplicate type var");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// just insert the id and ty of self
|
let type_vars_within = get_type_var_contained_in_type_annotation(&type_ann);
|
||||||
// since the function is not instantiated yet
|
for type_var_within in type_vars_within {
|
||||||
if let TypeEnum::TVar { id, .. } = unifier.get_ty(*ty).as_ref() {
|
if let TypeAnnotation::TypeVarKind(top_level_id, ty) = type_var_within {
|
||||||
method_var_map.insert(*id, *ty);
|
for (class_type_var_top_level_id, class_type_var_ty) in class_type_vars_def.iter() {
|
||||||
|
if top_level_id == *class_type_var_top_level_id {
|
||||||
|
unifier.unify(ty, *class_type_var_ty)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// note that this has to be done after the unify step between the common type vars
|
||||||
|
// between the method and the class(unify of type variables associated with class)
|
||||||
|
// since after unification, the var_id will change.
|
||||||
|
method_var_map.insert()
|
||||||
} else {
|
} else {
|
||||||
unreachable!("must be type var")
|
unreachable!("must be type var annotation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if let TypeAnnotation::TypeVarKind(id, ty) = &type_ann {
|
||||||
|
// let associated = class_type_vars_def
|
||||||
|
// .iter()
|
||||||
|
// .filter(|(class_type_var_id, _)| *class_type_var_id == *id)
|
||||||
|
// .collect_vec();
|
||||||
|
// match associated.len() {
|
||||||
|
// // 0, do nothing, this is not a type var
|
||||||
|
// // associated with the method's class
|
||||||
|
// // TODO: but this type var can occur multiple times in this
|
||||||
|
// // method's param list, still need to keep track of type vars
|
||||||
|
// // associated with this function
|
||||||
|
// 0 => {}
|
||||||
|
// // is type var associated with class, do the unification here
|
||||||
|
// 1 => {
|
||||||
|
// unifier.unify(*ty, associated[0].1)?;
|
||||||
|
// }
|
||||||
|
// _ => {
|
||||||
|
// unreachable!("there should not be duplicate type var");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // just insert the id and ty of self
|
||||||
|
// // since the function is not instantiated yet
|
||||||
|
// if let TypeEnum::TVar { id, .. } = unifier.get_ty(*ty).as_ref() {
|
||||||
|
// method_var_map.insert(*id, *ty);
|
||||||
|
// } else {
|
||||||
|
// unreachable!("must be type var")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
let dummy_func_arg = FuncArg {
|
let dummy_func_arg = FuncArg {
|
||||||
name,
|
name,
|
||||||
ty: unifier.get_fresh_var().0,
|
ty: unifier.get_fresh_var().0,
|
||||||
|
@ -876,7 +948,7 @@ impl TopLevelComposer {
|
||||||
};
|
};
|
||||||
|
|
||||||
let method_type = unifier.add_ty(TypeEnum::TFunc(
|
let method_type = unifier.add_ty(TypeEnum::TFunc(
|
||||||
FunSignature { args: arg_type, ret: ret_type, vars: method_var_map }.into(),
|
FunSignature { args: arg_types, ret: ret_type, vars: method_var_map }.into(),
|
||||||
));
|
));
|
||||||
// unify now since function type is not in type annotation define
|
// unify now since function type is not in type annotation define
|
||||||
// which is fine since type within method_type will be subst later
|
// which is fine since type within method_type will be subst later
|
||||||
|
@ -959,4 +1031,31 @@ impl TopLevelComposer {
|
||||||
result.push(child);
|
result.push(child);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// handle the method function types (especially the type vars things)
|
||||||
|
/// arg: ast node Arguments, contains lists of various kinds of function parameters, now only deal with arg.arg
|
||||||
|
/// resolver: the resolver of the corresponding top_level_function/class
|
||||||
|
/// class_type_vars: if is class method, this is the reference to the field: TopLevelDef::Class.type_vars \
|
||||||
|
/// \
|
||||||
|
/// return a tuple of three:
|
||||||
|
/// 0. vector of FuncArg which is used to construct the FunSignature
|
||||||
|
/// 1. Hashmap of occured type vars for later analyze the return type
|
||||||
|
/// 2. Hashmap of the function type var map to build the FunSignature
|
||||||
|
fn analyze_function_args_type(
|
||||||
|
arg: &ast::Arguments,
|
||||||
|
resolver: &(dyn SymbolResolver + Send + Sync),
|
||||||
|
class_type_vars: Option<&[(u32, Type)]>
|
||||||
|
) -> (Vec<FuncArg>, HashMap<u32, Type>, HashMap<u32, Type>) {
|
||||||
|
let mut occured_type_var: HashMap<u32, Type> = HashMap::new();
|
||||||
|
let mut function_var_map: HashMap<u32, Type> = HashMap::new();
|
||||||
|
// the type var of the class is essentially the occured_type_def
|
||||||
|
if let Some(class_type_vars) = class_type_vars {
|
||||||
|
occured_type_var.extend(class_type_vars.into_iter());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub enum TypeAnnotation {
|
||||||
TypeVarKind(u32, Type),
|
TypeVarKind(u32, Type),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// if is typevar, this function will make a copy of it
|
||||||
pub fn parse_ast_to_type_annotation_kinds<T>(
|
pub fn parse_ast_to_type_annotation_kinds<T>(
|
||||||
resolver: &Box<dyn SymbolResolver + Send + Sync>,
|
resolver: &Box<dyn SymbolResolver + Send + Sync>,
|
||||||
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
||||||
|
@ -58,8 +59,8 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
|
||||||
// but record the var_id of the original type var
|
// but record the var_id of the original type var
|
||||||
// returned by symbol resolver
|
// returned by symbol resolver
|
||||||
Ok(TypeAnnotation::TypeVarKind(
|
Ok(TypeAnnotation::TypeVarKind(
|
||||||
|
// this id is the id of the top level type var
|
||||||
*id,
|
*id,
|
||||||
// TODO: maybe not duplicate will also be fine here?
|
|
||||||
duplicate_type_var(unifier, ty).0
|
duplicate_type_var(unifier, ty).0
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
|
@ -143,6 +144,7 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// if is typeannotation::tvar, this function will NOT make a copy of it
|
||||||
pub fn get_type_from_type_annotation_kinds(
|
pub fn get_type_from_type_annotation_kinds(
|
||||||
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
|
@ -245,8 +247,19 @@ pub fn duplicate_type_var(
|
||||||
/// class A(Generic[T, V]):
|
/// class A(Generic[T, V]):
|
||||||
/// def fun(self):
|
/// def fun(self):
|
||||||
/// ```
|
/// ```
|
||||||
/// the type of `self` should be equivalent 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 direclty
|
||||||
|
/// 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
|
||||||
|
/// the Type of their fields and methods will also be subst when application/instantiation \
|
||||||
|
/// \
|
||||||
|
/// Note this implicit self type is different with seeing `A[T, V]` explicitly outside
|
||||||
|
/// the class def ast body, where it is a new instantiation of the generic class `A`,
|
||||||
|
/// but equivalent to seeing `A[T, V]` inside the class def body ast, where although we
|
||||||
|
/// create copies of `T` and `V`, we will find them out as occured type vars in the analyze_class()
|
||||||
|
/// and unify them with the class generic `T`, `V`
|
||||||
pub fn make_self_type_annotation(
|
pub fn make_self_type_annotation(
|
||||||
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
||||||
def_id: DefinitionId,
|
def_id: DefinitionId,
|
||||||
|
@ -263,10 +276,9 @@ pub fn make_self_type_annotation(
|
||||||
id: def_id,
|
id: def_id,
|
||||||
params: type_vars
|
params: type_vars
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(var_id, ty)| TypeAnnotation::TypeVarKind(
|
// note here the var_id also points to the var_id of
|
||||||
*var_id,
|
// the top level defined type var's var id
|
||||||
duplicate_type_var(unifier, *ty).0
|
.map(|(var_id, ty)| TypeAnnotation::TypeVarKind(*var_id, *ty))
|
||||||
))
|
|
||||||
.collect_vec()
|
.collect_vec()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -276,6 +288,7 @@ pub fn make_self_type_annotation(
|
||||||
|
|
||||||
/// get all the occurences of type vars contained in a type annotation
|
/// get all the occurences of type vars contained in a type annotation
|
||||||
/// e.g. `A[int, B[T], V]` => [T, V]
|
/// e.g. `A[int, B[T], V]` => [T, V]
|
||||||
|
/// this function will not make a duplicate of type var
|
||||||
pub fn get_type_var_contained_in_type_annotation(ann: &TypeAnnotation) -> Vec<TypeAnnotation> {
|
pub fn get_type_var_contained_in_type_annotation(ann: &TypeAnnotation) -> Vec<TypeAnnotation> {
|
||||||
let mut result: Vec<TypeAnnotation> = Vec::new();
|
let mut result: Vec<TypeAnnotation> = Vec::new();
|
||||||
match ann {
|
match ann {
|
||||||
|
|
Loading…
Reference in New Issue