From 3a93e2b048e77045b97a91299702d8aeac48e1da Mon Sep 17 00:00:00 2001 From: ychenfo Date: Thu, 12 Aug 2021 13:17:51 +0800 Subject: [PATCH] TypeEnum::TObj.param is now RefCell for interior mutability --- nac3core/src/codegen/expr.rs | 2 +- nac3core/src/symbol_resolver.rs | 3 +- nac3core/src/top_level.rs | 67 +++++++++---------- .../src/typecheck/type_inferencer/test.rs | 22 +++--- nac3core/src/typecheck/typedef/mod.rs | 13 ++-- nac3core/src/typecheck/typedef/test.rs | 13 ++-- 6 files changed, 61 insertions(+), 59 deletions(-) diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index 2f4c74db5..d21d3ba79 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -19,7 +19,7 @@ impl<'ctx> CodeGenContext<'ctx> { let mut vars = obj .map(|ty| { if let TypeEnum::TObj { params, .. } = &*self.unifier.get_ty(ty) { - params.clone() + params.borrow().clone() } else { unreachable!() } diff --git a/nac3core/src/symbol_resolver.rs b/nac3core/src/symbol_resolver.rs index b6e3b7929..ff0489276 100644 --- a/nac3core/src/symbol_resolver.rs +++ b/nac3core/src/symbol_resolver.rs @@ -143,8 +143,7 @@ impl dyn SymbolResolver { let ty = unifier.subst(*ty, &subst).unwrap_or(*ty); (attr.clone(), ty) })); - let fields = RefCell::new(fields); - Ok(unifier.add_ty(TypeEnum::TObj { obj_id, fields, params: subst })) + Ok(unifier.add_ty(TypeEnum::TObj { obj_id, fields: fields.into(), params: subst.into() })) } else { Err("Cannot use function name as type".into()) } diff --git a/nac3core/src/top_level.rs b/nac3core/src/top_level.rs index eaac3621d..98cbacb97 100644 --- a/nac3core/src/top_level.rs +++ b/nac3core/src/top_level.rs @@ -57,14 +57,8 @@ pub struct TopLevelContext { pub conetexts: Arc>>>, } -pub fn name_mangling(mut class_name: String, method_name: &str) -> String { - // need to further extend to more name mangling like instantiations of typevar - class_name.push_str(method_name); - class_name -} - -// like adding some info on top of the TopLevelDef for later parsing the class bases, method, -// and function sigatures +// like adding some info on top of the TopLevelDef for +// later parsing the class bases, method, and function sigatures pub struct TopLevelDefInfo { // the definition entry def: TopLevelDef, @@ -82,37 +76,42 @@ pub struct TopLevelComposer { pub primitives: PrimitiveStore, // start as a primitive unifier, will add more top_level defs inside pub unifier: Unifier, - // class method to definition id + // mangled class method name to def_id pub class_method_to_def_id: HashMap, } impl TopLevelComposer { + fn name_mangling(mut class_name: String, method_name: &str) -> String { + class_name.push_str(method_name); + class_name + } + pub fn make_primitives() -> (PrimitiveStore, Unifier) { let mut unifier = Unifier::new(); let int32 = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(0), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let int64 = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(1), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let float = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(2), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let bool = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(3), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let none = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(4), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let primitives = PrimitiveStore { int32, int64, float, bool, none }; crate::typecheck::magic_methods::set_primitives_magic_methods(&primitives, &mut unifier); @@ -212,6 +211,14 @@ impl TopLevelComposer { fields: Default::default(), params: Default::default(), }); + + // add the class to the definition list + def_list.push(TopLevelDefInfo { + def: Self::make_top_level_class_def(class_def_id, resolver.clone()), + // NOTE: Temporarily none here since function body need to be read later + ast: None, + ty, + }); // parse class def body and register class methods into the def list // module's symbol resolver would not know the name of the class methods, @@ -219,7 +226,7 @@ impl TopLevelComposer { // by using the field `class_method_to_def_id` for b in body { if let ast::StmtKind::FunctionDef { name, .. } = &b.node { - let fun_name = name_mangling(class_name.clone(), name); + let fun_name = Self::name_mangling(class_name.clone(), name); let def_id = def_list.len(); // add to unifier @@ -240,19 +247,14 @@ impl TopLevelComposer { }); // class method, do not let the symbol manager manage it, use our own map - // FIXME: maybe not do name magling, use map to map instead - self.class_method_to_def_id.insert( - fun_name, - DefinitionId(def_id) - ); + self.class_method_to_def_id.insert(fun_name, DefinitionId(def_id)); // if it is the contructor, special handling is needed. In the above // handling, we still add __init__ function to the class method if name == "__init__" { + // FIXME: how can this later be fetched? def_list.push(TopLevelDefInfo { - def: TopLevelDef::Initializer { - class_id: DefinitionId(class_def_id), - }, + def: TopLevelDef::Initializer { class_id: DefinitionId(class_def_id) }, // arbitary picked one for the constructor ty: self.primitives.none, // it is inside the class def body statments, so None @@ -262,13 +264,10 @@ impl TopLevelComposer { } } - // add the class to the definition list - def_list.push(TopLevelDefInfo { - def: Self::make_top_level_class_def(class_def_id, resolver), - ast: Some(ast), - ty, - }); - + // move the ast to the entry of the class in the def_list + def_list.get_mut(class_def_id).unwrap().ast = Some(ast); + + // return Ok((class_name, DefinitionId(class_def_id), ty)) }, @@ -313,28 +312,28 @@ impl TopLevelComposer { .. } => { // get the mutable reference of the entry in the definition list, get the `TopLevelDef` - let (_, + let ( ancestors, fields, methods, type_vars, resolver, ) = if let TopLevelDef::Class { - object_id, + object_id: _, ancestors, fields, methods, type_vars, resolver: Some(resolver) } = &mut d.def { - (object_id, ancestors, fields, methods, type_vars, resolver.lock()) + (ancestors, fields, methods, type_vars, resolver.lock()) } else { unreachable!() }; // try to get mutable reference of the entry in the unification table, get the `TypeEnum` let (params, fields ) = if let TypeEnum::TObj { - // FIXME: this params is immutable, even if this is mutable, what + // FIXME: this params is immutable, and what // should the key be, get the original typevar's var_id? params, fields, diff --git a/nac3core/src/typecheck/type_inferencer/test.rs b/nac3core/src/typecheck/type_inferencer/test.rs index ee65dbe3e..210129528 100644 --- a/nac3core/src/typecheck/type_inferencer/test.rs +++ b/nac3core/src/typecheck/type_inferencer/test.rs @@ -51,27 +51,27 @@ impl TestEnvironment { let int32 = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(0), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let int64 = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(1), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let float = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(2), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let bool = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(3), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let none = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(4), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let primitives = PrimitiveStore { int32, int64, float, bool, none }; set_primitives_magic_methods(&primitives, &mut unifier); @@ -123,27 +123,27 @@ impl TestEnvironment { let int32 = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(0), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let int64 = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(1), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let float = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(2), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let bool = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(3), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let none = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(4), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }); identifier_mapping.insert("None".into(), none); for i in 0..5 { @@ -164,7 +164,7 @@ impl TestEnvironment { let foo_ty = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(5), fields: [("a".into(), v0)].iter().cloned().collect::>().into(), - params: [(id, v0)].iter().cloned().collect(), + params: [(id, v0)].iter().cloned().collect::>().into(), }); top_level_defs.push(RwLock::new(TopLevelDef::Class { object_id: DefinitionId(5), diff --git a/nac3core/src/typecheck/typedef/mod.rs b/nac3core/src/typecheck/typedef/mod.rs index 5126d8429..979213add 100644 --- a/nac3core/src/typecheck/typedef/mod.rs +++ b/nac3core/src/typecheck/typedef/mod.rs @@ -68,7 +68,7 @@ pub enum TypeEnum { TObj { obj_id: DefinitionId, fields: RefCell>, - params: VarMap, + params: RefCell, }, TVirtual { ty: Type, @@ -216,6 +216,7 @@ impl Unifier { } } TypeEnum::TObj { params, .. } => { + let params = params.borrow(); let (keys, params): (Vec<&u32>, Vec<&Type>) = params.iter().unzip(); let params = params .into_iter() @@ -253,7 +254,7 @@ impl Unifier { TList { ty } => self.is_concrete(*ty, allowed_typevars), TTuple { ty } => ty.iter().all(|ty| self.is_concrete(*ty, allowed_typevars)), TObj { params: vars, .. } => { - vars.values().all(|ty| self.is_concrete(*ty, allowed_typevars)) + vars.borrow().values().all(|ty| self.is_concrete(*ty, allowed_typevars)) } // functions are instantiated for each call sites, so the function type can contain // type variables. @@ -437,7 +438,7 @@ impl Unifier { if id1 != id2 { return Err(format!("Cannot unify objects with ID {} and {}", id1.0, id2.0)); } - for (x, y) in zip(params1.values(), params2.values()) { + for (x, y) in zip(params1.borrow().values(), params2.borrow().values()) { self.unify(*x, *y)?; } self.set_a_to_b(a, b); @@ -573,6 +574,7 @@ impl Unifier { } TypeEnum::TObj { obj_id, params, .. } => { let name = obj_to_name(obj_id.0); + let params = params.borrow(); if !params.is_empty() { let mut params = params.values().map(|v| self.stringify(*v, obj_to_name, var_to_name)); @@ -679,6 +681,7 @@ impl Unifier { // If the mapping does not contain any type variables in the // parameter list, we don't need to substitute the fields. // This is also used to prevent infinite substitution... + let params = params.borrow(); let need_subst = params.values().any(|v| { let ty = self.unification_table.probe_value(*v); if let TypeEnum::TVar { id, .. } = ty.as_ref() { @@ -693,7 +696,7 @@ impl Unifier { let fields = self .subst_map(&fields.borrow(), mapping) .unwrap_or_else(|| fields.borrow().clone()); - Some(self.add_ty(TypeEnum::TObj { obj_id, params, fields: fields.into() })) + Some(self.add_ty(TypeEnum::TObj { obj_id, params: params.into(), fields: fields.into() })) } else { None } @@ -776,7 +779,7 @@ impl Unifier { self.occur_check(a, *ty)?; } TypeEnum::TObj { params: map, .. } => { - for t in map.values() { + for t in map.borrow().values() { self.occur_check(a, *t)?; } } diff --git a/nac3core/src/typecheck/typedef/test.rs b/nac3core/src/typecheck/typedef/test.rs index 0e4a32f8b..d782c14fa 100644 --- a/nac3core/src/typecheck/typedef/test.rs +++ b/nac3core/src/typecheck/typedef/test.rs @@ -43,7 +43,7 @@ impl Unifier { ( TypeEnum::TObj { obj_id: id1, params: params1, .. }, TypeEnum::TObj { obj_id: id2, params: params2, .. }, - ) => id1 == id2 && self.map_eq(params1, params2), + ) => id1 == id2 && self.map_eq(¶ms1.borrow(), ¶ms2.borrow()), // TCall and TFunc are not yet implemented _ => false, } @@ -80,7 +80,7 @@ impl TestEnvironment { unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(0), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }), ); type_mapping.insert( @@ -88,7 +88,7 @@ impl TestEnvironment { unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(1), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }), ); type_mapping.insert( @@ -96,7 +96,7 @@ impl TestEnvironment { unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(2), fields: HashMap::new().into(), - params: HashMap::new(), + params: HashMap::new().into(), }), ); let (v0, id) = unifier.get_fresh_var(); @@ -105,7 +105,7 @@ impl TestEnvironment { unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(3), fields: [("a".into(), v0)].iter().cloned().collect::>().into(), - params: [(id, v0)].iter().cloned().collect(), + params: [(id, v0)].iter().cloned().collect::>().into(), }), ); @@ -164,6 +164,7 @@ impl TestEnvironment { let mut ty = *self.type_mapping.get(x).unwrap(); let te = self.unifier.get_ty(ty); if let TypeEnum::TObj { params, .. } = &*te.as_ref() { + let params = params.borrow(); if !params.is_empty() { assert!(&s[0..1] == "["); let mut p = Vec::new(); @@ -340,7 +341,7 @@ fn test_virtual() { .cloned() .collect::>() .into(), - params: HashMap::new(), + params: HashMap::new().into(), }); let v0 = env.unifier.get_fresh_var().0; let v1 = env.unifier.get_fresh_var().0;