From 279f47f63394df29e651f651dca5ad74409f892e Mon Sep 17 00:00:00 2001 From: pca006132 Date: Sun, 17 Oct 2021 13:02:18 +0800 Subject: [PATCH] nac3core/codegen: avoid sending unifiers Previously, we have to copy types from one unification table to another, and make the table sendable. This requires cloning (processing) the whole table 3 times per function call which is not efficient and uses more memory than required when the unification table is large. We now use a concrete type table to only copy the type we need. This reduces the overhead as we only need to process the unification table for once (when we do the function codegen), and reduces memory usage by a bit (but not noticeable when the unification table is small, i.e. the types are simple). --- nac3artiq/src/lib.rs | 28 ++- nac3core/src/codegen/concrete_type.rs | 277 ++++++++++++++++++++++++++ nac3core/src/codegen/expr.rs | 64 +++--- nac3core/src/codegen/mod.rs | 58 ++++-- nac3core/src/codegen/test.rs | 42 +++- nac3core/src/symbol_resolver.rs | 2 +- nac3core/src/typecheck/typedef/mod.rs | 72 ------- nac3standalone/src/main.rs | 23 ++- 8 files changed, 405 insertions(+), 161 deletions(-) create mode 100644 nac3core/src/codegen/concrete_type.rs diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index edead5425..8d9d1e12b 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -19,7 +19,10 @@ use rustpython_parser::{ use parking_lot::{Mutex, RwLock}; use nac3core::{ - codegen::{CodeGenTask, DefaultCodeGenerator, WithCall, WorkerRegistry}, + codegen::{ + concrete_type::ConcreteTypeStore, CodeGenTask, DefaultCodeGenerator, WithCall, + WorkerRegistry, + }, symbol_resolver::SymbolResolver, toplevel::{composer::TopLevelComposer, DefinitionId, GenCall, TopLevelContext, TopLevelDef}, typecheck::typedef::{FunSignature, FuncArg}, @@ -354,6 +357,21 @@ impl Nac3 { ) .unwrap(); + let signature = FunSignature { + args: vec![], + ret: self.primitive.none, + vars: HashMap::new(), + }; + let mut store = ConcreteTypeStore::new(); + let mut cache = HashMap::new(); + let signature = store.from_signature( + &mut self.composer.unifier, + &self.primitive, + &signature, + &mut cache, + ); + let signature = store.add_cty(signature); + self.composer.start_analysis(true).unwrap(); self.top_level = Some(Arc::new(self.composer.make_top_level_context())); let top_level = self.top_level.as_ref().unwrap(); @@ -373,18 +391,14 @@ impl Nac3 { } }; - let signature = FunSignature { - args: vec![], - ret: self.primitive.none, - vars: HashMap::new(), - }; let task = CodeGenTask { subst: Default::default(), symbol_name: "__modinit__".to_string(), body: instance.body, signature, resolver, - unifier: top_level.unifiers.read()[instance.unifier_id].clone(), + store, + unifier_index: instance.unifier_id, calls: instance.calls, }; let isa = self.isa; diff --git a/nac3core/src/codegen/concrete_type.rs b/nac3core/src/codegen/concrete_type.rs new file mode 100644 index 000000000..347956aff --- /dev/null +++ b/nac3core/src/codegen/concrete_type.rs @@ -0,0 +1,277 @@ +use crate::{ + symbol_resolver::SymbolValue, + toplevel::DefinitionId, + typecheck::{ + type_inferencer::PrimitiveStore, + typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier}, + }, +}; + +use rustpython_parser::ast::StrRef; +use std::collections::HashMap; + +pub struct ConcreteTypeStore { + store: Vec, +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct ConcreteType(usize); + +#[derive(Clone, Debug)] +pub struct ConcreteFuncArg { + pub name: StrRef, + pub ty: ConcreteType, + pub default_value: Option, +} + +#[derive(Clone, Debug)] +pub enum Primitive { + Int32, + Int64, + Float, + Bool, + None, +} + +#[derive(Debug)] +pub enum ConcreteTypeEnum { + TPrimitive(Primitive), + TTuple { + ty: Vec, + }, + TList { + ty: ConcreteType, + }, + TObj { + obj_id: DefinitionId, + fields: HashMap, + params: HashMap, + }, + TVirtual { + ty: ConcreteType, + }, + TFunc { + args: Vec, + ret: ConcreteType, + vars: HashMap, + }, +} + +impl ConcreteTypeStore { + pub fn new() -> ConcreteTypeStore { + ConcreteTypeStore { + store: vec![ + ConcreteTypeEnum::TPrimitive(Primitive::Int32), + ConcreteTypeEnum::TPrimitive(Primitive::Int64), + ConcreteTypeEnum::TPrimitive(Primitive::Float), + ConcreteTypeEnum::TPrimitive(Primitive::Bool), + ConcreteTypeEnum::TPrimitive(Primitive::None), + ], + } + } + + pub fn get(&self, cty: ConcreteType) -> &ConcreteTypeEnum { + &self.store[cty.0] + } + + pub fn from_signature( + &mut self, + unifier: &mut Unifier, + primitives: &PrimitiveStore, + signature: &FunSignature, + cache: &mut HashMap>, + ) -> ConcreteTypeEnum { + ConcreteTypeEnum::TFunc { + args: signature + .args + .iter() + .map(|arg| ConcreteFuncArg { + name: arg.name, + ty: self.from_unifier_type(unifier, primitives, arg.ty, cache), + default_value: arg.default_value.clone(), + }) + .collect(), + ret: self.from_unifier_type(unifier, primitives, signature.ret, cache), + vars: signature + .vars + .iter() + .map(|(id, ty)| (*id, self.from_unifier_type(unifier, primitives, *ty, cache))) + .collect(), + } + } + + pub fn from_unifier_type( + &mut self, + unifier: &mut Unifier, + primitives: &PrimitiveStore, + ty: Type, + cache: &mut HashMap>, + ) -> ConcreteType { + let ty = unifier.get_representative(ty); + if unifier.unioned(ty, primitives.int32) { + ConcreteType(0) + } else if unifier.unioned(ty, primitives.int64) { + ConcreteType(1) + } else if unifier.unioned(ty, primitives.float) { + ConcreteType(2) + } else if unifier.unioned(ty, primitives.bool) { + ConcreteType(3) + } else if unifier.unioned(ty, primitives.none) { + ConcreteType(4) + } else if let Some(cty) = cache.get(&ty) { + if let Some(cty) = cty { + *cty + } else { + let index = self.store.len(); + // placeholder + self.store.push(ConcreteTypeEnum::TPrimitive(Primitive::Int32)); + let result = ConcreteType(index); + cache.insert(ty, Some(result)); + result + } + } else { + cache.insert(ty, None); + let ty_enum = unifier.get_ty(ty); + let result = match &*ty_enum { + TypeEnum::TTuple { ty } => ConcreteTypeEnum::TTuple { + ty: ty + .iter() + .map(|t| self.from_unifier_type(unifier, primitives, *t, cache)) + .collect(), + }, + TypeEnum::TList { ty } => ConcreteTypeEnum::TList { + ty: self.from_unifier_type(unifier, primitives, *ty, cache), + }, + TypeEnum::TObj { obj_id, fields, params } => ConcreteTypeEnum::TObj { + obj_id: *obj_id, + fields: fields + .borrow() + .iter() + .map(|(name, ty)| { + (*name, self.from_unifier_type(unifier, primitives, *ty, cache)) + }) + .collect(), + params: params + .borrow() + .iter() + .map(|(id, ty)| { + (*id, self.from_unifier_type(unifier, primitives, *ty, cache)) + }) + .collect(), + }, + TypeEnum::TVirtual { ty } => ConcreteTypeEnum::TVirtual { + ty: self.from_unifier_type(unifier, primitives, *ty, cache), + }, + TypeEnum::TFunc(signature) => { + let signature = signature.borrow(); + self.from_signature(unifier, primitives, &*signature, cache) + } + _ => unreachable!(), + }; + let index = if let Some(ConcreteType(index)) = cache.get(&ty).unwrap() { + self.store[*index] = result; + *index + } else { + self.store.push(result); + self.store.len() - 1 + }; + cache.insert(ty, Some(ConcreteType(index))); + ConcreteType(index) + } + } + + pub fn to_unifier_type( + &self, + unifier: &mut Unifier, + primitives: &PrimitiveStore, + cty: ConcreteType, + cache: &mut HashMap>, + ) -> Type { + if let Some(ty) = cache.get_mut(&cty) { + return if let Some(ty) = ty { + *ty + } else { + *ty = Some(unifier.get_fresh_var().0); + ty.unwrap() + }; + } + cache.insert(cty, None); + let result = match &self.store[cty.0] { + ConcreteTypeEnum::TPrimitive(primitive) => { + let ty = match primitive { + Primitive::Int32 => primitives.int32, + Primitive::Int64 => primitives.int64, + Primitive::Float => primitives.float, + Primitive::Bool => primitives.bool, + Primitive::None => primitives.none, + }; + *cache.get_mut(&cty).unwrap() = Some(ty); + return ty; + } + ConcreteTypeEnum::TTuple { ty } => TypeEnum::TTuple { + ty: ty + .iter() + .map(|cty| self.to_unifier_type(unifier, primitives, *cty, cache)) + .collect(), + }, + ConcreteTypeEnum::TList { ty } => { + TypeEnum::TList { ty: self.to_unifier_type(unifier, primitives, *ty, cache) } + } + ConcreteTypeEnum::TVirtual { ty } => { + TypeEnum::TVirtual { ty: self.to_unifier_type(unifier, primitives, *ty, cache) } + } + ConcreteTypeEnum::TObj { obj_id, fields, params } => TypeEnum::TObj { + obj_id: *obj_id, + fields: fields + .iter() + .map(|(name, cty)| { + (*name, self.to_unifier_type(unifier, primitives, *cty, cache)) + }) + .collect::>() + .into(), + params: params + .iter() + .map(|(id, cty)| (*id, self.to_unifier_type(unifier, primitives, *cty, cache))) + .collect::>() + .into(), + }, + ConcreteTypeEnum::TFunc { args, ret, vars } => TypeEnum::TFunc( + FunSignature { + args: args + .iter() + .map(|arg| FuncArg { + name: arg.name, + ty: self.to_unifier_type(unifier, primitives, arg.ty, cache), + default_value: arg.default_value.clone(), + }) + .collect(), + ret: self.to_unifier_type(unifier, primitives, *ret, cache), + vars: vars + .iter() + .map(|(id, cty)| { + (*id, self.to_unifier_type(unifier, primitives, *cty, cache)) + }) + .collect::>(), + } + .into(), + ), + }; + let result = unifier.add_ty(result); + if let Some(ty) = cache.get(&cty).unwrap() { + unifier.unify(*ty, result).unwrap(); + } + cache.insert(cty, Some(result)); + result + } + + pub fn add_cty(&mut self, cty: ConcreteTypeEnum) -> ConcreteType { + self.store.push(cty); + ConcreteType(self.store.len() - 1) + } +} + +impl Default for ConcreteTypeStore { + fn default() -> Self { + Self::new() + } +} diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index 7f319fd9a..1dec50f0b 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -1,10 +1,13 @@ use std::{collections::HashMap, convert::TryInto, iter::once}; use crate::{ - codegen::{get_llvm_type, CodeGenContext, CodeGenTask}, + codegen::{ + concrete_type::{ConcreteFuncArg, ConcreteTypeEnum, ConcreteTypeStore}, + get_llvm_type, CodeGenContext, CodeGenTask, + }, symbol_resolver::SymbolValue, toplevel::{DefinitionId, TopLevelDef}, - typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier}, + typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum}, }; use inkwell::{ types::{BasicType, BasicTypeEnum}, @@ -265,20 +268,9 @@ pub fn gen_func_instance<'ctx, 'a>( instance_to_symbol.insert(key, symbol.clone()); let key = ctx.get_subst_key(obj.map(|a| a.0), sign, Some(var_id)); let instance = instance_to_stmt.get(&key).unwrap(); - let unifiers = ctx.top_level.unifiers.read(); - let (unifier, primitives) = &unifiers[instance.unifier_id]; - let mut unifier = Unifier::from_shared_unifier(unifier); - let mut type_cache = [ - (ctx.primitives.int32, primitives.int32), - (ctx.primitives.int64, primitives.int64), - (ctx.primitives.float, primitives.float), - (ctx.primitives.bool, primitives.bool), - (ctx.primitives.none, primitives.none), - ] - .iter() - .map(|(a, b)| (ctx.unifier.get_representative(*a), unifier.get_representative(*b))) - .collect(); + let mut store = ConcreteTypeStore::new(); + let mut cache = HashMap::new(); let subst = sign .vars @@ -286,38 +278,27 @@ pub fn gen_func_instance<'ctx, 'a>( .map(|(id, ty)| { ( *instance.subst.get(id).unwrap(), - unifier.copy_from(&mut ctx.unifier, *ty, &mut type_cache), + store.from_unifier_type(&mut ctx.unifier, &ctx.primitives, *ty, &mut cache), ) }) .collect(); - let mut signature = FunSignature { - args: sign - .args - .iter() - .map(|arg| FuncArg { - name: arg.name, - ty: unifier.copy_from(&mut ctx.unifier, arg.ty, &mut type_cache), - default_value: arg.default_value.clone(), - }) - .collect(), - ret: unifier.copy_from(&mut ctx.unifier, sign.ret, &mut type_cache), - vars: sign - .vars - .iter() - .map(|(id, ty)| { - (*id, unifier.copy_from(&mut ctx.unifier, *ty, &mut type_cache)) - }) - .collect(), - }; + let mut signature = + store.from_signature(&mut ctx.unifier, &ctx.primitives, sign, &mut cache); if let Some(obj) = &obj { - signature - .args - .insert(0, FuncArg { name: "self".into(), ty: obj.0, default_value: None }); + let zelf = + store.from_unifier_type(&mut ctx.unifier, &ctx.primitives, obj.0, &mut cache); + if let ConcreteTypeEnum::TFunc { args, .. } = &mut signature { + args.insert( + 0, + ConcreteFuncArg { name: "self".into(), ty: zelf, default_value: None }, + ) + } else { + unreachable!() + } } - - let unifier = (unifier.get_shared_unifier(), *primitives); + let signature = store.add_cty(signature); ctx.registry.add_task(CodeGenTask { symbol_name: symbol.clone(), @@ -326,7 +307,8 @@ pub fn gen_func_instance<'ctx, 'a>( calls: instance.calls.clone(), subst, signature, - unifier, + store, + unifier_index: instance.unifier_id, }); symbol }) diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index 34125efc9..5db7c6f65 100644 --- a/nac3core/src/codegen/mod.rs +++ b/nac3core/src/codegen/mod.rs @@ -3,7 +3,7 @@ use crate::{ toplevel::{TopLevelContext, TopLevelDef}, typecheck::{ type_inferencer::{CodeLocation, PrimitiveStore}, - typedef::{CallId, FunSignature, SharedUnifier, Type, TypeEnum, Unifier}, + typedef::{CallId, FuncArg, Type, TypeEnum, Unifier}, }, }; use crossbeam::channel::{unbounded, Receiver, Sender}; @@ -27,6 +27,7 @@ use std::sync::{ }; use std::thread; +pub mod concrete_type; mod expr; mod generator; mod stmt; @@ -34,6 +35,7 @@ mod stmt; #[cfg(test)] mod test; +use concrete_type::{ConcreteType, ConcreteTypeEnum, ConcreteTypeStore}; pub use generator::{CodeGenerator, DefaultCodeGenerator}; pub struct CodeGenContext<'ctx, 'a> { @@ -198,12 +200,13 @@ impl WorkerRegistry { } pub struct CodeGenTask { - pub subst: Vec<(Type, Type)>, + pub subst: Vec<(Type, ConcreteType)>, + pub store: ConcreteTypeStore, pub symbol_name: String, - pub signature: FunSignature, + pub signature: ConcreteType, pub body: Arc>>>, pub calls: Arc>, - pub unifier: (SharedUnifier, PrimitiveStore), + pub unifier_index: usize, pub resolver: Arc, } @@ -218,7 +221,8 @@ fn get_llvm_type<'ctx>( // we assume the type cache should already contain primitive types, // and they should be passed by value instead of passing as pointer. type_cache.get(&unifier.get_representative(ty)).cloned().unwrap_or_else(|| { - match &*unifier.get_ty(ty) { + let ty = unifier.get_ty(ty); + match &*ty { TObj { obj_id, fields, .. } => { // a struct with fields in the order of declaration let top_level_defs = top_level.definitions.read(); @@ -252,7 +256,7 @@ fn get_llvm_type<'ctx>( ctx.struct_type(&fields, false).ptr_type(AddressSpace::Generic).into() } TVirtual { .. } => unimplemented!(), - _ => unreachable!(), + _ => unreachable!("{}", ty.get_type_name()), } }) } @@ -267,14 +271,16 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>( top_level_ctx: Arc, ) -> (Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>) { let (mut unifier, primitives) = { - let (unifier, primitives) = task.unifier; - (Unifier::from_shared_unifier(&unifier), primitives) + let (unifier, primitives) = &top_level_ctx.unifiers.read()[task.unifier_index]; + (Unifier::from_shared_unifier(unifier), *primitives) }; + let mut cache = HashMap::new(); for (a, b) in task.subst.iter() { // this should be unification between variables and concrete types // and should not cause any problem... - unifier.unify(*a, *b).unwrap(); + let b = task.store.to_unifier_type(&mut unifier, &primitives, *b, &mut cache); + unifier.unify(*a, b).unwrap(); } // rebuild primitive store with unique representatives @@ -296,26 +302,34 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>( .cloned() .collect(); - let params = task - .signature - .args + let (args, ret) = if let ConcreteTypeEnum::TFunc { args, ret, .. } = + task.store.get(task.signature) + { + ( + args.iter() + .map(|arg| FuncArg { + name: arg.name, + ty: task.store.to_unifier_type(&mut unifier, &primitives, arg.ty, &mut cache), + default_value: arg.default_value.clone(), + }) + .collect_vec(), + task.store.to_unifier_type(&mut unifier, &primitives, *ret, &mut cache), + ) + } else { + unreachable!() + }; + let params = args .iter() .map(|arg| { get_llvm_type(context, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, arg.ty) }) .collect_vec(); - let fn_type = if unifier.unioned(task.signature.ret, primitives.none) { + let fn_type = if unifier.unioned(ret, primitives.none) { context.void_type().fn_type(¶ms, false) } else { - get_llvm_type( - context, - &mut unifier, - top_level_ctx.as_ref(), - &mut type_cache, - task.signature.ret, - ) - .fn_type(¶ms, false) + get_llvm_type(context, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, ret) + .fn_type(¶ms, false) }; let symbol = &task.symbol_name; @@ -335,7 +349,7 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>( let body_bb = context.append_basic_block(fn_val, "body"); let mut var_assignment = HashMap::new(); - for (n, arg) in task.signature.args.iter().enumerate() { + for (n, arg) in args.iter().enumerate() { let param = fn_val.get_nth_param(n as u32).unwrap(); let alloca = builder.build_alloca( get_llvm_type(context, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, arg.ty), diff --git a/nac3core/src/codegen/test.rs b/nac3core/src/codegen/test.rs index 9682c69d9..c31fda8a4 100644 --- a/nac3core/src/codegen/test.rs +++ b/nac3core/src/codegen/test.rs @@ -1,5 +1,8 @@ use crate::{ - codegen::{CodeGenTask, WithCall, WorkerRegistry, CodeGenContext, DefaultCodeGenerator}, + codegen::{ + concrete_type::ConcreteTypeStore, CodeGenContext, CodeGenTask, DefaultCodeGenerator, + WithCall, WorkerRegistry, + }, location::Location, symbol_resolver::SymbolResolver, toplevel::{ @@ -34,11 +37,21 @@ impl Resolver { } impl SymbolResolver for Resolver { - fn get_symbol_type(&self, _: &mut Unifier, _: &[Arc>], _: &PrimitiveStore, str: StrRef) -> Option { + fn get_symbol_type( + &self, + _: &mut Unifier, + _: &[Arc>], + _: &PrimitiveStore, + str: StrRef, + ) -> Option { self.id_to_type.get(&str).cloned() } - fn get_symbol_value<'ctx, 'a>(&self, _: StrRef, _: &mut CodeGenContext<'ctx, 'a>) -> Option> { + fn get_symbol_value<'ctx, 'a>( + &self, + _: StrRef, + _: &mut CodeGenContext<'ctx, 'a>, + ) -> Option> { unimplemented!() } @@ -82,6 +95,11 @@ fn test_primitives() { vars: HashMap::new(), }; + let mut store = ConcreteTypeStore::new(); + let mut cache = HashMap::new(); + let signature = store.from_signature(&mut unifier, &primitives, &signature, &mut cache); + let signature = store.add_cty(signature); + let mut function_data = FunctionData { resolver: resolver.clone(), bound_variables: Vec::new(), @@ -116,15 +134,14 @@ fn test_primitives() { personality_symbol: None, }); - let unifier = (unifier.get_shared_unifier(), primitives); - let task = CodeGenTask { subst: Default::default(), symbol_name: "testing".into(), body: Arc::new(statements), - resolver, - unifier, + unifier_index: 0, calls: Arc::new(calls), + resolver, + store, signature, }; let f = Arc::new(WithCall::new(Box::new(|module| { @@ -216,6 +233,10 @@ fn test_simple_call() { vars: HashMap::new(), }; let fun_ty = unifier.add_ty(TypeEnum::TFunc(RefCell::new(signature.clone()))); + let mut store = ConcreteTypeStore::new(); + let mut cache = HashMap::new(); + let signature = store.from_signature(&mut unifier, &primitives, &signature, &mut cache); + let signature = store.add_cty(signature); let foo_id = top_level.definitions.read().len(); top_level.definitions.write().push(Arc::new(RwLock::new(TopLevelDef::Function { @@ -305,16 +326,15 @@ fn test_simple_call() { personality_symbol: None, }); - let unifier = (unifier.get_shared_unifier(), primitives); - let task = CodeGenTask { subst: Default::default(), symbol_name: "testing".to_string(), body: Arc::new(statements_1), - resolver, - unifier, calls: Arc::new(calls1), + unifier_index: 0, + resolver, signature, + store, }; let f = Arc::new(WithCall::new(Box::new(|module| { let expected = indoc! {" diff --git a/nac3core/src/symbol_resolver.rs b/nac3core/src/symbol_resolver.rs index 958757afe..ac0bbaa77 100644 --- a/nac3core/src/symbol_resolver.rs +++ b/nac3core/src/symbol_resolver.rs @@ -13,7 +13,7 @@ use parking_lot::RwLock; use rustpython_parser::ast::{Expr, StrRef}; use inkwell::values::BasicValueEnum; -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Debug)] pub enum SymbolValue { I32(i32), I64(i64), diff --git a/nac3core/src/typecheck/typedef/mod.rs b/nac3core/src/typecheck/typedef/mod.rs index 0391fa7b5..f12980d26 100644 --- a/nac3core/src/typecheck/typedef/mod.rs +++ b/nac3core/src/typecheck/typedef/mod.rs @@ -125,78 +125,6 @@ impl Unifier { } } - // copy concrete type from a type in another unifier - // note that we are constructing a new type this way - // this can handle recursive types - pub fn copy_from( - &mut self, - unifier: &mut Unifier, - ty: Type, - type_cache: &mut HashMap, - ) -> Type { - let representative = unifier.get_representative(ty); - type_cache.get(&representative).cloned().unwrap_or_else(|| { - // put in a placeholder first to handle possible recursive type - let placeholder = self.get_fresh_var().0; - type_cache.insert(representative, placeholder); - let ty = match &*self.get_ty(ty) { - TypeEnum::TVar { .. } | TypeEnum::TRigidVar { .. } | TypeEnum::TCall(..) => { - unreachable!() - } - TypeEnum::TObj { obj_id, fields, params } => TypeEnum::TObj { - obj_id: *obj_id, - fields: RefCell::new( - fields - .borrow() - .iter() - .map(|(name, ty)| (*name, self.copy_from(unifier, *ty, type_cache))) - .collect(), - ), - params: RefCell::new( - params - .borrow() - .iter() - .map(|(id, ty)| (*id, self.copy_from(unifier, *ty, type_cache))) - .collect(), - ), - }, - TypeEnum::TList { ty } => { - TypeEnum::TList { ty: self.copy_from(unifier, *ty, type_cache) } - } - TypeEnum::TFunc(fun) => { - let fun = fun.borrow(); - TypeEnum::TFunc(RefCell::new(FunSignature { - args: fun - .args - .iter() - .map(|arg| FuncArg { - name: arg.name, - ty: self.copy_from(unifier, arg.ty, type_cache), - default_value: arg.default_value.clone(), - }) - .collect(), - ret: self.copy_from(unifier, fun.ret, type_cache), - vars: fun - .vars - .iter() - .map(|(id, ty)| (*id, self.copy_from(unifier, *ty, type_cache))) - .collect(), - })) - } - TypeEnum::TTuple { ty } => TypeEnum::TTuple { - ty: ty.iter().map(|ty| self.copy_from(unifier, *ty, type_cache)).collect(), - }, - TypeEnum::TVirtual { ty } => { - TypeEnum::TVirtual { ty: self.copy_from(unifier, *ty, type_cache) } - } - }; - let ty = self.add_ty(ty); - self.unify_impl(placeholder, ty, false).unwrap(); - type_cache.insert(representative, ty); - ty - }) - } - /// Determine if the two types are the same pub fn unioned(&mut self, a: Type, b: Type) -> bool { self.unification_table.unioned(a, b) diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index 83839edcf..4fc9b8d51 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -10,7 +10,10 @@ use std::fs; use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime}; use nac3core::{ - codegen::{CodeGenTask, DefaultCodeGenerator, WithCall, WorkerRegistry}, + codegen::{ + concrete_type::ConcreteTypeStore, CodeGenTask, DefaultCodeGenerator, WithCall, + WorkerRegistry, + }, symbol_resolver::SymbolResolver, toplevel::{composer::TopLevelComposer, TopLevelDef}, typecheck::typedef::FunSignature, @@ -73,6 +76,16 @@ fn main() { } } + let signature = FunSignature { + args: vec![], + ret: primitive.int32, + vars: HashMap::new(), + }; + let mut store = ConcreteTypeStore::new(); + let mut cache = HashMap::new(); + let signature = store.from_signature(&mut composer.unifier, &primitive, &signature, &mut cache); + let signature = store.add_cty(signature); + composer.start_analysis(true).unwrap(); let analysis_time = SystemTime::now(); println!( @@ -100,11 +113,6 @@ fn main() { unreachable!() } }; - let signature = FunSignature { - args: vec![], - ret: primitive.int32, - vars: HashMap::new(), - }; let task = CodeGenTask { subst: Default::default(), @@ -112,7 +120,8 @@ fn main() { body: instance.body, signature, resolver, - unifier: top_level.unifiers.read()[instance.unifier_id].clone(), + store, + unifier_index: instance.unifier_id, calls: instance.calls, }; let f = Arc::new(WithCall::new(Box::new(move |module| {