From 33a1e7d2246bdea48dd6fe925d427c7be8c4659d Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Mon, 21 Oct 2024 16:45:57 +0100 Subject: [PATCH] fix: Display function name and body when inlining recursion limit hit (#6291) # Description ## Problem\* Resolves #4828 ## Summary\* Given a program like this: ``` fn main() { main(); } ``` Changed this panic message: ``` Attempted to recur more than 1000 times during function inlining. ``` Into this: ``` Attempted to recur more than 1000 times during inlining function 'main': acir(inline) fn main f0 { b0(): call f0() return } ``` I included the ACIR to help figure out which function is the culprit, in case the name is not enough. ## Additional Context I added a test to show that there is no compilation error or warning for the example program. It would be nice to issue a warning about unconditional recursion like Rust does. I'll try to do that in a followup PR. ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [ ] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --- .../noirc_evaluator/src/ssa/opt/inlining.rs | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index 7843c55da65..0c11a8bee9a 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -291,13 +291,14 @@ impl InlineContext { ) -> Vec { self.recursion_level += 1; + let source_function = &ssa.functions[&id]; + if self.recursion_level > RECURSION_LIMIT { panic!( - "Attempted to recur more than {RECURSION_LIMIT} times during function inlining." + "Attempted to recur more than {RECURSION_LIMIT} times during inlining function '{}': {}", source_function.name(), source_function ); } - let source_function = &ssa.functions[&id]; let mut context = PerFunctionContext::new(self, source_function); let parameters = source_function.parameters(); @@ -967,4 +968,28 @@ mod test { let main = ssa.main(); assert_eq!(main.reachable_blocks().len(), 4); } + + #[test] + #[should_panic( + expected = "Attempted to recur more than 1000 times during inlining function 'main': acir(inline) fn main f0 {" + )] + fn unconditional_recursion() { + // fn main f1 { + // b0(): + // call f1() + // return + // } + let main_id = Id::test_new(0); + let mut builder = FunctionBuilder::new("main".into(), main_id); + + let main = builder.import_function(main_id); + let results = builder.insert_call(main, Vec::new(), vec![]).to_vec(); + builder.terminate_with_return(results); + + let ssa = builder.finish(); + assert_eq!(ssa.functions.len(), 1); + + let inlined = ssa.inline_functions(); + assert_eq!(inlined.functions.len(), 0); + } }