forked from M-Labs/nac3
1
0
Fork 0

handle type var associated with class/function partially, change llvm version of nac3embedded to 11

format
This commit is contained in:
ychenfo 2021-08-23 16:57:50 +08:00
parent 39f300b62a
commit 56f082ca7c
5 changed files with 136 additions and 93 deletions

35
Cargo.lock generated
View File

@ -311,8 +311,7 @@ dependencies = [
"either", "either",
"inkwell_internals", "inkwell_internals",
"libc", "libc",
"llvm-sys 100.2.1", "llvm-sys",
"llvm-sys 110.0.1",
"once_cell", "once_cell",
"parking_lot", "parking_lot",
"regex", "regex",
@ -412,19 +411,6 @@ version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
[[package]]
name = "llvm-sys"
version = "100.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15d9c00ce56221b2150e2d4d51887ff139fce5a0e50346c744861d1e66d2f7c4"
dependencies = [
"cc",
"lazy_static",
"libc",
"regex",
"semver 0.9.0",
]
[[package]] [[package]]
name = "llvm-sys" name = "llvm-sys"
version = "110.0.1" version = "110.0.1"
@ -435,7 +421,7 @@ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
"regex", "regex",
"semver 0.11.0", "semver",
] ]
[[package]] [[package]]
@ -907,30 +893,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser 0.7.0",
]
[[package]] [[package]]
name = "semver" name = "semver"
version = "0.11.0" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [ dependencies = [
"semver-parser 0.10.2", "semver-parser",
] ]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]] [[package]]
name = "semver-parser" name = "semver-parser"
version = "0.10.2" version = "0.10.2"

View File

