diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index d250209b..3b28c6e4 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -41,8 +41,9 @@ use self::{ air::Air, builder::{ cast_validator_args, constants_ir, convert_type_to_data, extract_constant, - lookup_data_type_by_tipo, modify_self_calls, rearrange_list_clauses, AssignmentProperties, - ClauseProperties, DataTypeKey, FunctionAccessKey, HoistableFunction, Variant, + lookup_data_type_by_tipo, modify_cyclic_calls, modify_self_calls, rearrange_list_clauses, + AssignmentProperties, ClauseProperties, DataTypeKey, FunctionAccessKey, HoistableFunction, + Variant, }, tree::{AirExpression, AirTree, TreePath}, }; @@ -56,7 +57,8 @@ pub struct CodeGenerator<'a> { needs_field_access: bool, code_gen_functions: IndexMap, zero_arg_functions: IndexMap<(FunctionAccessKey, Variant), Vec>, - cyclic_functions: IndexMap<(FunctionAccessKey, Variant), (usize, FunctionAccessKey)>, + cyclic_functions: + IndexMap<(FunctionAccessKey, Variant), (Vec, usize, FunctionAccessKey)>, tracing: bool, id_gen: IdGenerator, } @@ -2697,12 +2699,28 @@ impl<'a> CodeGenerator<'a> { let mut cycle_of_functions = vec![]; let mut cycle_deps = vec![]; + let function_list = cyclic_function_names + .iter() + .map(|(key, variant)| { + format!( + "{}{}{}", + key.module_name, + key.function_name, + if variant.is_empty() { + "".to_string() + } else { + format!("_{}", variant) + } + ) + }) + .collect_vec(); + // By doing this any vars that "call" into a function in the cycle will be // redirected to call the cyclic function instead with the proper index for (index, (func_name, variant)) in cyclic_function_names.iter().enumerate() { self.cyclic_functions.insert( (func_name.clone(), variant.clone()), - (index, function_key.clone()), + (function_list.clone(), index, function_key.clone()), ); let (tree_path, func) = functions_to_hoist @@ -2753,6 +2771,7 @@ impl<'a> CodeGenerator<'a> { } // Rest of code is for hoisting functions + // TODO: replace with graph implementation of sorting let mut sorted_function_vec: Vec<(FunctionAccessKey, String)> = vec![]; let functions_to_hoist_cloned = functions_to_hoist.clone(); @@ -2865,8 +2884,6 @@ impl<'a> CodeGenerator<'a> { } sorted_function_vec.dedup(); - todo!(); - // Now we need to hoist the functions to the top of the validator for (key, variant) in sorted_function_vec { if hoisted_functions @@ -2910,54 +2927,99 @@ impl<'a> CodeGenerator<'a> { hoisted_functions: &mut Vec<(FunctionAccessKey, String)>, ) { match function { - HoistableFunction::Function { body, deps, params } => todo!(), - HoistableFunction::CyclicFunction { functions, deps } => todo!(), - HoistableFunction::Link(_) => todo!(), - HoistableFunction::CyclicLink(_) => todo!(), - } + HoistableFunction::Function { + body, + deps: func_deps, + params, + } => { + let mut body = body.clone(); - if let HoistableFunction::Function { - body, - deps: func_deps, - params, - } = function - { - let mut body = body.clone(); + let (key, variant) = key_var; - let (key, variant) = key_var; + // check for recursiveness + let is_recursive = func_deps + .iter() + .any(|(dep_key, dep_variant)| dep_key == key && dep_variant == variant); - // check for recursiveness - let is_recursive = func_deps - .iter() - .any(|(dep_key, dep_variant)| dep_key == key && dep_variant == variant); + // first grab dependencies + let func_params = params; - // first grab dependencies - let func_params = params; + let params_empty = func_params.is_empty(); - let params_empty = func_params.is_empty(); + let deps = (tree_path, func_deps.clone()); - 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() + }; - if !params_empty { - let recursive_nonstatics = if is_recursive { - modify_self_calls(&mut body, key, variant, func_params) + body = AirTree::define_func( + &key.function_name, + &key.module_name, + variant, + func_params.clone(), + is_recursive, + recursive_nonstatics, + body, + ); + + let function_deps = self.hoist_dependent_functions( + deps, + params_empty, + key, + variant, + hoisted_functions, + functions_to_hoist, + ); + let node_to_edit = air_tree.find_air_tree_node(tree_path); + + // now hoist full function onto validator tree + *node_to_edit = function_deps.hoist_over(body.hoist_over(node_to_edit.clone())); + + hoisted_functions.push((key.clone(), variant.clone())); } else { - func_params.clone() - }; + body = self + .hoist_dependent_functions( + deps, + params_empty, + key, + variant, + hoisted_functions, + functions_to_hoist, + ) + .hoist_over(body); - body = AirTree::define_func( + self.zero_arg_functions + .insert((key.clone(), variant.clone()), body.to_vec()); + } + } + HoistableFunction::CyclicFunction { + functions, + deps: func_deps, + } => { + let (key, variant) = key_var; + + let deps = (tree_path, func_deps.clone()); + + let mut functions = functions.clone(); + + for (_, body) in functions.iter_mut() { + modify_cyclic_calls(body, key, &self.cyclic_functions); + } + + let cyclic_body = AirTree::define_cyclic_func( &key.function_name, &key.module_name, variant, - func_params.clone(), - is_recursive, - recursive_nonstatics, - body, + functions, ); let function_deps = self.hoist_dependent_functions( deps, - params_empty, + // cyclic functions always have params + false, key, variant, hoisted_functions, @@ -2966,26 +3028,17 @@ impl<'a> CodeGenerator<'a> { let node_to_edit = air_tree.find_air_tree_node(tree_path); // now hoist full function onto validator tree - *node_to_edit = function_deps.hoist_over(body.hoist_over(node_to_edit.clone())); + *node_to_edit = + function_deps.hoist_over(cyclic_body.hoist_over(node_to_edit.clone())); hoisted_functions.push((key.clone(), variant.clone())); - } else { - body = self - .hoist_dependent_functions( - deps, - params_empty, - key, - variant, - hoisted_functions, - functions_to_hoist, - ) - .hoist_over(body); - - self.zero_arg_functions - .insert((key.clone(), variant.clone()), body.to_vec()); } - } else { - todo!() + HoistableFunction::Link(_) => { + todo!("This should probably be unreachable when I get to it") + } + HoistableFunction::CyclicLink(_) => { + unreachable!("Sorted functions should not contain cyclic links") + } } } @@ -3017,8 +3070,42 @@ impl<'a> CodeGenerator<'a> { .get(&dep.1) .unwrap_or_else(|| panic!("Missing Function Variant Definition")); - if let HoistableFunction::Function { deps, params, .. } = function { - if !params.is_empty() { + match function { + HoistableFunction::Function { deps, params, .. } => { + if !params.is_empty() { + for (dep_generic_func, dep_variant) in deps.iter() { + if !(dep_generic_func == &dep.0 && dep_variant == &dep.1) { + sorted_dep_vec.retain(|(generic_func, variant)| { + !(generic_func == dep_generic_func && variant == dep_variant) + }); + + deps_vec.insert(0, (dep_generic_func.clone(), dep_variant.clone())); + } + } + } + } + HoistableFunction::CyclicFunction { deps, .. } => { + for (dep_generic_func, dep_variant) in deps.iter() { + if !(dep_generic_func == &dep.0 && dep_variant == &dep.1) { + sorted_dep_vec.retain(|(generic_func, variant)| { + !(generic_func == dep_generic_func && variant == dep_variant) + }); + + deps_vec.insert(0, (dep_generic_func.clone(), dep_variant.clone())); + } + } + } + HoistableFunction::Link(_) => todo!("Deal with Link later"), + HoistableFunction::CyclicLink(cyclic_func) => { + let (_, HoistableFunction::CyclicFunction { deps, .. }) = functions_to_hoist + .get(cyclic_func) + .unwrap() + .get("") + .unwrap() + else { + unreachable!() + }; + for (dep_generic_func, dep_variant) in deps.iter() { if !(dep_generic_func == &dep.0 && dep_variant == &dep.1) { sorted_dep_vec.retain(|(generic_func, variant)| { @@ -3029,9 +3116,8 @@ impl<'a> CodeGenerator<'a> { } } } - } else { - todo!("Deal with Link later") } + sorted_dep_vec.push((dep.0.clone(), dep.1.clone())); } @@ -3061,42 +3147,66 @@ 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 if &dep_path.common_ancestor(func_path) == func_path || params_empty { - let HoistableFunction::Function { - body: mut dep_air_tree, - deps: dependency_deps, - params: dependent_params, - } = dep_function.clone() - else { - unreachable!() - }; + match dep_function.clone() { + HoistableFunction::Function { + body: mut dep_air_tree, + deps: dependency_deps, + params: dependent_params, + } => { + if dependent_params.is_empty() { + // continue for zero arg functions. They are treated like global hoists. + continue; + } - if dependent_params.is_empty() { - // continue for zero arg functions. They are treated like global hoists. - continue; - } + let is_dependent_recursive = dependency_deps + .iter() + .any(|(key, variant)| &dep_key == key && &dep_variant == variant); - let is_dependent_recursive = dependency_deps - .iter() - .any(|(key, variant)| &dep_key == key && &dep_variant == variant); + let recursive_nonstatics = if is_dependent_recursive { + modify_self_calls( + &mut dep_air_tree, + &dep_key, + &dep_variant, + &dependent_params, + ) + } else { + dependent_params.clone() + }; - let recursive_nonstatics = if is_dependent_recursive { - modify_self_calls(&mut dep_air_tree, &dep_key, &dep_variant, &dependent_params) - } else { - dependent_params.clone() - }; + dep_insertions.push(AirTree::define_func( + &dep_key.function_name, + &dep_key.module_name, + &dep_variant, + dependent_params, + is_dependent_recursive, + recursive_nonstatics, + dep_air_tree, + )); - dep_insertions.push(AirTree::define_func( - &dep_key.function_name, - &dep_key.module_name, - &dep_variant, - dependent_params, - is_dependent_recursive, - recursive_nonstatics, - dep_air_tree, - )); + if !params_empty { + hoisted_functions.push((dep_key.clone(), dep_variant.clone())); + } + } + HoistableFunction::CyclicFunction { functions, .. } => { + let mut functions = functions.clone(); - if !params_empty { - hoisted_functions.push((dep_key.clone(), dep_variant.clone())); + for (_, body) in functions.iter_mut() { + modify_cyclic_calls(body, key, &self.cyclic_functions); + } + + dep_insertions.push(AirTree::define_cyclic_func( + &dep_key.function_name, + &dep_key.module_name, + &dep_variant, + functions, + )); + + if !params_empty { + hoisted_functions.push((dep_key.clone(), dep_variant.clone())); + } + } + HoistableFunction::Link(_) => unreachable!(), + HoistableFunction::CyclicLink(_) => unreachable!(), } } } @@ -3441,22 +3551,48 @@ impl<'a> CodeGenerator<'a> { module, .. } => { - let name = if (*func_name == name - || name == format!("{module}_{func_name}")) - && !module.is_empty() - { - format!("{module}_{func_name}{variant_name}") - } else { - format!("{func_name}{variant_name}") - }; + if let Some((names, index, cyclic_name)) = self.cyclic_functions.get(&( + FunctionAccessKey { + module_name: module.clone(), + function_name: func_name.clone(), + }, + variant_name.clone(), + )) { + let cyclic_var_name = if cyclic_name.module_name.is_empty() { + cyclic_name.function_name.to_string() + } else { + format!("{}_{}", cyclic_name.module_name, cyclic_name.function_name) + }; - arg_stack.push(Term::Var( - Name { - text: name, - unique: 0.into(), + let index_name = names[*index].clone(); + + let mut arg_var = Term::var(index_name.clone()); + + for name in names.iter().rev() { + arg_var = arg_var.lambda(name); } - .into(), - )); + + let term = Term::var(cyclic_var_name).apply(arg_var); + + arg_stack.push(term); + } else { + let name = if (*func_name == name + || name == format!("{module}_{func_name}")) + && !module.is_empty() + { + format!("{module}_{func_name}{variant_name}") + } else { + format!("{func_name}{variant_name}") + }; + + arg_stack.push(Term::Var( + Name { + text: name, + unique: 0.into(), + } + .into(), + )); + } } ValueConstructorVariant::Record { name: constr_name, .. diff --git a/crates/aiken-lang/src/gen_uplc/builder.rs b/crates/aiken-lang/src/gen_uplc/builder.rs index 298b7cd5..d7a05291 100644 --- a/crates/aiken-lang/src/gen_uplc/builder.rs +++ b/crates/aiken-lang/src/gen_uplc/builder.rs @@ -751,6 +751,55 @@ pub fn modify_self_calls( recursive_nonstatics } +pub fn modify_cyclic_calls( + body: &mut AirTree, + func_key: &FunctionAccessKey, + cyclic_links: &IndexMap<(FunctionAccessKey, Variant), (Vec, usize, FunctionAccessKey)>, +) { + body.traverse_tree_with( + &mut |air_tree: &mut AirTree, _| { + if let AirTree::Expression(AirExpression::Var { + constructor: + ValueConstructor { + variant: ValueConstructorVariant::ModuleFn { name, module, .. }, + tipo, + .. + }, + variant_name, + .. + }) = air_tree + { + let tipo = tipo.clone(); + let var_key = FunctionAccessKey { + module_name: module.clone(), + function_name: name.clone(), + }; + + if let Some((names, index, cyclic_name)) = + cyclic_links.get(&(var_key.clone(), variant_name.to_string())) + { + if *cyclic_name == *func_key { + let index_name = names[*index].clone(); + + *air_tree = AirTree::call( + air_tree.clone(), + tipo.clone(), + vec![ + air_tree.clone(), + AirTree::anon_func( + names.clone(), + AirTree::local_var(index_name, tipo), + ), + ], + ); + } + } + } + }, + true, + ); +} + pub fn pattern_has_conditions( pattern: &TypedPattern, data_types: &IndexMap, diff --git a/crates/aiken-lang/src/gen_uplc/tree.rs b/crates/aiken-lang/src/gen_uplc/tree.rs index f3c39536..3273a971 100644 --- a/crates/aiken-lang/src/gen_uplc/tree.rs +++ b/crates/aiken-lang/src/gen_uplc/tree.rs @@ -430,6 +430,22 @@ impl AirTree { hoisted_over: None, } } + pub fn define_cyclic_func( + func_name: impl ToString, + module_name: impl ToString, + variant_name: impl ToString, + contained_functions: Vec<(Vec, AirTree)>, + ) -> AirTree { + AirTree::Statement { + statement: AirStatement::DefineCyclicFuncs { + func_name: func_name.to_string(), + module_name: module_name.to_string(), + variant_name: variant_name.to_string(), + contained_functions, + }, + hoisted_over: None, + } + } pub fn anon_func(params: Vec, func_body: AirTree) -> AirTree { AirTree::Expression(AirExpression::Fn { params, @@ -1375,10 +1391,10 @@ impl AirTree { pub fn traverse_tree_with( &mut self, with: &mut impl FnMut(&mut AirTree, &TreePath), - apply_with_last: bool, + apply_with_func_last: bool, ) { let mut tree_path = TreePath::new(); - self.do_traverse_tree_with(&mut tree_path, 0, 0, with, apply_with_last); + self.do_traverse_tree_with(&mut tree_path, 0, 0, with, apply_with_func_last); } pub fn traverse_tree_with_path( @@ -1387,9 +1403,9 @@ impl AirTree { current_depth: usize, depth_index: usize, with: &mut impl FnMut(&mut AirTree, &TreePath), - apply_with_last: bool, + apply_with_func_last: bool, ) { - self.do_traverse_tree_with(path, current_depth, depth_index, with, apply_with_last); + self.do_traverse_tree_with(path, current_depth, depth_index, with, apply_with_func_last); } fn do_traverse_tree_with( @@ -1398,7 +1414,7 @@ impl AirTree { current_depth: usize, depth_index: usize, with: &mut impl FnMut(&mut AirTree, &TreePath), - apply_with_last: bool, + apply_with_func_last: bool, ) { let mut index_count = IndexCounter::new(); tree_path.push(current_depth, depth_index); @@ -1411,7 +1427,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirStatement::DefineFunc { func_body, .. } => { @@ -1420,7 +1436,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirStatement::DefineCyclicFuncs { @@ -1433,7 +1449,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } } @@ -1444,7 +1460,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirStatement::AssertBool { value, .. } => { @@ -1453,7 +1469,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirStatement::ClauseGuard { pattern, .. } => { @@ -1462,7 +1478,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirStatement::ListClauseGuard { .. } => {} @@ -1473,7 +1489,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirStatement::ListAccessor { list, .. } => { @@ -1482,7 +1498,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirStatement::ListExpose { .. } => {} @@ -1492,7 +1508,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirStatement::NoOp => {} @@ -1502,7 +1518,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirStatement::ListEmpty { list } => { @@ -1511,13 +1527,13 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } }; } - if !apply_with_last { + if !apply_with_func_last { with(self, tree_path); } @@ -1531,7 +1547,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirTree::Expression(e) => match e { @@ -1542,7 +1558,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } } @@ -1553,7 +1569,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } } @@ -1563,7 +1579,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); for arg in args { @@ -1572,7 +1588,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } } @@ -1582,7 +1598,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::Builtin { args, .. } => { @@ -1592,7 +1608,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } } @@ -1602,7 +1618,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); right.do_traverse_tree_with( @@ -1610,7 +1626,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::UnOp { arg, .. } => { @@ -1619,7 +1635,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::CastFromData { value, .. } => { @@ -1628,7 +1644,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::CastToData { value, .. } => { @@ -1637,7 +1653,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::When { @@ -1648,7 +1664,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); clauses.do_traverse_tree_with( @@ -1656,7 +1672,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::Clause { @@ -1670,7 +1686,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); then.do_traverse_tree_with( @@ -1678,7 +1694,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); otherwise.do_traverse_tree_with( @@ -1686,7 +1702,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::ListClause { @@ -1697,7 +1713,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); otherwise.do_traverse_tree_with( @@ -1705,7 +1721,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::WrapClause { then, otherwise } => { @@ -1714,7 +1730,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); otherwise.do_traverse_tree_with( @@ -1722,7 +1738,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::TupleClause { @@ -1733,7 +1749,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); otherwise.do_traverse_tree_with( @@ -1741,7 +1757,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::Finally { pattern, then } => { @@ -1750,7 +1766,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); then.do_traverse_tree_with( @@ -1758,7 +1774,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::If { @@ -1772,7 +1788,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); then.do_traverse_tree_with( @@ -1780,7 +1796,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); otherwise.do_traverse_tree_with( @@ -1788,7 +1804,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::Constr { args, .. } => { @@ -1798,7 +1814,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } } @@ -1808,7 +1824,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); for arg in args { arg.do_traverse_tree_with( @@ -1816,7 +1832,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } } @@ -1826,7 +1842,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::TupleIndex { tuple, .. } => { @@ -1835,7 +1851,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } AirExpression::Trace { msg, then, .. } => { @@ -1844,7 +1860,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); then.do_traverse_tree_with( @@ -1852,7 +1868,7 @@ impl AirTree { current_depth + 1, index_count.next_number(), with, - apply_with_last, + apply_with_func_last, ); } _ => {} @@ -1860,7 +1876,7 @@ impl AirTree { a => unreachable!("GOT THIS {:#?}", a), } - if apply_with_last { + if apply_with_func_last { with(self, tree_path); }