forked from M-Labs/nac3
1
0
Fork 0

handle class method/fields type var

This commit is contained in:
ychenfo 2021-08-27 01:39:15 +08:00
parent 018d6643e1
commit b9a580d271
2 changed files with 199 additions and 159 deletions

View File

@ -1,4 +1,9 @@
use std::{collections::{HashMap, HashSet}, sync::Arc, ops::{Deref, DerefMut}, borrow::BorrowMut}; use std::{
borrow::BorrowMut,
collections::{HashMap, HashSet},
ops::{Deref, DerefMut},
sync::Arc,
};
use super::typecheck::type_inferencer::PrimitiveStore; use super::typecheck::type_inferencer::PrimitiveStore;
use super::typecheck::typedef::{FunSignature, FuncArg, SharedUnifier, Type, TypeEnum, Unifier}; use super::typecheck::typedef::{FunSignature, FuncArg, SharedUnifier, Type, TypeEnum, Unifier};
@ -29,10 +34,10 @@ pub enum TopLevelDef {
name: String, name: String,
// object ID used for TypeEnum // object ID used for TypeEnum
object_id: DefinitionId, object_id: DefinitionId,
// type variables bounded to the class. /// type variables bounded to the class.
// the first field in the tuple is the var_id of the /// the first field in the tuple is the var_id of the
// original typevar defined in the top level and returned ///original typevar defined in the top level and returned
// by the symbol resolver /// by the symbol resolver
type_vars: Vec<(u32, Type)>, type_vars: Vec<(u32, Type)>,
// class fields // class fields
fields: Vec<(String, Type)>, fields: Vec<(String, Type)>,
@ -467,7 +472,9 @@ impl TopLevelComposer {
for (class_def, class_ast) in self.definition_ast_list.iter_mut() { for (class_def, class_ast) in self.definition_ast_list.iter_mut() {
let mut class_def = class_def.write(); let mut class_def = class_def.write();
let (class_bases, class_ancestors, class_resolver, class_id, class_type_vars) = { let (class_bases, class_ancestors, class_resolver, class_id, class_type_vars) = {
if let TopLevelDef::Class { ancestors, resolver, object_id, type_vars, .. } = class_def.deref_mut() { if let TopLevelDef::Class { ancestors, resolver, object_id, type_vars, .. } =
class_def.deref_mut()
{
if let Some(ast::Located { if let Some(ast::Located {
node: ast::StmtKind::ClassDef { bases, .. }, .. node: ast::StmtKind::ClassDef { bases, .. }, ..
}) = class_ast }) = class_ast
@ -522,14 +529,18 @@ impl TopLevelComposer {
// find the intersection between type vars occured in the base class type parameter // find the intersection between type vars occured in the base class type parameter
// and the type vars occured in the class generic declaration // and the type vars occured in the class generic declaration
let type_var_occured_in_base = get_type_var_contained_in_type_annotation(&base_ty); let type_var_occured_in_base =
get_type_var_contained_in_type_annotation(&base_ty);
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 they refer to the same top level defined type var, we unify them together
if id == *ty_id { if id == *ty_id {
// assert to make sure // assert to make sure
assert!(matches!(self.unifier.get_ty(ty).as_ref(), TypeEnum::TVar{ .. })); 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)?;
} }
} }
@ -540,16 +551,16 @@ impl TopLevelComposer {
class_ancestors.push(base_ty); class_ancestors.push(base_ty);
} else { } else {
return Err( return Err("class base declaration can only be custom class".into());
"class base declaration can only be custom class".into()
);
} }
} }
// push self to the ancestors // push self to the ancestors
class_ancestors.push( class_ancestors.push(make_self_type_annotation(
make_self_type_annotation(&temp_def_list, class_id, self.unifier.borrow_mut())? &temp_def_list,
) class_id,
self.unifier.borrow_mut(),
)?)
} }
Ok(()) Ok(())
} }
@ -636,19 +647,12 @@ impl TopLevelComposer {
})? })?
.as_ref(); .as_ref();
let type_annotation = parse_ast_to_type_annotation_kinds( let type_annotation = parse_ast_to_type_annotation_kinds(
resolver, resolver,
temp_def_list.as_slice(), temp_def_list.as_slice(),
unifier, unifier,
primitives_store, primitives_store,
annotation annotation,
)?;
let ty = get_type_from_type_annotation_kinds(
temp_def_list.as_ref(),
unifier,
primitives_store,
&type_annotation
)?; )?;
// if there are same type variables appears, we only need to copy them once // if there are same type variables appears, we only need to copy them once
@ -658,7 +662,10 @@ impl TopLevelComposer {
.map(|x| { .map(|x| {
if let TypeAnnotation::TypeVarKind(id, ty) = x { if let TypeAnnotation::TypeVarKind(id, ty) = x {
// assert here to make sure the ty is TypeEnum::TVar // assert here to make sure the ty is TypeEnum::TVar
assert!(matches!(unifier.get_ty(ty).as_ref(), TypeEnum::TVar{ .. })); assert!(matches!(
unifier.get_ty(ty).as_ref(),
TypeEnum::TVar { .. }
));
(id, ty) (id, ty)
} else { } else {
unreachable!("must be type var annotation kind") unreachable!("must be type var annotation kind")
@ -666,7 +673,9 @@ impl TopLevelComposer {
}) })
.collect_vec(); .collect_vec();
for (top_level_var_id, ty) in type_vars_within { for (top_level_var_id, ty) in type_vars_within {
if let Some(occured_ty) = occured_type_var.get(&top_level_var_id) { if let Some(occured_ty) =
occured_type_var.get(&top_level_var_id)
{
// if already occured, we unify this two duplicated // if already occured, we unify this two duplicated
// type var of the same top level type var // type var of the same top level type var
unifier.unify(ty, *occured_ty)?; unifier.unify(ty, *occured_ty)?;
@ -676,7 +685,9 @@ impl TopLevelComposer {
// we do not need to duplicate it again // we do not need to duplicate it again
occured_type_var.insert(top_level_var_id, ty); occured_type_var.insert(top_level_var_id, ty);
// the type var map to it self // the type var map to it self
if let TypeEnum::TVar { id: self_id, .. } = unifier.get_ty(ty).as_ref() { if let TypeEnum::TVar { id: self_id, .. } =
unifier.get_ty(ty).as_ref()
{
function_var_map.insert(*self_id, ty); function_var_map.insert(*self_id, ty);
} else { } else {
unreachable!("must be type var"); unreachable!("must be type var");
@ -684,6 +695,14 @@ impl TopLevelComposer {
} }
} }
// NOTE: get the actual ty after handling the type vars, really? why?
let ty = get_type_from_type_annotation_kinds(
temp_def_list.as_ref(),
unifier,
primitives_store,
&type_annotation,
)?;
// TODO: default value? // TODO: default value?
Ok(FuncArg { Ok(FuncArg {
name: x.node.arg.clone(), name: x.node.arg.clone(),
@ -699,26 +718,25 @@ impl TopLevelComposer {
.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();
parse_ast_to_type_annotation_kinds(resolver, &temp_def_list, unifier, primitives_store, return_annotation)? parse_ast_to_type_annotation_kinds(
}; resolver,
let return_ty =
get_type_from_type_annotation_kinds(
&temp_def_list, &temp_def_list,
unifier, unifier,
primitives_store, primitives_store,
&return_ty_annotation return_annotation,
)?; )?
};
let type_vars_within = let type_vars_within =
get_type_var_contained_in_type_annotation(&return_ty_annotation) get_type_var_contained_in_type_annotation(&return_ty_annotation)
.into_iter() .into_iter()
.map(|x| .map(|x| {
if let TypeAnnotation::TypeVarKind(id, ty) = x { if let TypeAnnotation::TypeVarKind(id, ty) = x {
(id, ty) (id, ty)
} else { } else {
unreachable!("must be type var here") unreachable!("must be type var here")
} }
) })
.collect_vec(); .collect_vec();
for (top_level_var_id, ty) in type_vars_within { for (top_level_var_id, ty) in type_vars_within {
if let Some(existing_ty) = occured_type_var.get(&top_level_var_id) { if let Some(existing_ty) = occured_type_var.get(&top_level_var_id) {
@ -729,6 +747,14 @@ impl TopLevelComposer {
} }
} }
// NOTE: get the actual ty after handling the type vars, really? why?
let return_ty = get_type_from_type_annotation_kinds(
&temp_def_list,
unifier,
primitives_store,
&return_ty_annotation,
)?;
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 }
.into(), .into(),
@ -807,8 +833,24 @@ impl TopLevelComposer {
// handle var map, to create a new copy of type var // 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
// TODO: type vars occured as applications of generic classes is not handled // from the duplicated type var's var_id to themselves
let mut method_var_map: HashMap<u32, Type> = HashMap::new(); // include the class type vars like the type var context of the method
let mut method_var_map: HashMap<u32, Type> = class_type_vars_def
.iter()
.map(|(_, ty)| {
if let TypeEnum::TVar { id, .. } = unifier.get_ty(*ty).as_ref() {
(*id, *ty)
} else {
unreachable!("must be type var here")
}
})
.collect();
// from the def_id of top level type vars to duplicated type vars
// also include the class type var like the type var context of the method
let mut occured_type_vars: HashMap<u32, Type> =
class_type_vars_def.iter().map(|(id, ty)| (*id, *ty)).collect();
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_paramter_name: HashSet<String> = HashSet::new(); let mut defined_paramter_name: HashSet<String> = HashSet::new();
@ -837,57 +879,39 @@ impl TopLevelComposer {
annotation_expr, annotation_expr,
)? )?
}; };
// handle to differentiate type vars that are
// asscosiated with the class and that are not
let type_vars_within = get_type_var_contained_in_type_annotation(&type_ann); // find type vars within this method parameter type annotation
let type_vars_within =
get_type_var_contained_in_type_annotation(&type_ann);
// handle the class type var and the method type var
for type_var_within in type_vars_within { for type_var_within in type_vars_within {
if let TypeAnnotation::TypeVarKind(top_level_id, ty) = type_var_within { if let TypeAnnotation::TypeVarKind(top_level_id, ty) =
for (class_type_var_top_level_id, class_type_var_ty) in class_type_vars_def.iter() { type_var_within
if top_level_id == *class_type_var_top_level_id { {
unifier.unify(ty, *class_type_var_ty)?; if let Some(duped_ty) = occured_type_vars.get(&top_level_id) {
// if already occured, not matter if it is class typevar or method typevar, just unify
unifier.unify(ty, *duped_ty)?;
} else {
// if not insert them to the occured_type_vars and the method_varmap
// note that the content to insert is different
occured_type_vars.insert(top_level_id, ty);
method_var_map.insert(
if let TypeEnum::TVar { id, .. } =
unifier.get_ty(ty).as_ref()
{
*id
} else {
unreachable!("must be 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 annotation"); 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")
// }
// }
// finish handling type vars
let dummy_func_arg = FuncArg { let dummy_func_arg = FuncArg {
name, name,
ty: unifier.get_fresh_var().0, ty: unifier.get_fresh_var().0,
@ -902,23 +926,22 @@ impl TopLevelComposer {
// if the parameter name is self // if the parameter name is self
// python does not seem to enforce the name // python does not seem to enforce the name
// representing the self class object to be // representing the self class object to be
// `self`, but we do it here // `self`??, but we do it here
let dummy_func_arg = FuncArg { let dummy_func_arg = FuncArg {
name: "self".into(), name: "self".into(),
ty: unifier.get_fresh_var().0, ty: unifier.get_fresh_var().0,
default_value: None, default_value: None,
}; };
type_var_to_concrete_def type_var_to_concrete_def.insert(
.insert(
dummy_func_arg.ty, dummy_func_arg.ty,
make_self_type_annotation(temp_def_list, *class_id, unifier)? make_self_type_annotation(temp_def_list, *class_id, unifier)?,
); );
result.push(dummy_func_arg); result.push(dummy_func_arg);
} }
} }
result result
}; };
let ret_type = { let ret_type = {
if name != "__init__" { if name != "__init__" {
let result = returns let result = returns
@ -932,16 +955,45 @@ impl TopLevelComposer {
primitives, primitives,
result, result,
)?; )?;
// find type vars within this return type annotation
let type_vars_within =
get_type_var_contained_in_type_annotation(&annotation);
// handle the class type var and the method type var
for type_var_within in type_vars_within {
if let TypeAnnotation::TypeVarKind(top_level_id, ty) = type_var_within {
if let Some(duped_ty) = occured_type_vars.get(&top_level_id) {
// if already occured, not matter if it is class typevar or method typevar, just unify
unifier.unify(ty, *duped_ty)?;
} else {
// if not insert them to the occured_type_vars and the method_varmap
// note that the content to insert is different
occured_type_vars.insert(top_level_id, ty);
method_var_map.insert(
if let TypeEnum::TVar { id, .. } =
unifier.get_ty(ty).as_ref()
{
*id
} else {
unreachable!("must be type var")
},
ty,
);
}
} else {
unreachable!("must be type var annotation");
}
}
let dummy_return_type = unifier.get_fresh_var().0; let dummy_return_type = unifier.get_fresh_var().0;
type_var_to_concrete_def.insert(dummy_return_type, annotation.clone()); type_var_to_concrete_def.insert(dummy_return_type, annotation.clone());
dummy_return_type dummy_return_type
} else { } else {
// if is the "__init__" function, the return type is self // if is the "__init__" function, the return type is self
let dummy_return_type = unifier.get_fresh_var().0; let dummy_return_type = unifier.get_fresh_var().0;
type_var_to_concrete_def type_var_to_concrete_def.insert(
.insert(
dummy_return_type, dummy_return_type,
make_self_type_annotation(temp_def_list, *class_id, unifier)? make_self_type_annotation(temp_def_list, *class_id, unifier)?,
); );
dummy_return_type dummy_return_type
} }
@ -950,7 +1002,7 @@ impl TopLevelComposer {
let method_type = unifier.add_ty(TypeEnum::TFunc( let method_type = unifier.add_ty(TypeEnum::TFunc(
FunSignature { args: arg_types, 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 // NOTE: 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
unifier.unify(method_dummy_ty, method_type)?; unifier.unify(method_dummy_ty, method_type)?;
@ -968,6 +1020,7 @@ impl TopLevelComposer {
if defined_fields.insert(attr.to_string()) { if defined_fields.insert(attr.to_string()) {
let dummy_field_type = unifier.get_fresh_var().0; let dummy_field_type = unifier.get_fresh_var().0;
class_fields_def.push((attr.to_string(), dummy_field_type)); class_fields_def.push((attr.to_string(), dummy_field_type));
let annotation = parse_ast_to_type_annotation_kinds( let annotation = parse_ast_to_type_annotation_kinds(
class_resolver, class_resolver,
&temp_def_list, &temp_def_list,
@ -975,6 +1028,28 @@ impl TopLevelComposer {
primitives, primitives,
annotation.as_ref(), annotation.as_ref(),
)?; )?;
// find type vars within this return type annotation
let type_vars_within =
get_type_var_contained_in_type_annotation(&annotation);
// handle the class type var and the method type var
for type_var_within in type_vars_within {
if let TypeAnnotation::TypeVarKind(top_level_id, ty) =
type_var_within
{
if let Some(duped_ty) =
occured_type_vars.get(&top_level_id)
{
// if already occured, not matter if it is class typevar or method typevar, just unify
unifier.unify(ty, *duped_ty)?;
} else {
return Err("this type var is not available inside this function".into());
}
} else {
unreachable!("must be type var annotation");
}
}
type_var_to_concrete_def type_var_to_concrete_def
.insert(dummy_field_type, annotation); .insert(dummy_field_type, annotation);
} else { } else {
@ -1007,7 +1082,7 @@ impl TopLevelComposer {
/// get all base class def id of a class, including itself /// get all base class def id of a class, including itself
fn get_all_base( fn get_all_base(
child: DefinitionId, child: DefinitionId,
temp_def_list: &[Arc<RwLock<TopLevelDef>>] temp_def_list: &[Arc<RwLock<TopLevelDef>>],
) -> Vec<DefinitionId> { ) -> Vec<DefinitionId> {
let mut result: Vec<DefinitionId> = Vec::new(); let mut result: Vec<DefinitionId> = Vec::new();
let child_def = temp_def_list.get(child.0).unwrap(); let child_def = temp_def_list.get(child.0).unwrap();
@ -1031,31 +1106,4 @@ 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!()
}
} }

View File

@ -42,18 +42,17 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
if let TopLevelDef::Class { type_vars, .. } = &*def { if let TopLevelDef::Class { type_vars, .. } = &*def {
// also check param number here // also check param number here
if !type_vars.is_empty() { if !type_vars.is_empty() {
return Err(format!("expect {} type variable parameter but got 0", type_vars.len())) return Err(format!(
"expect {} type variable parameter but got 0",
type_vars.len()
));
} }
Ok(TypeAnnotation::CustomClassKind { Ok(TypeAnnotation::CustomClassKind { id: obj_id, params: vec![] })
id: obj_id,
params: vec![],
})
} else { } else {
Err("function cannot be used as a type".into()) Err("function cannot be used as a type".into())
} }
} else if let Some(ty) = resolver.get_symbol_type(unifier, primitives, id) { } else if let Some(ty) = resolver.get_symbol_type(unifier, primitives, id) {
if let TypeEnum::TVar { id, .. } = unifier.get_ty(ty).as_ref() if let TypeEnum::TVar { id, .. } = unifier.get_ty(ty).as_ref() {
{
// NOTE: always create a new one here // NOTE: always create a new one here
// and later unify if needed // and later unify if needed
// but record the var_id of the original type var // but record the var_id of the original type var
@ -61,7 +60,7 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
Ok(TypeAnnotation::TypeVarKind( Ok(TypeAnnotation::TypeVarKind(
// this id is the id of the top level type var // this id is the id of the top level type var
*id, *id,
duplicate_type_var(unifier, ty).0 duplicate_type_var(unifier, ty).0,
)) ))
} else { } else {
Err("not a type variable identifier".into()) Err("not a type variable identifier".into())
@ -125,13 +124,10 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
"expect {} type parameters but got {}", "expect {} type parameters but got {}",
type_vars.len(), type_vars.len(),
param_type_infos.len() param_type_infos.len()
)) ));
} }
// NOTE: allow type var in class generic application list // NOTE: allow type var in class generic application list
Ok(TypeAnnotation::CustomClassKind { Ok(TypeAnnotation::CustomClassKind { id: obj_id, params: param_type_infos })
id: obj_id,
params: param_type_infos,
})
} else { } else {
Err("function cannot be used as a type".into()) Err("function cannot be used as a type".into())
} }
@ -173,7 +169,7 @@ pub fn get_type_from_type_annotation_kinds(
) )
}) })
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
// FIXME: TODO: cannot directy subst type var here? need to subst types in fields/methods // NOTE: cannot directy subst type var here? need to subst types in fields/methods?
let subst = type_vars let subst = type_vars
.iter() .iter()
.map(|x| { .map(|x| {
@ -227,10 +223,7 @@ pub fn get_type_from_type_annotation_kinds(
/// the second return is the var_id of the duplicated type \ /// the second return is the var_id of the duplicated type \
/// the third return is the var_id of the original type /// the third return is the var_id of the original type
#[inline] #[inline]
pub fn duplicate_type_var( pub fn duplicate_type_var(unifier: &mut Unifier, type_var: Type) -> (Type, u32, u32) {
unifier: &mut Unifier,
type_var: Type
) -> (Type, u32, u32) {
let ty = unifier.get_ty(type_var); let ty = unifier.get_ty(type_var);
if let TypeEnum::TVar { id, range, .. } = ty.as_ref() { if let TypeEnum::TVar { id, range, .. } = ty.as_ref() {
let range = range.borrow(); let range = range.borrow();
@ -263,11 +256,10 @@ pub fn duplicate_type_var(
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,
unifier: &mut Unifier, _unifier: &mut Unifier,
) -> Result<TypeAnnotation, String> { ) -> Result<TypeAnnotation, String> {
let obj_def = top_level_defs let obj_def =
.get(def_id.0) top_level_defs.get(def_id.0).ok_or_else(|| "invalid definition id".to_string())?;
.ok_or_else(|| "invalid definition id".to_string())?;
let obj_def = obj_def.read(); let obj_def = obj_def.read();
let obj_def = obj_def.deref(); let obj_def = obj_def.deref();
@ -276,10 +268,10 @@ pub fn make_self_type_annotation(
id: def_id, id: def_id,
params: type_vars params: type_vars
.iter() .iter()
// note here the var_id also points to the var_id of // NOTE: here the var_id also points to the var_id of
// the top level defined type var's var id // the top level defined type var's var id
.map(|(var_id, ty)| TypeAnnotation::TypeVarKind(*var_id, *ty)) .map(|(var_id, ty)| TypeAnnotation::TypeVarKind(*var_id, *ty))
.collect_vec() .collect_vec(),
}) })
} else { } else {
unreachable!("must be top level class def here") unreachable!("must be top level class def here")
@ -293,14 +285,14 @@ pub fn get_type_var_contained_in_type_annotation(ann: &TypeAnnotation) -> Vec<Ty
let mut result: Vec<TypeAnnotation> = Vec::new(); let mut result: Vec<TypeAnnotation> = Vec::new();
match ann { match ann {
TypeAnnotation::TypeVarKind(..) => result.push(ann.clone()), TypeAnnotation::TypeVarKind(..) => result.push(ann.clone()),
TypeAnnotation::VirtualKind(ann) => result.extend( TypeAnnotation::VirtualKind(ann) => {
get_type_var_contained_in_type_annotation(ann.as_ref()) result.extend(get_type_var_contained_in_type_annotation(ann.as_ref()))
), }
TypeAnnotation::CustomClassKind { params, .. } => { TypeAnnotation::CustomClassKind { params, .. } => {
for p in params { for p in params {
result.extend(get_type_var_contained_in_type_annotation(p)); result.extend(get_type_var_contained_in_type_annotation(p));
} }
}, }
_ => {} _ => {}
} }
result result