From f674f9ee9748de3bc40ded16d6a2dde11367c154 Mon Sep 17 00:00:00 2001 From: microproofs Date: Wed, 14 Aug 2024 18:43:20 -0400 Subject: [PATCH] hoist functions to super constants too --- crates/aiken-lang/src/gen_uplc.rs | 155 ++++++++---------------------- 1 file changed, 41 insertions(+), 114 deletions(-) diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index 352da36a..b296c4f8 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -68,7 +68,6 @@ pub struct CodeGenerator<'a> { defined_functions: IndexMap, special_functions: CodeGenSpecialFuncs, code_gen_functions: IndexMap, - zero_arg_functions: IndexMap<(FunctionAccessKey, Variant), Vec>, cyclic_functions: IndexMap<(FunctionAccessKey, Variant), (CycleFunctionNames, usize, FunctionAccessKey)>, /// mutable and reset as well @@ -100,7 +99,6 @@ impl<'a> CodeGenerator<'a> { defined_functions: IndexMap::new(), special_functions: CodeGenSpecialFuncs::new(), code_gen_functions: IndexMap::new(), - zero_arg_functions: IndexMap::new(), cyclic_functions: IndexMap::new(), id_gen: IdGenerator::new(), } @@ -108,7 +106,6 @@ impl<'a> CodeGenerator<'a> { pub fn reset(&mut self, reset_special_functions: bool) { self.code_gen_functions = IndexMap::new(); - self.zero_arg_functions = IndexMap::new(); self.defined_functions = IndexMap::new(); self.cyclic_functions = IndexMap::new(); self.id_gen = IdGenerator::new(); @@ -3686,56 +3683,39 @@ impl<'a> CodeGenerator<'a> { // first grab dependencies let func_params = params; - let params_empty = func_params.is_empty(); - let deps = (tree_path, func_deps.clone()); - if !params_empty { - let recursive_nonstatics = if is_recursive { - modify_self_calls(&mut body, key, variant, func_params) - } else { - func_params.clone() - }; - - let node_to_edit = air_tree.find_air_tree_node(tree_path); - - let defined_function = AirTree::define_func( - &key.function_name, - &key.module_name, - variant, - func_params.clone(), - is_recursive, - recursive_nonstatics, - body, - node_to_edit.clone(), - ); - - let defined_dependencies = self.hoist_dependent_functions( - deps, - params_empty, - (key, variant), - hoisted_functions, - functions_to_hoist, - defined_function, - ); - - // now hoist full function onto validator tree - *node_to_edit = defined_dependencies; - - hoisted_functions.push((key.clone(), variant.clone())); + let recursive_nonstatics = if is_recursive { + modify_self_calls(&mut body, key, variant, func_params) } else { - let defined_func = self.hoist_dependent_functions( - deps, - params_empty, - (key, variant), - hoisted_functions, - functions_to_hoist, - body, - ); + func_params.clone() + }; - self.zero_arg_functions - .insert((key.clone(), variant.clone()), defined_func.to_vec()); - } + let node_to_edit = air_tree.find_air_tree_node(tree_path); + + let defined_function = AirTree::define_func( + &key.function_name, + &key.module_name, + variant, + func_params.clone(), + is_recursive, + recursive_nonstatics, + body, + node_to_edit.clone(), + ); + + let defined_dependencies = self.hoist_dependent_functions( + deps, + (key, variant), + hoisted_functions, + functions_to_hoist, + defined_function, + ); + + // now hoist full function onto validator tree + *node_to_edit = defined_dependencies; + + hoisted_functions.push((key.clone(), variant.clone())); } HoistableFunction::CyclicFunction { functions, @@ -3763,8 +3743,6 @@ impl<'a> CodeGenerator<'a> { let defined_dependencies = self.hoist_dependent_functions( deps, - // cyclic functions always have params - false, (key, variant), hoisted_functions, functions_to_hoist, @@ -3788,7 +3766,6 @@ impl<'a> CodeGenerator<'a> { fn hoist_dependent_functions( &mut self, deps: (&TreePath, Vec<(FunctionAccessKey, String)>), - params_empty: bool, func_key_variant: (&FunctionAccessKey, &Variant), hoisted_functions: &mut Vec<(FunctionAccessKey, String)>, functions_to_hoist: &IndexMap< @@ -3855,12 +3832,12 @@ impl<'a> CodeGenerator<'a> { sorted_dep_vec .into_iter() .fold(air_tree, |then, (dep_key, dep_variant)| { - if (!params_empty - // if the dependency is the same as the function we're hoisting - // or we hoisted it, then skip it - && hoisted_functions.iter().any(|(generic, variant)| { - generic == &dep_key && variant == &dep_variant - })) + if + // if the dependency is the same as the function we're hoisting + // or we hoisted it, then skip it + hoisted_functions + .iter() + .any(|(generic, variant)| generic == &dep_key && variant == &dep_variant) || (&dep_key == key && &dep_variant == variant) { return then; @@ -3877,7 +3854,7 @@ impl<'a> CodeGenerator<'a> { // In the case of zero args, we need to hoist the dependency function to the top of the zero arg function // The dependency we are hoisting should have an equal path to the function we hoisted // if we are going to hoist it - if &dep_path.common_ancestor(func_path) == func_path || params_empty { + if &dep_path.common_ancestor(func_path) == func_path { match dep_function.clone() { HoistableFunction::Function { body: mut dep_air_tree, @@ -3904,9 +3881,7 @@ impl<'a> CodeGenerator<'a> { dependent_params.clone() }; - if !params_empty { - hoisted_functions.push((dep_key.clone(), dep_variant.clone())); - } + hoisted_functions.push((dep_key.clone(), dep_variant.clone())); AirTree::define_func( &dep_key.function_name, @@ -3926,9 +3901,7 @@ impl<'a> CodeGenerator<'a> { modify_cyclic_calls(body, &dep_key, &self.cyclic_functions); } - if !params_empty { - hoisted_functions.push((dep_key.clone(), dep_variant.clone())); - } + hoisted_functions.push((dep_key.clone(), dep_variant.clone())); AirTree::define_cyclic_func( &dep_key.function_name, @@ -4272,6 +4245,8 @@ impl<'a> CodeGenerator<'a> { true, ); + value = self.hoist_functions_to_validator(value); + let term = self .uplc_code_gen(value.to_vec()) .constr_fields_exposer() @@ -4638,55 +4613,7 @@ impl<'a> CodeGenerator<'a> { // How we handle zero arg anon functions has changed // We now delay zero arg anon functions and force them on a call operation match term.pierce_no_inlines() { - Term::Var(name) => { - let zero_arg_functions = self.zero_arg_functions.clone(); - let text = &name.text; - - if let Some((_, air_vec)) = zero_arg_functions.iter().find( - |( - ( - FunctionAccessKey { - module_name, - function_name, - }, - variant, - ), - _, - )| { - let name_module = - format!("{module_name}_{function_name}{variant}"); - let name = format!("{function_name}{variant}"); - - text == &name || text == &name_module - }, - ) { - let mut term = self.uplc_code_gen(air_vec.clone()); - - term = term.constr_fields_exposer().constr_index_exposer(); - - let mut program: Program = Program { - version: (1, 0, 0), - term: self.special_functions.apply_used_functions(term), - }; - - let mut interner = CodeGenInterner::new(); - - interner.program(&mut program); - - let eval_program: Program = - program.remove_no_inlines().try_into().unwrap(); - - let result = eval_program.eval(ExBudget::max()).result(); - - let evaluated_term: Term = result.unwrap_or_else(|e| { - panic!("Evaluated a zero argument function and received this error: {e:#?}") - }); - - Some(evaluated_term.try_into().unwrap()) - } else { - Some(term.force()) - } - } + Term::Var(_) => Some(term.force()), Term::Delay(inner_term) => Some(inner_term.as_ref().clone()), Term::Apply { .. } => Some(term.force()), _ => unreachable!(