@ -140,7 +140,7 @@ pub fn parse_type_annotation<T>(
} }
let mut subst = HashMap::new(); let mut subst = HashMap::new();
for (var, ty) in izip!(type_vars.iter(), types.iter()) { for (var, ty) in izip!(type_vars.iter(), types.iter()) {
let id = if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*var) { let id = if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(var.1) {
*id *id
} else { } else {
unreachable!() unreachable!()

View File

@ -16,6 +16,7 @@ pub struct DefinitionId(pub usize);
pub mod top_level_type_annotation_info { pub mod top_level_type_annotation_info {
use super::*; use super::*;
use crate::typecheck::typedef::TypeVarMeta;
#[derive(Clone)] #[derive(Clone)]
pub enum TypeAnnotation { pub enum TypeAnnotation {
@ -23,11 +24,17 @@ pub mod top_level_type_annotation_info {
ConcretizedCustomClassKind { ConcretizedCustomClassKind {
id: DefinitionId, id: DefinitionId,
// can not be type var, others are all fine // can not be type var, others are all fine
// TODO: can also be type var?
params: Vec<TypeAnnotation>, params: Vec<TypeAnnotation>,
}, },
// can only be ConcretizedCustomClassKind // can only be ConcretizedCustomClassKind
VirtualKind(Box<TypeAnnotation>), VirtualKind(Box<TypeAnnotation>),
TypeVarKind(Type), // the first u32 refers to the var_id of the
// TVar returned by the symbol resolver,
// this is used to handle type vars
// associated with class/functions
// since when associating we create a copy of type vars
TypeVarKind(u32, Type),
SelfTypeKind(DefinitionId), SelfTypeKind(DefinitionId),
} }
@ -97,7 +104,10 @@ pub mod top_level_type_annotation_info {
let subst = type_vars let subst = type_vars
.iter() .iter()
.map(|x| { .map(|x| {
if let TypeEnum::TVar { id, .. } = unifier.get_ty(*x).as_ref() { if let TypeEnum::TVar { id, .. } = unifier.get_ty(x.1).as_ref() {
// this is for the class generic application,
// we only need the information for the copied type var
// associated with the class
*id *id
} else { } else {
unreachable!() unreachable!()
@ -134,8 +144,8 @@ pub mod top_level_type_annotation_info {
let subst = type_vars let subst = type_vars
.iter() .iter()
.map(|x| { .map(|x| {
if let TypeEnum::TVar { id, .. } = unifier.get_ty(*x).as_ref() { if let TypeEnum::TVar { id, .. } = unifier.get_ty(x.1).as_ref() {
(*id, *x) (*id, x.1)
} else { } else {
unreachable!() unreachable!()
} }
@ -158,7 +168,7 @@ pub mod top_level_type_annotation_info {
} }
} }
TypeAnnotation::PrimitiveKind(ty) => Ok(*ty), TypeAnnotation::PrimitiveKind(ty) => Ok(*ty),
TypeAnnotation::TypeVarKind(ty) => Ok(*ty), TypeAnnotation::TypeVarKind(_, ty) => Ok(*ty),
TypeAnnotation::VirtualKind(ty) => { TypeAnnotation::VirtualKind(ty) => {
let ty = get_type_from_type_annotation_kinds( let ty = get_type_from_type_annotation_kinds(
top_level_defs, top_level_defs,
@ -252,14 +262,15 @@ pub mod top_level_type_annotation_info {
slice, slice,
)?] )?]
}; };
if param_type_infos // TODO: allow type var in class generic application list
.iter() // if param_type_infos
.any(|x| matches!(x, TypeAnnotation::TypeVarKind(..))) // .iter()
{ // .any(|x| matches!(x, TypeAnnotation::TypeVarKind(..)))
return Err( // {
"cannot apply type variable to class generic parameters".into() // return Err(
); // "cannot apply type variable to class generic parameters".into()
} // );
// }
Ok(TypeAnnotation::ConcretizedCustomClassKind { Ok(TypeAnnotation::ConcretizedCustomClassKind {
id: obj_id, id: obj_id,
params: param_type_infos, params: param_type_infos,
@ -315,8 +326,15 @@ 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())?;
if let TypeEnum::TVar { .. } = unifier.get_ty(ty).as_ref() { if let TypeEnum::TVar { id, meta: TypeVarMeta::Generic, range } =
Ok(TypeAnnotation::TypeVarKind(ty)) unifier.get_ty(ty).as_ref()
{
// NOTE: always create a new one here
// and later unify if needed
// but record the var_id of the original type var returned by symbol resolver
let range = range.borrow();
let range = range.as_slice();
Ok(TypeAnnotation::TypeVarKind(*id, unifier.get_fresh_var_with_range(range).0))
} else { } else {
Err("not a type variable identifier".into()) Err("not a type variable identifier".into())
} }
@ -333,7 +351,10 @@ pub enum TopLevelDef {
// 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.
type_vars: Vec<Type>, // the first field in the tuple is the var_id of the
// original typevar defined in the top level and returned
// by the symbol resolver
type_vars: Vec<(u32, Type)>,
// class fields // class fields
fields: Vec<(String, Type)>, fields: Vec<(String, Type)>,
// class methods, pointing to the corresponding function definition. // class methods, pointing to the corresponding function definition.
@ -518,6 +539,7 @@ impl TopLevelComposer {
} }
/// step 0, register, just remeber the names of top level classes/function /// step 0, register, just remeber the names of top level classes/function
/// and check duplicate class/method/function definition
pub fn register_top_level( pub fn register_top_level(
&mut self, &mut self,
ast: ast::Stmt<()>, ast: ast::Stmt<()>,
@ -724,26 +746,25 @@ impl TopLevelComposer {
false false
} }
}); });
if !all_unique_type_var {
return Err("expect unique type variables".into());
}
// NOTE: create a copy of all type vars for the type vars associated with class // NOTE: create a copy of all type vars for the type vars associated with class
let type_vars = type_vars let type_vars = type_vars
.into_iter() .into_iter()
.map(|x| { .map(|x| {
let range = unifier.get_ty(x); let range = unifier.get_ty(x);
if let TypeEnum::TVar { range, .. } = range.as_ref() { if let TypeEnum::TVar { id, range, .. } = range.as_ref() {
let range = &*range.borrow(); let range = &*range.borrow();
let range = range.as_slice(); let range = range.as_slice();
unifier.get_fresh_var_with_range(range).0 (*id, unifier.get_fresh_var_with_range(range).0)
} else { } else {
unreachable!("must be type var here"); unreachable!("must be type var here after previous check");
} }
}) })
.collect_vec(); .collect_vec();
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);
} }
@ -874,14 +895,21 @@ 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(); // occured type vars should not be handled separately
let have_unique_fuction_parameter_name = // TODO: type vars occured as applications of generic classes is not handled
args.args.iter().all(|x| defined_paramter_name.insert(x.node.arg.clone())); let mut occured_type_var: HashMap<u32, Type> = HashMap::new();
if !have_unique_fuction_parameter_name { let mut function_var_map: HashMap<u32, Type> = HashMap::new();
return Err("top level function have duplicate parameter name".into());
}
let arg_types = { let arg_types = {
// make sure no duplicate parameter
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());
}
args.args args.args
.iter() .iter()
.map(|x| -> Result<FuncArg, String> { .map(|x| -> Result<FuncArg, String> {
@ -893,14 +921,33 @@ impl TopLevelComposer {
"function parameter type annotation needed".to_string() "function parameter type annotation needed".to_string()
})? })?
.as_ref(); .as_ref();
let mut ty = function_resolver.parse_type_annotation(
temp_def_list.as_slice(),
unifier,
primitives_store,
annotation,
)?;
if let TypeEnum::TVar { id, range, .. } =
unifier.get_ty(ty).as_ref()
{
if let Some(occured_ty) = occured_type_var.get(id) {
// if already occured
ty = *occured_ty;
} else {
// if not, create a duplicate
let range = range.borrow();
let range = range.as_slice();
let ty_copy = unifier.get_fresh_var_with_range(range);
ty = ty_copy.0;
occured_type_var.insert(*id, ty);
function_var_map.insert(ty_copy.1, ty_copy.0);
}
}
Ok(FuncArg { Ok(FuncArg {
name: x.node.arg.clone(), name: x.node.arg.clone(),
ty: function_resolver.parse_type_annotation( ty,
temp_def_list.as_slice(),
unifier,
primitives_store,
annotation,
)?,
// TODO: function type var // TODO: function type var
default_value: Default::default(), default_value: Default::default(),
}) })
@ -922,13 +969,8 @@ impl TopLevelComposer {
}; };
let function_ty = unifier.add_ty(TypeEnum::TFunc( let function_ty = unifier.add_ty(TypeEnum::TFunc(
FunSignature { FunSignature { args: arg_types, ret: return_ty, vars: function_var_map }
args: arg_types, .into(),
ret: return_ty,
// TODO: handle var map
vars: Default::default(),
}
.into(),
)); ));
unifier.unify(*dummy_ty, function_ty)?; unifier.unify(*dummy_ty, function_ty)?;
} else { } else {
@ -964,7 +1006,7 @@ impl TopLevelComposer {
_class_ancestor_def, _class_ancestor_def,
class_fields_def, class_fields_def,
class_methods_def, class_methods_def,
_class_type_vars_def, class_type_vars_def,
class_resolver, class_resolver,
) = if let TopLevelDef::Class { ) = if let TopLevelDef::Class {
object_id, object_id,
@ -1003,15 +1045,19 @@ impl TopLevelComposer {
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)?;
let mut defined_paramter_name: HashSet<String> = HashSet::new(); // handle var map, to create a new copy of type var
let have_unique_fuction_parameter_name = // while tracking the type var associated with class
args.args.iter().all(|x| defined_paramter_name.insert(x.node.arg.clone())); // TODO: type vars occured as applications of generic classes is not handled
if !have_unique_fuction_parameter_name { let mut method_var_map: HashMap<u32, Type> = HashMap::new();
return Err("class method have duplicate parameter name".into());
}
// TODO: handle parameter with same name
let arg_type: Vec<FuncArg> = { let arg_type: Vec<FuncArg> = {
// check method parameters cannot have same name
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());
}
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();
@ -1031,9 +1077,37 @@ impl TopLevelComposer {
annotation_expr, annotation_expr,
)? )?
}; };
if let TypeAnnotation::TypeVarKind(_ty) = &type_ann { // handle to differentiate type vars that are
// TODO: need to handle to different 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!("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,
@ -1087,9 +1161,7 @@ impl TopLevelComposer {
dummy_return_type dummy_return_type
} }
}; };
// TODO: handle var map, to create a new copy of type var
// while tracking the type var associated with class
let method_var_map: HashMap<u32, Type> = HashMap::new();
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_type, ret: ret_type, vars: method_var_map }.into(),
)); ));

View File

@ -173,7 +173,7 @@ impl TestEnvironment {
RwLock::new(TopLevelDef::Class { RwLock::new(TopLevelDef::Class {
name: "Foo".to_string(), name: "Foo".to_string(),
object_id: DefinitionId(5), object_id: DefinitionId(5),
type_vars: vec![v0], type_vars: vec![(id, v0)],
fields: [("a".into(), v0)].into(), fields: [("a".into(), v0)].into(),
methods: Default::default(), methods: Default::default(),
ancestors: Default::default(), ancestors: Default::default(),

View File

@ -10,6 +10,6 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
pyo3 = { version = "0.12.4", features = ["extension-module"] } pyo3 = { version = "0.12.4", features = ["extension-module"] }
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm10-0"] } inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm11-0"] }
rustpython-parser = { git = "https://github.com/RustPython/RustPython", branch = "master" } rustpython-parser = { git = "https://github.com/RustPython/RustPython", branch = "master" }
nac3core = { path = "../nac3core" } nac3core = { path = "../nac3core" }