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

Issue:
bug: compilation panic: cairo-lang-lowering `IndexMap: key not found`
# Bug Report
3e611b5c965cd9882e7476bd72321ac245044ec6
**Cairo version:**

<!-- Please specify commit or tag version. -->

**Current behavior:**
With the changes made in #7094, the code no longer compiles, and panics instead of succeeding (or failing) compilation.
I'm unsure what exactly causes the bug - will try to give a MRE when I can.

related code:
```rust
    #[inline]
    fn count<+Destruct<T>, +Destruct<Self::Item>>(
        self: T,
    ) -> usize {
        let mut self = self;
        Self::fold(ref self, 0_usize, |count, _x| {
            count + 1
        })
    }
```

panic trace:
```
thread '<unnamed>' panicked at crates/cairo-lang-lowering/src/db.rs:399:47:
IndexMap: key not found
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at crates/cairo-lang-lowering/src/db.rs:399:47:
IndexMap: key not found
```


Discussion / hints:

Fix patch:
diff --git a/crates/cairo-lang-lowering/src/ids.rs b/crates/cairo-lang-lowering/src/ids.rs
index a68cf8f625e..9f6fd714227 100644
--- a/crates/cairo-lang-lowering/src/ids.rs
+++ b/crates/cairo-lang-lowering/src/ids.rs
@@ -1,5 +1,7 @@
 use cairo_lang_debug::DebugWithDb;
-use cairo_lang_defs::ids::UnstableSalsaId;
+use cairo_lang_defs::ids::{
+    NamedLanguageElementId, TopLevelLanguageElementId, TraitFunctionId, UnstableSalsaId,
+};
 use cairo_lang_diagnostics::{DiagnosticAdded, DiagnosticNote, Maybe};
 use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
 use cairo_lang_semantic::corelib::panic_destruct_trait_fn;
@@ -7,9 +9,7 @@ use cairo_lang_semantic::items::functions::ImplGenericFunctionId;
 use cairo_lang_semantic::items::imp::ImplLongId;
 use cairo_lang_semantic::{GenericArgumentId, TypeLongId};
 use cairo_lang_syntax::node::{TypedStablePtr, ast};
-use cairo_lang_utils::{
-    Intern, LookupIntern, define_short_id, extract_matches, try_extract_matches,
-};
+use cairo_lang_utils::{Intern, LookupIntern, define_short_id, try_extract_matches};
 use defs::diagnostic_utils::StableLocation;
 use defs::ids::{ExternFunctionId, FreeFunctionId};
 use semantic::items::functions::GenericFunctionId;
@@ -106,12 +106,7 @@ impl ConcreteFunctionWithBodyId {
             ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction {
                 parent: _,
                 key: GeneratedFunctionKey::TraitFunc(function, _),
-            }) => Ok(extract_matches!(
-                function.get_concrete(db.upcast()).generic_function,
-                GenericFunctionId::Impl
-            )
-            .function
-                == panic_destruct_trait_fn(db.upcast())),
+            }) => Ok(function == panic_destruct_trait_fn(db.upcast())),
             _ => Ok(false),
         }
     }
