From c3aa5e718211ee1a88d7ebc51798280e8321e387 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Sun, 28 Aug 2022 16:16:54 +0100 Subject: [PATCH] Add monomorph cache prototype. --- .../declaration_engine/declaration_engine.rs | 106 ++++++++++++++++-- de/src/language/typed/typed_declaration.rs | 6 +- de/src/namespace/function_signature.rs | 12 ++ .../semantic_analysis/inference/expression.rs | 40 ++----- de/src/type_system/trait_constraint.rs | 2 +- de/src/type_system/type_argument.rs | 8 +- de/src/type_system/type_engine.rs | 39 +++---- de/src/type_system/type_id.rs | 2 +- de/src/type_system/type_parameter.rs | 9 +- de/tests/harness.rs | 54 +++++++++ 10 files changed, 202 insertions(+), 76 deletions(-) diff --git a/de/src/declaration_engine/declaration_engine.rs b/de/src/declaration_engine/declaration_engine.rs index bc08103..294b2a5 100644 --- a/de/src/declaration_engine/declaration_engine.rs +++ b/de/src/declaration_engine/declaration_engine.rs @@ -6,6 +6,8 @@ use crate::{ TypedFunctionDeclaration, TypedStructDeclaration, TypedTraitDeclaration, TypedTraitFn, TypedTraitImpl, }, + namespace::namespace::Namespace, + type_system::type_argument::TypeArgument, types::pretty_print::PrettyPrint, }; @@ -78,14 +80,54 @@ impl DeclarationEngine { self.slab.get(index).expect_function() } - // TODO(joao): consider only adding unique copies, if you get a non unique copy, throw it away - pub(crate) fn add_monomorphized_function_copy( + pub(crate) fn get_or_create_monomorphized_fn( &mut self, + decl_id: DeclarationId, + type_arguments: &mut Vec, + namespace: &Namespace, + ) -> Option { + // get the original function declaration + let mut typed_function_declaration = self.get_function(decl_id).unwrap(); + + let cached_fn_decl = self.get_monomorphized_function(decl_id, type_arguments); + if cached_fn_decl.is_some() { + return cached_fn_decl; + } + + // monomorphize the function declaration into a new copy + crate::type_system::type_engine::monomorphize( + &mut typed_function_declaration, + type_arguments, + namespace, + self, + ) + .unwrap(); + + // add the new copy to the declaration engine + let new_id = self.slab.insert(DeclarationWrapper::Function( + typed_function_declaration.clone(), + )); + self.add_monomorphized_copy(decl_id, new_id); + + Some(typed_function_declaration) + } + + pub(crate) fn get_monomorphized_function( + &self, original_id: DeclarationId, - new_copy: TypedFunctionDeclaration, - ) { - let new_id = self.slab.insert(DeclarationWrapper::Function(new_copy)); - self.add_monomorphized_copy(original_id, new_id) + type_arguments: &Vec, + ) -> Option { + for copy in self.get_monomorphized_copies(original_id).iter() { + let monomorphized_fn_decl = match copy { + DeclarationWrapper::Function(fn_decl) => fn_decl, + _ => panic!(), + }; + + if &monomorphized_fn_decl.type_parameters == type_arguments { + return Some(monomorphized_fn_decl.clone()); + } + } + None } pub(crate) fn get_monomorphized_function_copies( @@ -133,14 +175,54 @@ impl DeclarationEngine { self.slab.get(index).expect_struct() } - // TODO(joao): consider only adding unique copies, if you get a non unique copy, throw it away - pub(crate) fn add_monomorphized_struct_copy( + pub(crate) fn get_or_create_monomorphized_struct( &mut self, + decl_id: DeclarationId, + type_arguments: &mut Vec, + namespace: &Namespace, + ) -> Option { + // get the original struct declaration + let mut typed_struct_declaration = self.get_struct(decl_id).unwrap(); + + let cached_struct_decl = self.get_monomorphized_struct(decl_id, type_arguments); + if cached_struct_decl.is_some() { + return cached_struct_decl; + } + + // monomorphize the function declaration into a new copy + crate::type_system::type_engine::monomorphize( + &mut typed_struct_declaration, + type_arguments, + namespace, + self, + ) + .unwrap(); + + // add the new copy to the declaration engine + let new_id = self + .slab + .insert(DeclarationWrapper::Struct(typed_struct_declaration.clone())); + self.add_monomorphized_copy(decl_id, new_id); + + Some(typed_struct_declaration) + } + + pub(crate) fn get_monomorphized_struct( + &self, original_id: DeclarationId, - new_copy: TypedStructDeclaration, - ) { - let new_id = self.slab.insert(DeclarationWrapper::Struct(new_copy)); - self.add_monomorphized_copy(original_id, new_id) + type_arguments: &Vec, + ) -> Option { + for copy in self.get_monomorphized_copies(original_id).iter() { + let monomorphized_struct_decl = match copy { + DeclarationWrapper::Struct(struct_decl) => struct_decl, + _ => panic!(), + }; + + if &monomorphized_struct_decl.type_parameters == type_arguments { + return Some(monomorphized_struct_decl.clone()); + } + } + None } pub(crate) fn get_monomorphized_struct_copies( diff --git a/de/src/language/typed/typed_declaration.rs b/de/src/language/typed/typed_declaration.rs index 9c93e56..b5927ac 100644 --- a/de/src/language/typed/typed_declaration.rs +++ b/de/src/language/typed/typed_declaration.rs @@ -184,7 +184,7 @@ impl PrettyPrint for TypedFunctionDeclaration { } } -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Debug)] pub(crate) struct TypedFunctionParameter { pub(crate) name: String, pub(crate) type_id: TypeId, @@ -280,7 +280,7 @@ impl PrettyPrint for TypedTraitImpl { } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] pub(crate) struct TypedStructDeclaration { pub(crate) name: String, pub(crate) type_parameters: Vec, @@ -348,7 +348,7 @@ impl fmt::Display for TypedStructDeclaration { } } -#[derive(Clone, Hash, PartialEq, Eq)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct TypedStructField { pub(crate) name: String, pub(crate) type_id: TypeId, diff --git a/de/src/namespace/function_signature.rs b/de/src/namespace/function_signature.rs index b0472b8..2dc1367 100644 --- a/de/src/namespace/function_signature.rs +++ b/de/src/namespace/function_signature.rs @@ -5,6 +5,7 @@ use crate::{ type_system::{type_id::TypeId, type_parameter::TypeParameter}, }; +#[derive(PartialEq, Eq, PartialOrd, Ord)] pub(crate) struct TypedFunctionSignature { #[allow(dead_code)] pub(crate) name: String, @@ -25,6 +26,17 @@ impl From for TypedFunctionSignature { } } +impl From<&TypedFunctionDeclaration> for TypedFunctionSignature { + fn from(decl: &TypedFunctionDeclaration) -> Self { + TypedFunctionSignature { + name: decl.name.clone(), + type_parameters: decl.type_parameters.clone(), + parameters: decl.parameters.clone(), + return_type: decl.return_type, + } + } +} + impl From for TypedFunctionSignature { fn from(decl: TypedTraitFn) -> Self { TypedFunctionSignature { diff --git a/de/src/semantic_analysis/inference/expression.rs b/de/src/semantic_analysis/inference/expression.rs index 4ad4503..5e03dd0 100644 --- a/de/src/semantic_analysis/inference/expression.rs +++ b/de/src/semantic_analysis/inference/expression.rs @@ -10,7 +10,7 @@ use crate::{ }, namespace::namespace::Namespace, type_system::{ - type_engine::{insert_type, monomorphize, unify_types}, + type_engine::{insert_type, unify_types}, type_info::TypeInfo, }, types::create_type_id::CreateTypeId, @@ -53,28 +53,15 @@ pub(super) fn analyze_expression( .expect_function() .unwrap(); - // get the original function declaration - let mut typed_function_declaration = declaration_engine.get_function(decl_id).unwrap(); + let typed_function_declaration = declaration_engine + .get_or_create_monomorphized_fn(decl_id, &mut type_arguments, namespace) + .unwrap(); // make sure we have the correct number of arguments if typed_function_declaration.parameters.len() != arguments.len() { panic!(); } - // monomorphize the function declaration into a new copy - // TODO(joao): optimize this to cache repeated monomorphize copies - monomorphize( - &mut typed_function_declaration, - &mut type_arguments, - namespace, - declaration_engine, - ) - .unwrap(); - - // add the new copy to the declaration engine - declaration_engine - .add_monomorphized_function_copy(decl_id, typed_function_declaration.clone()); - // type check the arguments let new_arguments = arguments .into_iter() @@ -113,22 +100,9 @@ pub(super) fn analyze_expression( .expect_struct() .unwrap(); - // get the original struct declaration - let mut typed_struct_declaration = declaration_engine.get_struct(decl_id).unwrap(); - - // monomorphize the struct declaration into a new copy - // TODO(joao): optimize this to cache repeated monomorphize copies - monomorphize( - &mut typed_struct_declaration, - &mut type_arguments, - namespace, - declaration_engine, - ) - .unwrap(); - - // add the new copy to the declaration engine - declaration_engine - .add_monomorphized_struct_copy(decl_id, typed_struct_declaration.clone()); + let typed_struct_declaration = declaration_engine + .get_or_create_monomorphized_struct(decl_id, &mut type_arguments, namespace) + .unwrap(); // type check the fields let given_fields_map: HashMap<_, _> = fields diff --git a/de/src/type_system/trait_constraint.rs b/de/src/type_system/trait_constraint.rs index 997d608..9e4d5dd 100644 --- a/de/src/type_system/trait_constraint.rs +++ b/de/src/type_system/trait_constraint.rs @@ -1,4 +1,4 @@ -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) struct TraitConstraint { pub(crate) trait_name: String, } diff --git a/de/src/type_system/type_argument.rs b/de/src/type_system/type_argument.rs index 8a94d04..66cf5f3 100644 --- a/de/src/type_system/type_argument.rs +++ b/de/src/type_system/type_argument.rs @@ -1,6 +1,6 @@ use std::fmt; -use super::type_id::TypeId; +use super::{type_id::TypeId, type_parameter::TypeParameter}; #[derive(Debug, Clone)] pub struct TypeArgument { @@ -12,3 +12,9 @@ impl fmt::Display for TypeArgument { write!(f, "{}", self.type_id) } } + +impl PartialEq for TypeArgument { + fn eq(&self, other: &TypeParameter) -> bool { + self.type_id == other.type_id + } +} diff --git a/de/src/type_system/type_engine.rs b/de/src/type_system/type_engine.rs index 7cd997f..6d664af 100644 --- a/de/src/type_system/type_engine.rs +++ b/de/src/type_system/type_engine.rs @@ -185,32 +185,23 @@ impl TypeEngine { _ => Err("could not find generic declaration".to_string()), }, TypeInfo::Ref(id) => Ok(id), - TypeInfo::Custom { name } => { - match namespace.get_symbol(&name)? { - TypedDeclaration::Struct(decl_id) => { - // get the original struct declaration - let mut struct_decl = declaration_engine.get_struct(decl_id).unwrap(); + TypeInfo::Custom { name } => match namespace.get_symbol(&name)? { + TypedDeclaration::Struct(decl_id) => { + let mut type_arguments = vec![]; + let struct_decl = declaration_engine + .get_or_create_monomorphized_struct(decl_id, &mut type_arguments, namespace) + .unwrap(); - // monomorphize the struct declaration into a new copy - // TODO(joao): optimize this to cache repeated monomorphize copies - monomorphize(&mut struct_decl, &mut [], namespace, declaration_engine) - .unwrap(); - - // add the new copy to the declaration engine - declaration_engine - .add_monomorphized_struct_copy(decl_id, struct_decl.clone()); - - Ok(struct_decl.create_type_id()) - } - TypedDeclaration::GenericTypeForFunctionScope { type_id, .. } => { - Ok(insert_type(TypeInfo::Ref(type_id))) - } - got => Err(format!( - "err, found: {}", - got.pretty_print(declaration_engine) - )), + Ok(struct_decl.create_type_id()) } - } + TypedDeclaration::GenericTypeForFunctionScope { type_id, .. } => { + Ok(insert_type(TypeInfo::Ref(type_id))) + } + got => Err(format!( + "err, found: {}", + got.pretty_print(declaration_engine) + )), + }, o => Ok(insert_type(o)), } } diff --git a/de/src/type_system/type_id.rs b/de/src/type_system/type_id.rs index 6bdfef4..fa60c93 100644 --- a/de/src/type_system/type_id.rs +++ b/de/src/type_system/type_id.rs @@ -7,7 +7,7 @@ use super::type_engine::{insert_type, look_up_type_id, look_up_type_id_raw}; use super::type_info::TypeInfo; use super::type_mapping::TypeMapping; -#[derive(Eq, Clone, Copy, Debug)] +#[derive(Eq, Clone, Copy, PartialOrd, Ord, Debug)] pub struct TypeId(usize); impl std::ops::Deref for TypeId { diff --git a/de/src/type_system/type_parameter.rs b/de/src/type_system/type_parameter.rs index 6be92aa..678e864 100644 --- a/de/src/type_system/type_parameter.rs +++ b/de/src/type_system/type_parameter.rs @@ -4,10 +4,11 @@ use std::hash::Hash; use crate::types::copy_types::CopyTypes; use super::trait_constraint::TraitConstraint; +use super::type_argument::TypeArgument; use super::type_id::TypeId; use super::type_mapping::TypeMapping; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TypeParameter { pub(crate) name: String, pub(crate) type_id: TypeId, @@ -25,3 +26,9 @@ impl fmt::Display for TypeParameter { write!(f, "{}", self.type_id) } } + +impl PartialEq for TypeParameter { + fn eq(&self, other: &TypeArgument) -> bool { + self.type_id == other.type_id + } +} diff --git a/de/tests/harness.rs b/de/tests/harness.rs index 02679b1..748e28f 100644 --- a/de/tests/harness.rs +++ b/de/tests/harness.rs @@ -304,6 +304,60 @@ fn generic_struct_test() { println!("{}", resolved_application); } +#[test] +fn generic_struct_monomorph_cache_test() { + println!( + "\n\n**********************************************************************************" + ); + + let data_decl = struct_( + "Data", + &[type_param("T", None)], + &[ + struct_field("field_one", t_u8()), + struct_field("field_two", t_u32()), + struct_field("field_three", t_gen_("T")), + ], + ); + let foo_decl = var_decl( + "foo", + None, + struct_exp( + "Data", + &[], + &[ + struct_exp_field("field_one", u8(2u8)), + struct_exp_field("field_two", u32(3u32)), + struct_exp_field("field_three", u64(100u64)), + ], + ), + ); + let bar_decl = var_decl( + "bar", + None, + struct_exp( + "Data", + &[], + &[ + struct_exp_field("field_one", u8(99u8)), + struct_exp_field("field_two", u32(24u32)), + struct_exp_field("field_three", u64(100u64)), + ], + ), + ); + let main_fn = func_decl("main", &[], &[], &[foo_decl, bar_decl], t_unit()); + let program_1 = File { + name: "bob.sw".to_string(), + nodes: vec![data_decl, main_fn], + }; + let application = Application { + files: vec![program_1], + }; + println!("{}", application); + let resolved_application = compile(application); + println!("{}", resolved_application); +} + #[test] fn generic_struct_with_trait_test() { println!(