hm-inference #6
|
@ -200,14 +200,8 @@ 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 (
|
let (mut def_list, mut ast_list) = (self.definition_list.write(), self.ast_list.write());
|
||||||
mut def_list,
|
|
||||||
mut ast_list
|
|
||||||
) = (
|
|
||||||
self.definition_list.write(),
|
|
||||||
self.ast_list.write()
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(def_list.len(), ast_list.len());
|
assert_eq!(def_list.len(), ast_list.len());
|
||||||
|
|
||||||
match &ast.node {
|
match &ast.node {
|
||||||
|
@ -235,11 +229,14 @@ impl TopLevelComposer {
|
||||||
def_list.push(
|
def_list.push(
|
||||||
Self::make_top_level_function_def(
|
Self::make_top_level_function_def(
|
||||||
fun_name.clone(),
|
fun_name.clone(),
|
||||||
self.unifier.write().add_ty(TypeEnum::TFunc(FunSignature {
|
self.unifier.write().add_ty(TypeEnum::TFunc(
|
||||||
args: Default::default(),
|
FunSignature {
|
||||||
ret: self.primitives.none.into(),
|
args: Default::default(),
|
||||||
vars: Default::default(),
|
ret: self.primitives.none.into(),
|
||||||
}.into())),
|
vars: Default::default(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
resolver.clone(),
|
resolver.clone(),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
|
@ -256,17 +253,14 @@ impl TopLevelComposer {
|
||||||
ast_list[class_def_id] = Some(ast);
|
ast_list[class_def_id] = Some(ast);
|
||||||
|
|
||||||
// put the constructor into the def_list
|
// put the constructor into the def_list
|
||||||
def_list.push(
|
def_list
|
||||||
TopLevelDef::Initializer { class_id: DefinitionId(class_def_id) }
|
.push(TopLevelDef::Initializer { class_id: DefinitionId(class_def_id) }.into());
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
ast_list.push(None);
|
ast_list.push(None);
|
||||||
|
|
||||||
// class, put its def_id into the to be analyzed set
|
// class, put its def_id into the to be analyzed set
|
||||||
let mut to_be_analyzed = self.to_be_analyzed_class.write();
|
let mut to_be_analyzed = self.to_be_analyzed_class.write();
|
||||||
to_be_analyzed.push(DefinitionId(class_def_id));
|
to_be_analyzed.push(DefinitionId(class_def_id));
|
||||||
|
|
||||||
|
|
||||||
Ok((class_name, DefinitionId(class_def_id)))
|
Ok((class_name, DefinitionId(class_def_id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,27 +291,24 @@ impl TopLevelComposer {
|
||||||
for (class_def, class_ast) in def_list
|
for (class_def, class_ast) in def_list
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(ast_list.iter())
|
.zip(ast_list.iter())
|
||||||
.collect::<Vec<(&mut RwLock<TopLevelDef>, &Option<ast::Stmt<()>>)>>() {
|
.collect::<Vec<(&mut RwLock<TopLevelDef>, &Option<ast::Stmt<()>>)>>()
|
||||||
|
{
|
||||||
// only deal with class def here
|
// only deal with class def here
|
||||||
let (
|
let (class_bases, class_def_type_vars, class_resolver) = {
|
||||||
class_bases,
|
if let TopLevelDef::Class { type_vars, resolver, .. } = class_def.get_mut() {
|
||||||
class_def_type_vars,
|
if let Some(ast::Located {
|
||||||
class_resolver
|
node: ast::StmtKind::ClassDef { bases, .. }, ..
|
||||||
) = {
|
}) = class_ast
|
||||||
if let TopLevelDef::Class {
|
{
|
||||||
type_vars,
|
|
||||||
resolver,
|
|
||||||
..
|
|
||||||
} = class_def.get_mut() {
|
|
||||||
if let Some(ast::Located {node: ast::StmtKind::ClassDef {
|
|
||||||
bases,
|
|
||||||
..
|
|
||||||
}, .. }) = class_ast {
|
|
||||||
(bases, type_vars, resolver)
|
(bases, type_vars, resolver)
|
||||||
} else { unreachable!("must be both class") }
|
} else {
|
||||||
} else { continue }
|
unreachable!("must be both class")
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut is_generic = false;
|
let mut is_generic = false;
|
||||||
for b in class_bases {
|
for b in class_bases {
|
||||||
match &b.node {
|
match &b.node {
|
||||||
|
@ -326,84 +317,86 @@ impl TopLevelComposer {
|
||||||
// things like `class A(Generic[T, V, ImportedModule.T])` is not supported
|
// things like `class A(Generic[T, V, ImportedModule.T])` is not supported
|
||||||
// i.e. only simple names are allowed in the subscript
|
// i.e. only simple names are allowed in the subscript
|
||||||
// should update the TopLevelDef::Class.typevars and the TypeEnum::TObj.params
|
// should update the TopLevelDef::Class.typevars and the TypeEnum::TObj.params
|
||||||
ast::ExprKind::Subscript {value, slice, ..} if {
|
ast::ExprKind::Subscript { value, slice, .. }
|
||||||
// can only be `Generic[...]` and this can only appear once
|
if {
|
||||||
if let ast::ExprKind::Name { id, .. } = &value.node {
|
// can only be `Generic[...]` and this can only appear once
|
||||||
if id == "Generic" {
|
if let ast::ExprKind::Name { id, .. } = &value.node {
|
||||||
if !is_generic {
|
if id == "Generic" {
|
||||||
is_generic = true;
|
if !is_generic {
|
||||||
true
|
is_generic = true;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
return Err(
|
||||||
|
"Only single Generic[...] can be in bases".into()
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err("Only single Generic[...] can be in bases".into())
|
false
|
||||||
}
|
}
|
||||||
} else { false }
|
} else {
|
||||||
} else { false }
|
false
|
||||||
} => {
|
}
|
||||||
|
} =>
|
||||||
|
{
|
||||||
// if `class A(Generic[T, V, G])`
|
// if `class A(Generic[T, V, G])`
|
||||||
if let ast::ExprKind::Tuple { elts, .. } = &slice.node {
|
if let ast::ExprKind::Tuple { elts, .. } = &slice.node {
|
||||||
// parse the type vars
|
// parse the type vars
|
||||||
let type_vars = elts
|
let type_vars = elts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e|
|
.map(|e| {
|
||||||
class_resolver
|
class_resolver.as_ref().unwrap().lock().parse_type_annotation(
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.lock()
|
|
||||||
.parse_type_annotation(
|
|
||||||
&self.to_top_level_context(),
|
&self.to_top_level_context(),
|
||||||
unifier.borrow_mut(),
|
unifier.borrow_mut(),
|
||||||
&self.primitives,
|
&self.primitives,
|
||||||
e)
|
e,
|
||||||
)
|
)
|
||||||
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
// check if all are unique type vars
|
// check if all are unique type vars
|
||||||
let mut occured_type_var_id: HashSet<u32> = HashSet::new();
|
let mut occured_type_var_id: HashSet<u32> = HashSet::new();
|
||||||
let all_unique_type_var = type_vars
|
let all_unique_type_var = type_vars.iter().all(|x| {
|
||||||
.iter()
|
let ty = unifier.get_ty(*x);
|
||||||
.all(|x| {
|
if let TypeEnum::TVar { id, .. } = ty.as_ref() {
|
||||||
let ty = unifier.get_ty(*x);
|
occured_type_var_id.insert(*id)
|
||||||
if let TypeEnum::TVar {id, ..} = ty.as_ref() {
|
} else {
|
||||||
occured_type_var_id.insert(*id)
|
false
|
||||||
} else { false }
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if !all_unique_type_var { return Err("expect unique type variables".into()) }
|
if !all_unique_type_var {
|
||||||
|
return Err("expect unique type variables".into());
|
||||||
|
}
|
||||||
|
|
||||||
// add to TopLevelDef
|
// add to TopLevelDef
|
||||||
class_def_type_vars.extend(type_vars);
|
class_def_type_vars.extend(type_vars);
|
||||||
|
|
||||||
// `class A(Generic[T])`
|
// `class A(Generic[T])`
|
||||||
} else {
|
} else {
|
||||||
let ty =
|
let ty =
|
||||||
class_resolver
|
class_resolver.as_ref().unwrap().lock().parse_type_annotation(
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.lock()
|
|
||||||
.parse_type_annotation(
|
|
||||||
&self.to_top_level_context(),
|
&self.to_top_level_context(),
|
||||||
unifier.borrow_mut(),
|
unifier.borrow_mut(),
|
||||||
&self.primitives,
|
&self.primitives,
|
||||||
&slice
|
&slice,
|
||||||
)?;
|
)?;
|
||||||
// check if it is type var
|
// check if it is type var
|
||||||
let is_type_var = matches!(
|
let is_type_var =
|
||||||
unifier.get_ty(ty).as_ref(),
|
matches!(unifier.get_ty(ty).as_ref(), &TypeEnum::TVar { .. });
|
||||||
&TypeEnum::TVar { .. }
|
if !is_type_var {
|
||||||
);
|
return Err("expect type variable here".into());
|
||||||
if !is_type_var { return Err("expect type variable here".into()) }
|
}
|
||||||
|
|
||||||
// add to TopLevelDef
|
// add to TopLevelDef
|
||||||
class_def_type_vars.push(ty);
|
class_def_type_vars.push(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if others, do nothing in this function
|
// if others, do nothing in this function
|
||||||
_ => continue
|
_ => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,30 +413,29 @@ impl TopLevelComposer {
|
||||||
for (class_def, class_ast) in def_list
|
for (class_def, class_ast) in def_list
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(ast_list.iter())
|
.zip(ast_list.iter())
|
||||||
.collect::<Vec<(&mut RwLock<TopLevelDef>, &Option<ast::Stmt<()>>)>>() {
|
.collect::<Vec<(&mut RwLock<TopLevelDef>, &Option<ast::Stmt<()>>)>>()
|
||||||
let (
|
{
|
||||||
class_bases,
|
let (class_bases, class_ancestors, class_resolver) = {
|
||||||
class_ancestors,
|
if let TopLevelDef::Class { ancestors, resolver, .. } = class_def.get_mut() {
|
||||||
class_resolver
|
if let Some(ast::Located {
|
||||||
) = {
|
node: ast::StmtKind::ClassDef { bases, .. }, ..
|
||||||
if let TopLevelDef::Class {
|
}) = class_ast
|
||||||
ancestors,
|
{
|
||||||
resolver,
|
|
||||||
..
|
|
||||||
} = class_def.get_mut() {
|
|
||||||
if let Some(ast::Located {node: ast::StmtKind::ClassDef {
|
|
||||||
bases,
|
|
||||||
..
|
|
||||||
}, .. }) = class_ast {
|
|
||||||
(bases, ancestors, resolver)
|
(bases, ancestors, resolver)
|
||||||
} else { unreachable!("must be both class") }
|
} else {
|
||||||
} else { continue }
|
unreachable!("must be both class")
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
for b in class_bases {
|
for b in class_bases {
|
||||||
// type vars have already been handled, so skip on `Generic[...]`
|
// type vars have already been handled, so skip on `Generic[...]`
|
||||||
if let ast::ExprKind::Subscript {value, ..} = &b.node {
|
if let ast::ExprKind::Subscript { value, .. } = &b.node {
|
||||||
if let ast::ExprKind::Name {id, ..} = &value.node {
|
if let ast::ExprKind::Name { id, .. } = &value.node {
|
||||||
if id == "Generic" { continue }
|
if id == "Generic" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// get the def id of the base class
|
// get the def id of the base class
|
||||||
|
@ -451,18 +443,19 @@ impl TopLevelComposer {
|
||||||
&self.to_top_level_context(),
|
&self.to_top_level_context(),
|
||||||
unifier.borrow_mut(),
|
unifier.borrow_mut(),
|
||||||
&self.primitives,
|
&self.primitives,
|
||||||
b
|
b,
|
||||||
)?;
|
)?;
|
||||||
let base_id =
|
let base_id =
|
||||||
if let TypeEnum::TObj {obj_id, ..} = unifier.get_ty(base_ty).as_ref() {
|
if let TypeEnum::TObj { obj_id, .. } = unifier.get_ty(base_ty).as_ref() {
|
||||||
*obj_id
|
*obj_id
|
||||||
} else { return Err("expect concrete class/type to be base class".into()) };
|
} else {
|
||||||
|
return Err("expect concrete class/type to be base class".into());
|
||||||
|
};
|
||||||
|
|
||||||
// write to the class ancestors
|
// write to the class ancestors
|
||||||
class_ancestors.push(base_id);
|
class_ancestors.push(base_id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,21 +471,18 @@ impl TopLevelComposer {
|
||||||
let class_ind = to_be_analyzed_class.remove(0).0;
|
let class_ind = to_be_analyzed_class.remove(0).0;
|
||||||
let (class_name, class_body) = {
|
let (class_name, class_body) = {
|
||||||
let class_ast = &ast_list[class_ind];
|
let class_ast = &ast_list[class_ind];
|
||||||
if let Some(
|
if let Some(ast::Located {
|
||||||
ast::Located { node:
|
node: ast::StmtKind::ClassDef { name, body, .. }, ..
|
||||||
ast::StmtKind::ClassDef {
|
}) = class_ast
|
||||||
name,
|
{
|
||||||
body,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
}
|
|
||||||
) = class_ast {
|
|
||||||
(name, body)
|
(name, body)
|
||||||
} else { unreachable!("should be class def ast") }
|
} else {
|
||||||
|
unreachable!("should be class def ast")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let class_methods_parsing_result: Vec<(String, Type, DefinitionId)> = Default::default();
|
let class_methods_parsing_result: Vec<(String, Type, DefinitionId)> =
|
||||||
|
Default::default();
|
||||||
let class_fields_parsing_result: Vec<(String, Type)> = Default::default();
|
let class_fields_parsing_result: Vec<(String, Type)> = Default::default();
|
||||||
for b in class_body {
|
for b in class_body {
|
||||||
if let ast::StmtKind::FunctionDef {
|
if let ast::StmtKind::FunctionDef {
|
||||||
|
@ -501,25 +491,24 @@ impl TopLevelComposer {
|
||||||
name: method_name,
|
name: method_name,
|
||||||
returns: method_returns_ast,
|
returns: method_returns_ast,
|
||||||
..
|
..
|
||||||
} = &b.node {
|
} = &b.node
|
||||||
|
{
|
||||||
let (class_def, method_def) = {
|
let (class_def, method_def) = {
|
||||||
// unwrap should not fail
|
// unwrap should not fail
|
||||||
let method_ind = class_method_to_def_id
|
let method_ind = class_method_to_def_id
|
||||||
.get(&Self::name_mangling(
|
.get(&Self::name_mangling(class_name.into(), method_name))
|
||||||
class_name.into(),
|
.unwrap()
|
||||||
method_name)
|
.0;
|
||||||
).unwrap().0;
|
|
||||||
|
|
||||||
// split the def_list to two parts to get the
|
// split the def_list to two parts to get the
|
||||||
// mutable reference to both the method and the class
|
// mutable reference to both the method and the class
|
||||||
assert_ne!(method_ind, class_ind);
|
assert_ne!(method_ind, class_ind);
|
||||||
let min_ind = (if method_ind > class_ind { class_ind } else { method_ind }) + 1;
|
let min_ind =
|
||||||
let (head_slice,
|
(if method_ind > class_ind { class_ind } else { method_ind }) + 1;
|
||||||
tail_slice
|
let (head_slice, tail_slice) = def_list.split_at_mut(min_ind);
|
||||||
) = def_list.split_at_mut(min_ind);
|
|
||||||
let (new_method_ind, new_class_ind) = (
|
let (new_method_ind, new_class_ind) = (
|
||||||
if method_ind >= min_ind { method_ind - min_ind } else { method_ind },
|
if method_ind >= min_ind { method_ind - min_ind } else { method_ind },
|
||||||
if class_ind >= min_ind { class_ind - min_ind } else { class_ind }
|
if class_ind >= min_ind { class_ind - min_ind } else { class_ind },
|
||||||
);
|
);
|
||||||
if new_class_ind == class_ind {
|
if new_class_ind == class_ind {
|
||||||
(&mut head_slice[new_class_ind], &mut tail_slice[new_method_ind])
|
(&mut head_slice[new_class_ind], &mut tail_slice[new_method_ind])
|
||||||
|
@ -527,19 +516,14 @@ impl TopLevelComposer {
|
||||||
(&mut tail_slice[new_class_ind], &mut head_slice[new_method_ind])
|
(&mut tail_slice[new_class_ind], &mut head_slice[new_method_ind])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (
|
let (class_fields, class_methods, class_resolver) = {
|
||||||
class_fields,
|
if let TopLevelDef::Class { resolver, fields, methods, .. } =
|
||||||
class_methods,
|
class_def.get_mut()
|
||||||
class_resolver
|
{
|
||||||
) = {
|
|
||||||
if let TopLevelDef::Class {
|
|
||||||
resolver,
|
|
||||||
fields,
|
|
||||||
methods,
|
|
||||||
..
|
|
||||||
} = class_def.get_mut() {
|
|
||||||
(fields, methods, resolver)
|
(fields, methods, resolver)
|
||||||
} else { unreachable!("must be class def here") }
|
} else {
|
||||||
|
unreachable!("must be class def here")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let arg_tys = method_args_ast
|
let arg_tys = method_args_ast
|
||||||
|
@ -550,18 +534,17 @@ impl TopLevelComposer {
|
||||||
.node
|
.node
|
||||||
.annotation
|
.annotation
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or_else(|| "type annotation for function parameter is needed".to_string())?
|
.ok_or_else(|| {
|
||||||
|
"type annotation for function parameter is needed".to_string()
|
||||||
|
})?
|
||||||
.as_ref();
|
.as_ref();
|
||||||
|
|
||||||
let ty = class_resolver
|
let ty =
|
||||||
.as_ref()
|
class_resolver.as_ref().unwrap().lock().parse_type_annotation(
|
||||||
.unwrap()
|
|
||||||
.lock()
|
|
||||||
.parse_type_annotation(
|
|
||||||
&self.to_top_level_context(),
|
&self.to_top_level_context(),
|
||||||
unifier.borrow_mut(),
|
unifier.borrow_mut(),
|
||||||
&self.primitives,
|
&self.primitives,
|
||||||
annotation
|
annotation,
|
||||||
)?;
|
)?;
|
||||||
Ok(ty)
|
Ok(ty)
|
||||||
})
|
})
|
||||||
|
@ -569,39 +552,37 @@ impl TopLevelComposer {
|
||||||
let ret_ty = method_returns_ast
|
let ret_ty = method_returns_ast
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|x| {
|
.and_then(|x| {
|
||||||
Some(
|
Some(class_resolver.as_ref().unwrap().lock().parse_type_annotation(
|
||||||
class_resolver
|
&self.to_top_level_context(),
|
||||||
.as_ref()
|
unifier.borrow_mut(),
|
||||||
.unwrap()
|
&self.primitives,
|
||||||
.lock()
|
x.as_ref(),
|
||||||
.parse_type_annotation(
|
))
|
||||||
&self.to_top_level_context(),
|
})
|
||||||
unifier.borrow_mut(),
|
.unwrap()?;
|
||||||
&self.primitives,
|
|
||||||
x.as_ref()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}).unwrap()?;
|
|
||||||
|
|
||||||
let all_tys_ok = {
|
let all_tys_ok = {
|
||||||
let ret_ty_iter = vec![ret_ty];
|
let ret_ty_iter = vec![ret_ty];
|
||||||
let ret_ty_iter = ret_ty_iter.iter();
|
let ret_ty_iter = ret_ty_iter.iter();
|
||||||
let mut all_tys = chain!(arg_tys.iter(), ret_ty_iter);
|
let mut all_tys = chain!(arg_tys.iter(), ret_ty_iter);
|
||||||
all_tys.all(|x| {
|
all_tys.all(|x| {
|
||||||
let type_enum = unifier.get_ty(*x);
|
let type_enum = unifier.get_ty(*x);
|
||||||
match type_enum.as_ref() {
|
match type_enum.as_ref() {
|
||||||
TypeEnum::TObj {obj_id, ..} => {
|
TypeEnum::TObj { obj_id, .. } => {
|
||||||
!to_be_analyzed_class.contains(obj_id)
|
!to_be_analyzed_class.contains(obj_id)
|
||||||
},
|
|
||||||
TypeEnum::TVirtual { ty } => {
|
|
||||||
if let TypeEnum::TObj {obj_id, ..} = unifier.get_ty(*ty).as_ref() {
|
|
||||||
!to_be_analyzed_class.contains(obj_id)
|
|
||||||
} else { unreachable!() }
|
|
||||||
},
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
}
|
||||||
|
TypeEnum::TVirtual { ty } => {
|
||||||
|
if let TypeEnum::TObj { obj_id, .. } =
|
||||||
|
unifier.get_ty(*ty).as_ref()
|
||||||
|
{
|
||||||
|
!to_be_analyzed_class.contains(obj_id)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
if all_tys_ok {
|
if all_tys_ok {
|
||||||
|
@ -614,21 +595,21 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// what should we do with `class A: a = 3`?
|
// what should we do with `class A: a = 3`?
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: now it should be confirmed that every
|
// TODO: now it should be confirmed that every
|
||||||
// methods and fields of the class can be correctly typed, put the results
|
// methods and fields of the class can be correctly typed, put the results
|
||||||
// into the actual def_list and the unifier
|
// into the actual def_list and the unifier
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyze_top_level_inheritance(&mut self) -> Result<(), String> {
|
fn analyze_top_level_inheritance(&mut self) -> Result<(), String> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyze_top_level_field_instantiation(&mut self) -> Result<(), String> {
|
fn analyze_top_level_field_instantiation(&mut self) -> Result<(), String> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,11 +80,18 @@ pub fn impl_binop(
|
||||||
} else {
|
} else {
|
||||||
unifier.get_fresh_var_with_range(other_ty).0
|
unifier.get_fresh_var_with_range(other_ty).0
|
||||||
};
|
};
|
||||||
unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
unifier.add_ty(TypeEnum::TFunc(
|
||||||
ret: ret_ty,
|
FunSignature {
|
||||||
vars: HashMap::new(),
|
ret: ret_ty,
|
||||||
args: vec![FuncArg { ty: other, default_value: None, name: "other".into() }],
|
vars: HashMap::new(),
|
||||||
}.into()))
|
args: vec![FuncArg {
|
||||||
|
ty: other,
|
||||||
|
default_value: None,
|
||||||
|
name: "other".into(),
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
fields.borrow_mut().insert(binop_assign_name(op).into(), {
|
fields.borrow_mut().insert(binop_assign_name(op).into(), {
|
||||||
|
@ -93,11 +100,18 @@ pub fn impl_binop(
|
||||||
} else {
|
} else {
|
||||||
unifier.get_fresh_var_with_range(other_ty).0
|
unifier.get_fresh_var_with_range(other_ty).0
|
||||||
};
|
};
|
||||||
unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
unifier.add_ty(TypeEnum::TFunc(
|
||||||
ret: ret_ty,
|
FunSignature {
|
||||||
vars: HashMap::new(),
|
ret: ret_ty,
|
||||||
args: vec![FuncArg { ty: other, default_value: None, name: "other".into() }],
|
vars: HashMap::new(),
|
||||||
}.into()))
|
args: vec![FuncArg {
|
||||||
|
ty: other,
|
||||||
|
default_value: None,
|
||||||
|
name: "other".into(),
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -116,11 +130,9 @@ pub fn impl_unaryop(
|
||||||
for op in ops {
|
for op in ops {
|
||||||
fields.borrow_mut().insert(
|
fields.borrow_mut().insert(
|
||||||
unaryop_name(op).into(),
|
unaryop_name(op).into(),
|
||||||
unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
unifier.add_ty(TypeEnum::TFunc(
|
||||||
ret: ret_ty,
|
FunSignature { ret: ret_ty, vars: HashMap::new(), args: vec![] }.into(),
|
||||||
vars: HashMap::new(),
|
)),
|
||||||
args: vec![],
|
|
||||||
}.into())),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -139,11 +151,18 @@ pub fn impl_cmpop(
|
||||||
for op in ops {
|
for op in ops {
|
||||||
fields.borrow_mut().insert(
|
fields.borrow_mut().insert(
|
||||||
comparison_name(op).unwrap().into(),
|
comparison_name(op).unwrap().into(),
|
||||||
unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
unifier.add_ty(TypeEnum::TFunc(
|
||||||
ret: store.bool,
|
FunSignature {
|
||||||
vars: HashMap::new(),
|
ret: store.bool,
|
||||||
args: vec![FuncArg { ty: other_ty, default_value: None, name: "other".into() }],
|
vars: HashMap::new(),
|
||||||
}.into())),
|
args: vec![FuncArg {
|
||||||
|
ty: other_ty,
|
||||||
|
default_value: None,
|
||||||
|
name: "other".into(),
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -176,18 +176,19 @@ impl TestEnvironment {
|
||||||
|
|
||||||
identifier_mapping.insert(
|
identifier_mapping.insert(
|
||||||
"Foo".into(),
|
"Foo".into(),
|
||||||
unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
unifier.add_ty(TypeEnum::TFunc(
|
||||||
args: vec![],
|
FunSignature {
|
||||||
ret: foo_ty,
|
args: vec![],
|
||||||
vars: [(id, v0)].iter().cloned().collect(),
|
ret: foo_ty,
|
||||||
}.into())),
|
vars: [(id, v0)].iter().cloned().collect(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let fun = unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
let fun = unifier.add_ty(TypeEnum::TFunc(
|
||||||
args: vec![],
|
FunSignature { args: vec![], ret: int32, vars: Default::default() }.into(),
|
||||||
ret: int32,
|
));
|
||||||
vars: Default::default(),
|
|
||||||
}.into()));
|
|
||||||
let bar = unifier.add_ty(TypeEnum::TObj {
|
let bar = unifier.add_ty(TypeEnum::TObj {
|
||||||
obj_id: DefinitionId(6),
|
obj_id: DefinitionId(6),
|
||||||
fields: [("a".into(), int32), ("b".into(), fun)]
|
fields: [("a".into(), int32), ("b".into(), fun)]
|
||||||
|
@ -207,11 +208,9 @@ impl TestEnvironment {
|
||||||
}));
|
}));
|
||||||
identifier_mapping.insert(
|
identifier_mapping.insert(
|
||||||
"Bar".into(),
|
"Bar".into(),
|
||||||
unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
unifier.add_ty(TypeEnum::TFunc(
|
||||||
args: vec![],
|
FunSignature { args: vec![], ret: bar, vars: Default::default() }.into(),
|
||||||
ret: bar,
|
)),
|
||||||
vars: Default::default(),
|
|
||||||
}.into())),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let bar2 = unifier.add_ty(TypeEnum::TObj {
|
let bar2 = unifier.add_ty(TypeEnum::TObj {
|
||||||
|
@ -233,11 +232,9 @@ impl TestEnvironment {
|
||||||
}));
|
}));
|
||||||
identifier_mapping.insert(
|
identifier_mapping.insert(
|
||||||
"Bar2".into(),
|
"Bar2".into(),
|
||||||
unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
unifier.add_ty(TypeEnum::TFunc(
|
||||||
args: vec![],
|
FunSignature { args: vec![], ret: bar2, vars: Default::default() }.into(),
|
||||||
ret: bar2,
|
)),
|
||||||
vars: Default::default(),
|
|
||||||
}.into())),
|
|
||||||
);
|
);
|
||||||
let class_names = [("Bar".into(), bar), ("Bar2".into(), bar2)].iter().cloned().collect();
|
let class_names = [("Bar".into(), bar), ("Bar2".into(), bar2)].iter().cloned().collect();
|
||||||
|
|
||||||
|
|
|
@ -472,7 +472,8 @@ impl Unifier {
|
||||||
}
|
}
|
||||||
(TCall(calls), TFunc(signature)) => {
|
(TCall(calls), TFunc(signature)) => {
|
||||||
self.occur_check(a, b)?;
|
self.occur_check(a, b)?;
|
||||||
let required: Vec<String> = signature.borrow()
|
let required: Vec<String> = signature
|
||||||
|
.borrow()
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|v| v.default_value.is_none())
|
.filter(|v| v.default_value.is_none())
|
||||||
|
@ -494,8 +495,13 @@ impl Unifier {
|
||||||
// we check to make sure that all required arguments (those without default
|
// we check to make sure that all required arguments (those without default
|
||||||
// arguments) are provided, and do not provide the same argument twice.
|
// arguments) are provided, and do not provide the same argument twice.
|
||||||
let mut required = required.clone();
|
let mut required = required.clone();
|
||||||
let mut all_names: Vec<_> =
|
let mut all_names: Vec<_> = signature
|
||||||
signature.borrow().args.iter().map(|v| (v.name.clone(), v.ty)).rev().collect();
|
.borrow()
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|v| (v.name.clone(), v.ty))
|
||||||
|
.rev()
|
||||||
|
.collect();
|
||||||
for (i, t) in posargs.iter().enumerate() {
|
for (i, t) in posargs.iter().enumerate() {
|
||||||
if signature.borrow().args.len() <= i {
|
if signature.borrow().args.len() <= i {
|
||||||
return Err("Too many arguments.".to_string());
|
return Err("Too many arguments.".to_string());
|
||||||
|
@ -741,7 +747,11 @@ impl Unifier {
|
||||||
let params = new_params.unwrap_or_else(|| params.clone());
|
let params = new_params.unwrap_or_else(|| params.clone());
|
||||||
let ret = new_ret.unwrap_or_else(|| *ret);
|
let ret = new_ret.unwrap_or_else(|| *ret);
|
||||||
let args = new_args.into_owned();
|
let args = new_args.into_owned();
|
||||||
Some(self.add_ty(TypeEnum::TFunc(FunSignature { args, ret, vars: params }.into())))
|
Some(
|
||||||
|
self.add_ty(TypeEnum::TFunc(
|
||||||
|
FunSignature { args, ret, vars: params }.into(),
|
||||||
|
)),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -329,11 +329,9 @@ fn test_invalid_unification(
|
||||||
fn test_virtual() {
|
fn test_virtual() {
|
||||||
let mut env = TestEnvironment::new();
|
let mut env = TestEnvironment::new();
|
||||||
let int = env.parse("int", &HashMap::new());
|
let int = env.parse("int", &HashMap::new());
|
||||||
let fun = env.unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
let fun = env.unifier.add_ty(TypeEnum::TFunc(
|
||||||
args: vec![],
|
FunSignature { args: vec![], ret: int, vars: HashMap::new() }.into(),
|
||||||
ret: int,
|
));
|
||||||
vars: HashMap::new(),
|
|
||||||
}.into()));
|
|
||||||
let bar = env.unifier.add_ty(TypeEnum::TObj {
|
let bar = env.unifier.add_ty(TypeEnum::TObj {
|
||||||
obj_id: DefinitionId(5),
|
obj_id: DefinitionId(5),
|
||||||
fields: [("f".to_string(), fun), ("a".to_string(), int)]
|
fields: [("f".to_string(), fun), ("a".to_string(), int)]
|
||||||
|
|
Loading…
Reference in New Issue