From 8fd7216243a756fed97b2014215cd5fade324698 Mon Sep 17 00:00:00 2001 From: David Mak Date: Mon, 12 Aug 2024 18:00:23 +0800 Subject: [PATCH] [core] toplevel/composer: Add lateinit_builtins This is required for the new core_log and rtio_log functions, which take a generic type as its parameter. However, in ARTIQ builtins are initialized using one unifier and then actually used by another unifier. lateinit_builtins workaround this issue by deferring the initialization of functions requiring type variables until the actual unifier is ready. --- nac3artiq/src/lib.rs | 8 ++++---- nac3core/src/codegen/test.rs | 4 ++-- nac3core/src/toplevel/composer.rs | 27 ++++++++++++++++++++++++--- nac3core/src/toplevel/test.rs | 15 ++++++++++----- nac3standalone/src/main.rs | 2 +- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 32fe0218d..92597ee06 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -51,7 +51,7 @@ use nac3core::{ codegen::{concrete_type::ConcreteTypeStore, CodeGenTask, WithCall, WorkerRegistry}, symbol_resolver::SymbolResolver, toplevel::{ - composer::{ComposerConfig, TopLevelComposer}, + composer::{BuiltinFuncSpec, ComposerConfig, TopLevelComposer}, DefinitionId, GenCall, TopLevelDef, }, typecheck::typedef::{FunSignature, FuncArg}, @@ -60,13 +60,12 @@ use nac3core::{ use nac3ld::Linker; -use tempfile::{self, TempDir}; - use crate::codegen::attributes_writeback; use crate::{ codegen::{rpc_codegen_callback, ArtiqCodeGenerator}, symbol_resolver::{DeferredEvaluationStore, InnerResolver, PythonHelper, Resolver}, }; +use tempfile::{self, TempDir}; mod codegen; mod symbol_resolver; @@ -127,7 +126,7 @@ struct Nac3 { isa: Isa, time_fns: &'static (dyn TimeFns + Sync), primitive: PrimitiveStore, - builtins: Vec<(StrRef, FunSignature, Arc)>, + builtins: Vec, pyid_to_def: Arc>>, primitive_ids: PrimitivePythonId, working_directory: TempDir, @@ -313,6 +312,7 @@ impl Nac3 { let size_t = self.isa.get_size_type(); let (mut composer, mut builtins_def, mut builtins_ty) = TopLevelComposer::new( self.builtins.clone(), + Vec::new(), ComposerConfig { kernel_ann: Some("Kernel"), kernel_invariant_ann: "KernelInvariant" }, size_t, ); diff --git a/nac3core/src/codegen/test.rs b/nac3core/src/codegen/test.rs index 8d128ae35..9ed495e09 100644 --- a/nac3core/src/codegen/test.rs +++ b/nac3core/src/codegen/test.rs @@ -94,7 +94,7 @@ fn test_primitives() { "}; let statements = parse_program(source, FileName::default()).unwrap(); - let composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 32).0; + let composer = TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 32).0; let mut unifier = composer.unifier.clone(); let primitives = composer.primitives_ty; let top_level = Arc::new(composer.make_top_level_context()); @@ -258,7 +258,7 @@ fn test_simple_call() { "}; let statements_2 = parse_program(source_2, FileName::default()).unwrap(); - let composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 32).0; + let composer = TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 32).0; let mut unifier = composer.unifier.clone(); let primitives = composer.primitives_ty; let top_level = Arc::new(composer.make_top_level_context()); diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 547c7e276..2f0f7e875 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -44,12 +44,27 @@ pub struct TopLevelComposer { pub size_t: u32, } +/// The specification for a builtin function, consisting of the function name, the function +/// signature, and a [code generation callback][`GenCall`]. +pub type BuiltinFuncSpec = (StrRef, FunSignature, Arc); + +/// A function that creates a [`BuiltinFuncSpec`] using the provided [`PrimitiveStore`] and +/// [`Unifier`]. +pub type BuiltinFuncCreator = dyn Fn(&PrimitiveStore, &mut Unifier) -> BuiltinFuncSpec; + impl TopLevelComposer { /// return a composer and things to make a "primitive" symbol resolver, so that the symbol - /// resolver can later figure out primitive type definitions when passed a primitive type name + /// resolver can later figure out primitive tye definitions when passed a primitive type name + /// + /// `lateinit_builtins` are specifically for the ARTIQ module. Since the [`Unifier`] instance + /// used to create builtin functions do not persist until method compilation, any types + /// created (e.g. [`TypeEnum::TVar`]) also do not persist. Those functions should be instead put + /// in `lateinit_builtins`, where they will be instantiated with the [`Unifier`] instance used + /// for method compilation. #[must_use] pub fn new( - builtins: Vec<(StrRef, FunSignature, Arc)>, + builtins: Vec, + lateinit_builtins: Vec>, core_config: ComposerConfig, size_t: u32, ) -> (Self, HashMap, HashMap) { @@ -119,7 +134,13 @@ impl TopLevelComposer { } } - for (name, sig, codegen_callback) in builtins { + // Materialize lateinit_builtins, now that the unifier is ready + let lateinit_builtins = lateinit_builtins + .into_iter() + .map(|builtin| builtin(&primitives_ty, &mut unifier)) + .collect_vec(); + + for (name, sig, codegen_callback) in builtins.into_iter().chain(lateinit_builtins) { let fun_sig = unifier.add_ty(TypeEnum::TFunc(sig)); builtin_ty.insert(name, fun_sig); builtin_id.insert(name, DefinitionId(definition_ast_list.len())); diff --git a/nac3core/src/toplevel/test.rs b/nac3core/src/toplevel/test.rs index 7678452d8..522cb23d0 100644 --- a/nac3core/src/toplevel/test.rs +++ b/nac3core/src/toplevel/test.rs @@ -117,7 +117,8 @@ impl SymbolResolver for Resolver { "register" )] fn test_simple_register(source: Vec<&str>) { - let mut composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 64).0; + let mut composer = + TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0; for s in source { let ast = parse_program(s, FileName::default()).unwrap(); @@ -137,7 +138,8 @@ fn test_simple_register(source: Vec<&str>) { "register" )] fn test_simple_register_without_constructor(source: &str) { - let mut composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 64).0; + let mut composer = + TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0; let ast = parse_program(source, FileName::default()).unwrap(); let ast = ast[0].clone(); composer.register_top_level(ast, None, "", true).unwrap(); @@ -171,7 +173,8 @@ fn test_simple_register_without_constructor(source: &str) { "function compose" )] fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) { - let mut composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 64).0; + let mut composer = + TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0; let internal_resolver = Arc::new(ResolverInternal { id_to_def: Mutex::default(), @@ -519,7 +522,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) { )] fn test_analyze(source: &[&str], res: &[&str]) { let print = false; - let mut composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 64).0; + let mut composer = + TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0; let internal_resolver = make_internal_resolver_with_tvar( vec![ @@ -696,7 +700,8 @@ fn test_analyze(source: &[&str], res: &[&str]) { )] fn test_inference(source: Vec<&str>, res: &[&str]) { let print = true; - let mut composer = TopLevelComposer::new(Vec::new(), ComposerConfig::default(), 64).0; + let mut composer = + TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0; let internal_resolver = make_internal_resolver_with_tvar( vec![ diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index 228b75c4f..cc4811c19 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -301,7 +301,7 @@ fn main() { let primitive: PrimitiveStore = TopLevelComposer::make_primitives(size_t).0; let (mut composer, builtins_def, builtins_ty) = - TopLevelComposer::new(vec![], ComposerConfig::default(), size_t); + TopLevelComposer::new(vec![], vec![], ComposerConfig::default(), size_t); let internal_resolver: Arc = ResolverInternal { id_to_type: builtins_ty.into(),