From ce40a46f8a44f3d095e236e7773790e097b6c048 Mon Sep 17 00:00:00 2001 From: abdul124 Date: Thu, 16 Jan 2025 10:54:07 +0800 Subject: [PATCH] [core] add module type --- nac3core/src/codegen/concrete_type.rs | 13 ++ nac3core/src/typecheck/type_inferencer/mod.rs | 137 ++++++++++-------- nac3core/src/typecheck/typedef/mod.rs | 33 ++++- 3 files changed, 118 insertions(+), 65 deletions(-) diff --git a/nac3core/src/codegen/concrete_type.rs b/nac3core/src/codegen/concrete_type.rs index d5c1fc38..f0c92ed8 100644 --- a/nac3core/src/codegen/concrete_type.rs +++ b/nac3core/src/codegen/concrete_type.rs @@ -205,6 +205,19 @@ impl ConcreteTypeStore { }) .collect(), }, + TypeEnum::TModule { module_id, attributes } => ConcreteTypeEnum::TModule { + module_id: *module_id, + methods: attributes + .iter() + .filter_map(|(name, ty)| match &*unifier.get_ty(ty.0) { + TypeEnum::TFunc(..) | TypeEnum::TObj { .. } => None, + _ => Some(( + *name, + (self.from_unifier_type(unifier, primitives, ty.0, cache), ty.1), + )), + }) + .collect(), + }, TypeEnum::TVirtual { ty } => ConcreteTypeEnum::TVirtual { ty: self.from_unifier_type(unifier, primitives, *ty, cache), }, diff --git a/nac3core/src/typecheck/type_inferencer/mod.rs b/nac3core/src/typecheck/type_inferencer/mod.rs index a58045be..7ce659f3 100644 --- a/nac3core/src/typecheck/type_inferencer/mod.rs +++ b/nac3core/src/typecheck/type_inferencer/mod.rs @@ -2008,72 +2008,90 @@ impl Inferencer<'_> { ctx: ExprContext, ) -> InferenceResult { let ty = value.custom.unwrap(); - if let TypeEnum::TObj { obj_id, fields, .. } = &*self.unifier.get_ty(ty) { - // just a fast path - match (fields.get(&attr), ctx == ExprContext::Store) { - (Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty), - (Some((ty, false)), true) => report_type_error( - TypeErrorKind::MutationError(RecordKey::Str(attr), *ty), - Some(value.location), - self.unifier, - ), - (None, mutable) => { - // Check whether it is a class attribute - let defs = self.top_level.definitions.read(); - let result = { - if let TopLevelDef::Class { attributes, .. } = &*defs[obj_id.0].read() { - attributes.iter().find_map(|f| { - if f.0 == attr { - return Some(f.1); - } - None - }) - } else { - None - } - }; - match result { - Some(res) if !mutable => Ok(res), - Some(_) => report_error( - &format!("Class Attribute `{attr}` is immutable"), - value.location, - ), - None => report_type_error( - TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty), - Some(value.location), - self.unifier, - ), - } - } - } - } else if let TypeEnum::TFunc(sign) = &*self.unifier.get_ty(ty) { - // Access Class Attributes of classes with __init__ function using Class names e.g. Foo.ATTR1 - let result = { - self.top_level.definitions.read().iter().find_map(|def| { - if let Some(rear_guard) = def.try_read() { - if let TopLevelDef::Class { name, attributes, .. } = &*rear_guard { - if name.to_string() == self.unifier.stringify(sign.ret) { - return attributes.iter().find_map(|f| { + match &*self.unifier.get_ty(ty) { + TypeEnum::TObj { obj_id, fields, .. } => { + // just a fast path + match (fields.get(&attr), ctx == ExprContext::Store) { + (Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty), + (Some((ty, false)), true) => report_type_error( + TypeErrorKind::MutationError(RecordKey::Str(attr), *ty), + Some(value.location), + self.unifier, + ), + (None, mutable) => { + // Check whether it is a class attribute + let defs = self.top_level.definitions.read(); + let result = { + if let TopLevelDef::Class { attributes, .. } = &*defs[obj_id.0].read() { + attributes.iter().find_map(|f| { if f.0 == attr { - return Some(f.clone().1); + return Some(f.1); } None - }); + }) + } else { + None } + }; + match result { + Some(res) if !mutable => Ok(res), + Some(_) => report_error( + &format!("Class Attribute `{attr}` is immutable"), + value.location, + ), + None => report_type_error( + TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty), + Some(value.location), + self.unifier, + ), } } - None - }) - }; - match result { - Some(f) if ctx != ExprContext::Store => Ok(f), - Some(_) => { - report_error(&format!("Class Attribute `{attr}` is immutable"), value.location) } - None => self.infer_general_attribute(value, attr, ctx), } - } else { - self.infer_general_attribute(value, attr, ctx) + TypeEnum::TFunc(sign) => { + // Access Class Attributes of classes with __init__ function using Class names e.g. Foo.ATTR1 + let result = { + self.top_level.definitions.read().iter().find_map(|def| { + if let Some(rear_guard) = def.try_read() { + if let TopLevelDef::Class { name, attributes, .. } = &*rear_guard { + if name.to_string() == self.unifier.stringify(sign.ret) { + return attributes.iter().find_map(|f| { + if f.0 == attr { + return Some(f.clone().1); + } + None + }); + } + } + } + None + }) + }; + match result { + Some(f) if ctx != ExprContext::Store => Ok(f), + Some(_) => report_error( + &format!("Class Attribute `{attr}` is immutable"), + value.location, + ), + None => self.infer_general_attribute(value, attr, ctx), + } + } + TypeEnum::TModule { attributes, .. } => { + match (attributes.get(&attr), ctx == ExprContext::Load) { + (Some((ty, _)), true) | (Some((ty, false)), false) => Ok(*ty), + (Some((ty, true)), false) => report_type_error( + TypeErrorKind::MutationError(RecordKey::Str(attr), *ty), + Some(value.location), + self.unifier, + ), + (None, _) => report_type_error( + TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty), + Some(value.location), + self.unifier, + ), + } + } + _ => self.infer_general_attribute(value, attr, ctx), } } @@ -2734,8 +2752,7 @@ impl Inferencer<'_> { .read() .iter() .map(|def| match *def.read() { - TopLevelDef::Class { name, .. } - | TopLevelDef::Module { name, .. } => (name, false), + TopLevelDef::Class { name, .. } | TopLevelDef::Module { name, .. } => (name, false), TopLevelDef::Function { simple_name, .. } => (simple_name, false), TopLevelDef::Variable { simple_name, .. } => (simple_name, true), }) diff --git a/nac3core/src/typecheck/typedef/mod.rs b/nac3core/src/typecheck/typedef/mod.rs index e190c4c4..f2f9ed6f 100644 --- a/nac3core/src/typecheck/typedef/mod.rs +++ b/nac3core/src/typecheck/typedef/mod.rs @@ -270,6 +270,19 @@ pub enum TypeEnum { /// A function type. TFunc(FunSignature), + + /// Module Type + TModule { + /// The [`DefinitionId`] of this object type. + module_id: DefinitionId, + + /// The attributes present in this object type. + /// + /// The key of the [Mapping] is the identifier of the field, while the value is a tuple + /// containing the [Type] of the field, and a `bool` indicating whether the field is a + /// variable (as opposed to a function). + attributes: Mapping, + }, } impl TypeEnum { @@ -284,6 +297,7 @@ impl TypeEnum { TypeEnum::TVirtual { .. } => "TVirtual", TypeEnum::TCall { .. } => "TCall", TypeEnum::TFunc { .. } => "TFunc", + TypeEnum::TModule { .. } => "TModule", } } } @@ -593,7 +607,8 @@ impl Unifier { | TLiteral { .. } // functions are instantiated for each call sites, so the function type can contain // type variables. - | TFunc { .. } => true, + | TFunc { .. } + | TModule { .. } => true, TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)), TCall { .. } => false, @@ -1315,10 +1330,12 @@ impl Unifier { || format!("{id}"), |top_level| { let top_level_def = &top_level.definitions.read()[id]; - let TopLevelDef::Class { name, .. } = &*top_level_def.read() else { - unreachable!("expected class definition") + let top_level_def = top_level_def.read(); + let (TopLevelDef::Class { name, .. } | TopLevelDef::Module { name, .. }) = + &*top_level_def + else { + unreachable!("expected module/class definition") }; - name.to_string() }, ) @@ -1446,6 +1463,10 @@ impl Unifier { let ret = self.internal_stringify(signature.ret, obj_to_name, var_to_name, notes); format!("fn[[{params}], {ret}]") } + TypeEnum::TModule { module_id, .. } => { + let name = obj_to_name(module_id.0); + name.to_string() + } } } @@ -1521,7 +1542,9 @@ impl Unifier { // variables, i.e. things like TRecord, TCall should not occur, and we // should be safe to not implement the substitution for those variants. match &*ty { - TypeEnum::TRigidVar { .. } | TypeEnum::TLiteral { .. } => None, + TypeEnum::TRigidVar { .. } | TypeEnum::TLiteral { .. } | TypeEnum::TModule { .. } => { + None + } TypeEnum::TVar { id, .. } => mapping.get(id).copied(), TypeEnum::TTuple { ty, is_vararg_ctx } => { let mut new_ty = Cow::from(ty);