@@ -287,7 +282,7 @@ impl FunctionLongId {
                         return Ok(Some(
                             GeneratedFunction {
                                 parent,
-                                key: GeneratedFunctionKey::TraitFunc(id, ty.wrapper_location),
+                                key: GeneratedFunctionKey::TraitFunc(function, ty.wrapper_location),
                             }
                             .body(db),
                         ));
@@ -385,7 +380,7 @@ impl<'a> DebugWithDb<dyn LoweringGroup + 'a> for FunctionLongId {
 pub enum GeneratedFunctionKey {
     /// Generated loop functions are identified by the loop expr_id.
     Loop(semantic::ExprId),
-    TraitFunc(semantic::FunctionId, StableLocation),
+    TraitFunc(TraitFunctionId, StableLocation),
 }
 
 /// Generated function.
@@ -396,17 +391,11 @@ pub struct GeneratedFunction {
 }
 impl GeneratedFunction {
     pub fn body(&self, db: &dyn LoweringGroup) -> ConcreteFunctionWithBodyId {
-        let GeneratedFunction { parent, key } = *self;
-        let long_id = ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction { parent, key });
+        let long_id = ConcreteFunctionWithBodyLongId::Generated(*self);
         long_id.intern(db)
     }
     pub fn full_path(&self, db: &dyn LoweringGroup) -> String {
-        match self.key {
-            GeneratedFunctionKey::Loop(expr_id) => {
-                format!("{}[expr{}]", self.parent.full_path(db.upcast()), expr_id.index())
-            }
-            GeneratedFunctionKey::TraitFunc(trait_func, _) => trait_func.full_path(db.upcast()),
-        }
+        format!("{:?}", self.debug(db))
     }
 }
 impl<'a> DebugWithDb<dyn LoweringGroup + 'a> for GeneratedFunction {
@@ -419,8 +408,15 @@ impl<'a> DebugWithDb<dyn LoweringGroup + 'a> for GeneratedFunction {
             GeneratedFunctionKey::Loop(expr_id) => {
                 write!(f, "{:?}[expr{}]", self.parent.debug(db), expr_id.index())
             }
-            GeneratedFunctionKey::TraitFunc(trait_func, _) => {
-                write!(f, "{:?}", trait_func.debug(db))
+            GeneratedFunctionKey::TraitFunc(trait_func, loc) => {
+                let trait_id = trait_func.trait_id(db.upcast());
+                write!(
+                    f,
+                    "Generated `{}::{}` for {{closure@{:?}}}",
+                    trait_id.full_path(db.upcast()),
+                    trait_func.name(db.upcast()),
+                    loc.debug(db.upcast()),
+                )
             }
         }
     }
diff --git a/crates/cairo-lang-lowering/src/lower/mod.rs b/crates/cairo-lang-lowering/src/lower/mod.rs
index 895394ce2a4..605120b707f 100644
--- a/crates/cairo-lang-lowering/src/lower/mod.rs
+++ b/crates/cairo-lang-lowering/src/lower/mod.rs
@@ -1719,7 +1719,7 @@ fn add_capture_destruct_impl(
     let signature =
         Signature::from_semantic(ctx.db, semantic_db.concrete_function_signature(function)?);
 
-    let func_key = GeneratedFunctionKey::TraitFunc(function, location);
+    let func_key = GeneratedFunctionKey::TraitFunc(trait_function, location);
     let function_id =
         FunctionWithBodyLongId::Generated { parent: ctx.semantic_function_id, key: func_key }
             .intern(ctx.db);
@@ -1824,7 +1824,7 @@ fn add_closure_call_function(
     .intern(semantic_db);
     let function_with_body_id = FunctionWithBodyLongId::Generated {
         parent: encapsulated_ctx.semantic_function_id,
-        key: GeneratedFunctionKey::TraitFunc(function, closure_ty.wrapper_location),
+        key: GeneratedFunctionKey::TraitFunc(trait_function, closure_ty.wrapper_location),
     }
     .intern(encapsulated_ctx.db);
     let signature = Signature::from_semantic(
@@ -1909,9 +1909,10 @@ fn add_closure_call_function(
         signature: ctx.signature.clone(),
         parameters,
     };
-    encapsulated_ctx
-        .lowerings
-        .insert(GeneratedFunctionKey::TraitFunc(function, closure_ty.wrapper_location), lowered);
+    encapsulated_ctx.lowerings.insert(
+        GeneratedFunctionKey::TraitFunc(trait_function, closure_ty.wrapper_location),
+        lowered,
+    );
     Ok(())
 }
 


Test patch:
diff --git a/crates/cairo-lang-lowering/src/borrow_check/test_data/closure b/crates/cairo-lang-lowering/src/borrow_check/test_data/closure
index d4e2dfa9c55..ec1f3980e04 100644
--- a/crates/cairo-lang-lowering/src/borrow_check/test_data/closure
+++ b/crates/cairo-lang-lowering/src/borrow_check/test_data/closure
@@ -275,7 +275,7 @@ Statements:
   (v2: {closure@lib.cairo:3:13: 3:16}, v3: @{closure@lib.cairo:3:13: 3:16}) <- snapshot(v1{`c`})
   (v4: core::felt252) <- 2
   (v5: (core::felt252,)) <- struct_construct(v4{`2`})
-  (v6: core::felt252) <- Generated core::ops::function::Fn::<{closure@lib.cairo:3:13: 3:16}, (core::felt252,)>::call(v3{`c`}, v5{`c(2)`})
+  (v6: core::felt252) <- Generated `core::ops::function::Fn::call` for {closure@lib.cairo:3:13: 3:16}(v3{`c`}, v5{`c(2)`})
   (v7: core::felt252) <- core::Felt252Add::add(v6{`y`}, v0{`x`})
 End:
   Return(v7)
@@ -318,7 +318,7 @@ Statements:
   (v7: {closure@lib.cairo:3:13: 3:16}, v8: @{closure@lib.cairo:3:13: 3:16}) <- snapshot(v6{`c`})
   (v9: core::integer::u32) <- 2
   (v10: (core::integer::u32,)) <- struct_construct(v9{`2`})
-  (v11: core::integer::u32) <- Generated core::ops::function::Fn::<{closure@lib.cairo:3:13: 3:16}, (core::integer::u32,)>::call(v8{`c`}, v10{`c(2)`})
+  (v11: core::integer::u32) <- Generated `core::ops::function::Fn::call` for {closure@lib.cairo:3:13: 3:16}(v8{`c`}, v10{`c(2)`})
   (v12: core::array::Array::<core::felt252>, v13: @core::array::Array::<core::felt252>) <- snapshot(v4{`x`})
   (v14: core::integer::u32) <- 0
   (v15: @core::felt252) <- core::ops::index::DeprecatedIndexViewImpl::<core::array::Array::<core::felt252>, core::integer::u32, @core::felt252, core::array::ArrayIndex::<core::felt252>>::index(v13{`x`}, v14{`0`})
diff --git a/crates/cairo-lang-lowering/src/lower/generated_test.rs b/crates/cairo-lang-lowering/src/lower/generated_test.rs
index 3cce4487971..6efba3da8fe 100644
--- a/crates/cairo-lang-lowering/src/lower/generated_test.rs
+++ b/crates/cairo-lang-lowering/src/lower/generated_test.rs
@@ -3,11 +3,10 @@ use std::fmt::Write;
 use cairo_lang_debug::DebugWithDb;
 use cairo_lang_defs::ids::TopLevelLanguageElementId;
 use cairo_lang_diagnostics::get_location_marks;
-use cairo_lang_semantic::items::functions::GenericFunctionId;
 use cairo_lang_semantic::test_utils::setup_test_function;
 use cairo_lang_test_utils::parse_test_file::TestRunnerResult;
+use cairo_lang_utils::Intern;
 use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
-use cairo_lang_utils::{Intern, LookupIntern, extract_matches};
 
 use crate::db::LoweringGroup;
 use crate::fmt::LoweredFormatter;
@@ -73,12 +72,7 @@ fn test_generated_function(
 
             let func_description = match key {
                 crate::ids::GeneratedFunctionKey::Loop(_) => "loop".into(),
-                crate::ids::GeneratedFunctionKey::TraitFunc(func, _) => extract_matches!(
-                    func.lookup_intern(db).function.generic_function,
-                    GenericFunctionId::Impl
-                )
-                .function
-                .full_path(db),
+                crate::ids::GeneratedFunctionKey::TraitFunc(func, _) => func.full_path(db),
             };
 
             writeln!(
diff --git a/crates/cairo-lang-lowering/src/lower/test_data/closure b/crates/cairo-lang-lowering/src/lower/test_data/closure
index 4f93940c588..e29e40ca781 100644
--- a/crates/cairo-lang-lowering/src/lower/test_data/closure
+++ b/crates/cairo-lang-lowering/src/lower/test_data/closure
@@ -338,7 +338,7 @@ Statements:
   (v2: {closure@lib.cairo:2:13: 2:25}, v3: @{closure@lib.cairo:2:13: 2:25}) <- snapshot(v1)
   (v4: core::felt252) <- 0
   (v5: (core::felt252,)) <- struct_construct(v4)
-  (v6: ()) <- Generated core::ops::function::Fn::<{closure@lib.cairo:2:13: 2:25}, (core::felt252,)>::call(v3, v5)
+  (v6: ()) <- Generated `core::ops::function::Fn::call` for {closure@lib.cairo:2:13: 2:25}(v3, v5)
   (v7: ()) <- struct_construct()
 End:
   Return(v7)
diff --git a/tests/bug_samples/issue7095.cairo b/tests/bug_samples/issue7095.cairo
new file mode 100644
index 00000000000..3922fa7a29d
--- /dev/null
+++ b/tests/bug_samples/issue7095.cairo
@@ -0,0 +1,17 @@
+trait MyTrait<T> {
+    fn consume<B, F, +core::ops::Fn<F, (T,)>[Output: B], +Destruct<F>>(
+        self: T, f: F,
+    ) -> B {
+        f(self)
+    }
+    fn user<+Destruct<T>>(self: T) -> usize {
+        Self::consume(self, |_v| 1)
+    }
+}
+
+impl MyImpl<T> of MyTrait<T> {}
+
+#[test]
+fn test_call() {
+    MyTrait::<u8>::user(0);
+}
diff --git a/tests/bug_samples/lib.cairo b/tests/bug_samples/lib.cairo
index 9d035b98434..9ecbf9a3e14 100644
--- a/tests/bug_samples/lib.cairo
+++ b/tests/bug_samples/lib.cairo
@@ -58,6 +58,7 @@ mod issue7038;
 mod issue7060;
 mod issue7071;
 mod issue7083;
+mod issue7095;
 mod loop_break_in_match;
 mod loop_only_change;
 mod partial_param_local;