diff --git a/crates/lean_compiler/src/a_simplify_lang.rs b/crates/lean_compiler/src/a_simplify_lang.rs index 5c7308eed..2a028d718 100644 --- a/crates/lean_compiler/src/a_simplify_lang.rs +++ b/crates/lean_compiler/src/a_simplify_lang.rs @@ -1521,28 +1521,68 @@ fn handle_inlined_functions(program: &mut Program) { ); } - for func in program.functions.values_mut() { - if func.inlined { - let mut func_called = Vec::new(); - get_function_called(&func.body, &mut func_called); - for func_called in func_called { - assert!( - !inlined_functions.contains_key(&func_called), - "Inlined functions calling other inlined functions are not supported yet" + // Process inline functions iteratively to handle dependencies + // Repeat until all inline function calls are resolved + let mut max_iterations = 10; + while max_iterations > 0 { + let mut any_changes = false; + + // Process non-inlined functions + for func in program.functions.values_mut() { + if !func.inlined { + let mut counter1 = Counter::new(); + let mut counter2 = Counter::new(); + let old_body = func.body.clone(); + + handle_inlined_functions_helper( + &mut func.body, + &inlined_functions, + &mut counter1, + &mut counter2, ); + + if func.body != old_body { + any_changes = true; + } } - } else { - handle_inlined_functions_helper( - &mut func.body, - &inlined_functions, - &mut Counter::new(), - &mut Counter::new(), - ); } + + // Process inlined functions that may call other inlined functions + // We need to update them so that when they get inlined later, they don't have unresolved calls + for func in program.functions.values_mut() { + if func.inlined { + let mut counter1 = Counter::new(); + let mut counter2 = Counter::new(); + let old_body = func.body.clone(); + + handle_inlined_functions_helper( + &mut func.body, + &inlined_functions, + &mut counter1, + &mut counter2, + ); + + if func.body != old_body { + any_changes = true; + } + } + } + + if !any_changes { + break; + } + + max_iterations -= 1; } - for func in inlined_functions.keys() { - program.functions.remove(func); + assert!( + max_iterations > 0, + "Too many iterations processing inline functions" + ); + + // Remove all inlined functions from the program (they've been inlined) + for func_name in inlined_functions.keys() { + program.functions.remove(func_name); } } diff --git a/crates/lean_compiler/tests/test_compiler.rs b/crates/lean_compiler/tests/test_compiler.rs index a96c202a7..a82652484 100644 --- a/crates/lean_compiler/tests/test_compiler.rs +++ b/crates/lean_compiler/tests/test_compiler.rs @@ -464,3 +464,53 @@ fn test_const_functions_calling_const_functions() { compile_and_run(program, &[], &[], false); } + +#[test] +fn test_inline_functions_calling_inline_functions() { + let program = r#" + fn main() { + x = double(3); + y = quad(x); + print(y); + return; + } + + fn double(a) inline -> 1 { + return a + a; + } + + fn quad(b) inline -> 1 { + result = double(b); + return result + result; + } + "#; + + compile_and_run(program, &[], &[], false); +} + +#[test] +fn test_nested_inline_functions() { + let program = r#" + fn main() { + result = level_one(3); + print(result); + return; + } + + fn level_one(x) inline -> 1 { + result = level_two(x); + return result; + } + + fn level_two(y) inline -> 1 { + result = level_three(y); + return result; + } + + fn level_three(z) inline -> 1 { + return z * z * z; + } + "#; + + compile_and_run(program, &[], &[], false); +}