forked from M-Labs/nac3
[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.
This commit is contained in:
parent
4f5e417012
commit
8fd7216243
|
@ -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<GenCall>)>,
|
||||
builtins: Vec<BuiltinFuncSpec>,
|
||||
pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>,
|
||||
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,
|
||||
);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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<GenCall>);
|
||||
|
||||
/// 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<GenCall>)>,
|
||||
builtins: Vec<BuiltinFuncSpec>,
|
||||
lateinit_builtins: Vec<Box<BuiltinFuncCreator>>,
|
||||
core_config: ComposerConfig,
|
||||
size_t: u32,
|
||||
) -> (Self, HashMap<StrRef, DefinitionId>, HashMap<StrRef, Type>) {
|
||||
|
@ -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()));
|
||||
|
|
|
@ -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![
|
||||
|
|
|
@ -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> = ResolverInternal {
|
||||
id_to_type: builtins_ty.into(),
|
||||
|
|
Loading…
Reference in New Issue