Repository: starkware-libs/cairo (language: rust)

Issue:
bug: stack overflow on closures with outer params
# Bug Report

**Cairo version:**
```
❯ scarb --version
scarb 2.9.2+nightly-2025-02-01 (3a752f93d 2025-02-01)
cairo: 2.9.2 (99f052811)
sierra: 1.6.0
```
The following code:
```
fn main() {
    let outer_var = 42;
    let closure_annotated = |i: u32| -> u32 { i + outer_var };
    println!("closure_annotated: {}", closure_annotated(1));
}
```

fails `scarb cairo-run` with:

```
thread 'scarb compile closures-665rku3l74rb0' has overflowed its stack
fatal runtime error: stack overflow
error: `scarb metadata` exited with error
```


Discussion / hints:
Specifying the outer_var type solves it.

```
fn main() {
    let outer_var = 42_u32;
    let closure_annotated = |i: u32| -> u32 { i + outer_var };
    println!("closure_annotated: {}", closure_annotated(1));
}
```
Mind if I take this issue?
probably not - issues that we need handled right away (such as compiler crashes) are to be taken by the team.
(assuming you don't already have a lot of experience in our repo)

Fix patch:
diff --git a/crates/cairo-lang-semantic/src/types.rs b/crates/cairo-lang-semantic/src/types.rs
index 392695c053d..71faba8790d 100644
--- a/crates/cairo-lang-semantic/src/types.rs
+++ b/crates/cairo-lang-semantic/src/types.rs
@@ -10,7 +10,7 @@ use cairo_lang_syntax::attribute::consts::MUST_USE_ATTR;
 use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
 use cairo_lang_syntax::node::{TypedStablePtr, TypedSyntaxNode, ast};
 use cairo_lang_utils::{Intern, LookupIntern, OptionFrom, define_short_id, try_extract_matches};
-use itertools::Itertools;
+use itertools::{Itertools, chain};
 use num_bigint::BigInt;
 use num_traits::Zero;
 use sha3::{Digest, Keccak256};
@@ -946,7 +946,7 @@ pub fn priv_type_is_var_free(db: &dyn SemanticGroup, ty: TypeId) -> bool {
         // a var free ImplType needs to be rewritten if has impl bounds constraints.
         TypeLongId::ImplType(_) => false,
         TypeLongId::Closure(closure) => {
-            closure.param_tys.iter().all(|param| param.is_var_free(db))
+            chain!(&closure.captured_types, &closure.param_tys).all(|param| param.is_var_free(db))
                 && closure.ret_ty.is_var_free(db)
         }
     }


Test patch:
diff --git a/tests/bug_samples/issue7233.cairo b/tests/bug_samples/issue7233.cairo
new file mode 100644
index 00000000000..0ff6d8083a7
--- /dev/null
+++ b/tests/bug_samples/issue7233.cairo
@@ -0,0 +1,8 @@
+#[test]
+fn stack_overflow() {
+    let outer_var = 42;
+    let closure_annotated = |i: u32| -> u32 {
+        i + outer_var
+    };
+    let _v = closure_annotated(1);
+}
diff --git a/tests/bug_samples/lib.cairo b/tests/bug_samples/lib.cairo
index 2c2d74b0a4e..f380cc9d107 100644
--- a/tests/bug_samples/lib.cairo
+++ b/tests/bug_samples/lib.cairo
@@ -60,6 +60,7 @@ mod issue7071;
 mod issue7083;
 mod issue7095;
 mod issue7155;
+mod issue7233;
 mod loop_break_in_match;
 mod loop_only_change;
 mod partial_param_local;