From 7a5f5b7bd79f592a523f25a9a63643deb3ed8c8c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 30 Jul 2026 13:05:56 +0000 Subject: [PATCH] fix(semantic): add salsa cycle recovery to the item generic-params queries Follow-up to #10268, which fixed enum_definition_data. Seven sibling queries had the same gap and each panicked with its own cycle head: struct_generic_params_data, enum_generic_params_data, free_function_generic_params_data, extern_function_declaration_generic_params_data, impl_def_generic_params_data, module_type_alias_generic_params_data, priv_trait_function_generic_params_data The trigger needs no malformed input, contrary to how the original was described. `E::A!(());` is well-formed item-level macro syntax whose path names ::; combined with any generic item carrying a trait bound, the macro-call expansion resolves the enum, the enum resolves a variant type, and that re-enters whichever generic-params query is already on the stack. The re-entered query need not be reachable from priv_macro_call_data at all - it only has to be on the stack. One generic handler pair in generics.rs serves all seven, with salsa inferring the key type, rather than fourteen near-identical functions. Use the fixpoint shape - cycle_fn returns the computed value, not the provisional. Measured on these goldens, the provisional shape is worse than just losing information: five of seven change, it drops E2028 and (for extern fns) E2165, and for struct/enum it invents a spurious E2006 "Unknown type". Convergence measured per key via Cycle::iteration(): at most 3 iterations, against MAX_ITERATIONS 200. Also guard module_type_alias_semantic_data_cycle. It recovers by re-calling module_type_alias_semantic_data(id, true), but that body reads module_type_alias_generic_params_data before branching on in_cycle, so once that query recovers, the handler re-enters itself and stack-overflows. Without the guard this change trades an ICE for a worse one. The guard is inert for genuine alias cycles - it fires only on re-entry of the in_cycle key. The guard leaves module_type_alias_semantic_data(id, false) as Err in this scenario, which module_type_alias_semantic_diagnostics mapped to no diagnostics, dropping the alias's own E2028 (caught by Cursor Bugbot). Its Err path now falls back to the generic-params diagnostics, which no other query surfaces; the type_alias golden now shows E2028 like the sibling item kinds. impl_alias_semantic_data has the same unsafe shape and is latent only because impl_alias_generic_params_data still lacks recovery; adding it there later must guard that handler too. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01E43saQzYdQ7UC9UyyGx5Sr --- crates/cairo-lang-semantic/src/items/enm.rs | 7 ++- .../src/items/extern_function.rs | 7 ++- .../src/items/free_function.rs | 7 ++- .../cairo-lang-semantic/src/items/generics.rs | 39 +++++++++++++++++ crates/cairo-lang-semantic/src/items/imp.rs | 5 ++- .../src/items/module_type_alias.rs | 30 +++++++++---- .../src/items/structure.rs | 7 ++- crates/cairo-lang-semantic/src/items/test.rs | 1 + .../cairo-lang-semantic/src/items/tests/enum | 33 ++++++++++++++ .../src/items/tests/extern_func | 37 ++++++++++++++++ .../src/items/tests/free_function | 31 +++++++++++++ .../src/items/tests/impl_def | 43 +++++++++++++++++++ .../src/items/tests/struct | 33 ++++++++++++++ .../cairo-lang-semantic/src/items/tests/trait | 38 ++++++++++++++++ .../src/items/tests/type_alias | 31 +++++++++++++ crates/cairo-lang-semantic/src/items/trt.rs | 5 ++- 16 files changed, 334 insertions(+), 20 deletions(-) create mode 100644 crates/cairo-lang-semantic/src/items/tests/impl_def diff --git a/crates/cairo-lang-semantic/src/items/enm.rs b/crates/cairo-lang-semantic/src/items/enm.rs index 54b15bb216c..bbbc9c68456 100644 --- a/crates/cairo-lang-semantic/src/items/enm.rs +++ b/crates/cairo-lang-semantic/src/items/enm.rs @@ -14,7 +14,10 @@ use cairo_lang_utils::ordered_hash_map::{Entry, OrderedHashMap}; use salsa::Database; use super::attribute::SemanticQueryAttrs; -use super::generics::{GenericParamsData, semantic_generic_params}; +use super::generics::{ + GenericParamsData, generic_params_data_cycle, generic_params_data_initial, + semantic_generic_params, +}; use crate::corelib::unit_ty; use crate::diagnostic::SemanticDiagnosticKind::*; use crate::diagnostic::{SemanticDiagnostics, SemanticDiagnosticsBuilder}; @@ -70,7 +73,7 @@ fn enum_declaration_data<'db>( } /// Returns the generic parameters data of an enum. -#[salsa::tracked(returns(ref))] +#[salsa::tracked(returns(ref), cycle_fn=generic_params_data_cycle, cycle_initial=generic_params_data_initial)] fn enum_generic_params_data<'db>( db: &'db dyn Database, enum_id: EnumId<'db>, diff --git a/crates/cairo-lang-semantic/src/items/extern_function.rs b/crates/cairo-lang-semantic/src/items/extern_function.rs index ddf004bb3bc..bd25173c7fc 100644 --- a/crates/cairo-lang-semantic/src/items/extern_function.rs +++ b/crates/cairo-lang-semantic/src/items/extern_function.rs @@ -13,7 +13,10 @@ use salsa::Database; use super::function_with_body::get_inline_config; use super::functions::{FunctionDeclarationData, GenericFunctionId, InlineConfiguration}; -use super::generics::{GenericParamsData, semantic_generic_params}; +use super::generics::{ + GenericParamsData, generic_params_data_cycle, generic_params_data_initial, + semantic_generic_params, +}; use super::report_extern_item_outside_corelib; use crate::corelib::get_core_generic_function_id; use crate::diagnostic::SemanticDiagnosticKind::*; @@ -33,7 +36,7 @@ mod test; /// Query implementation of /// [ExternFunctionSemantic::extern_function_declaration_generic_params_data]. -#[salsa::tracked(returns(ref))] +#[salsa::tracked(returns(ref), cycle_fn=generic_params_data_cycle, cycle_initial=generic_params_data_initial)] fn extern_function_declaration_generic_params_data<'db>( db: &'db dyn Database, extern_function_id: ExternFunctionId<'db>, diff --git a/crates/cairo-lang-semantic/src/items/free_function.rs b/crates/cairo-lang-semantic/src/items/free_function.rs index b7099633ec2..5c99c5d2093 100644 --- a/crates/cairo-lang-semantic/src/items/free_function.rs +++ b/crates/cairo-lang-semantic/src/items/free_function.rs @@ -16,7 +16,10 @@ use super::functions::{ FunctionDeclarationData, GenericFunctionId, InlineConfiguration, forbid_inline_always_with_impl_generic_param, }; -use super::generics::{GenericParamsData, semantic_generic_params}; +use super::generics::{ + GenericParamsData, generic_params_data_cycle, generic_params_data_initial, + semantic_generic_params, +}; use crate::diagnostic::SemanticDiagnostics; use crate::expr::compute::{ComputationContext, ContextFunction, Environment, compute_root_expr}; use crate::expr::inference::InferenceId; @@ -32,7 +35,7 @@ use crate::{FunctionLongId, GenericParam, SemanticDiagnostic, semantic}; mod test; /// Returns the generic params data of a free function. -#[salsa::tracked(returns(ref))] +#[salsa::tracked(returns(ref), cycle_fn=generic_params_data_cycle, cycle_initial=generic_params_data_initial)] fn free_function_generic_params_data<'db>( db: &'db dyn Database, free_function_id: FreeFunctionId<'db>, diff --git a/crates/cairo-lang-semantic/src/items/generics.rs b/crates/cairo-lang-semantic/src/items/generics.rs index c6f0122724a..15cf9f062fd 100644 --- a/crates/cairo-lang-semantic/src/items/generics.rs +++ b/crates/cairo-lang-semantic/src/items/generics.rs @@ -281,6 +281,45 @@ pub struct GenericParamsData<'db> { pub resolver_data: Arc>, } +/// Cycle handling for the `*_generic_params_data` queries. +/// +/// Example cycle, given `struct W>` and an item-level macro call `E::A!(());` where +/// variant `E::A`'s type is `W`: +/// `W`'s generic params -> resolving `+Drop` -> the module's items -> expanding `E::A!` +/// (`priv_macro_call_data`) -> resolving the path `E::A` -> `E`'s variants -> the variant's type +/// `W` -> `W`'s generic params. +/// +/// Returning the freshly computed `value` lets salsa fixpoint-iterate, so the memoized result is +/// the real computation and the item's own diagnostics survive. Returning the last provisional +/// value instead would freeze the query at [generic_params_data_initial] and silently drop them. +/// +/// The computed value depends only on whether the re-entrant read saw the initial `Err` or a real +/// value, so the fixpoint is reached within 3 iterations (verified on the goldens via +/// `Cycle::iteration()`, against salsa's `MAX_ITERATIONS` of 200): +/// initial `Err` -> value computed against that `Err` -> value computed against a real value -> +/// unchanged. +pub fn generic_params_data_cycle<'db, TKey>( + _db: &'db dyn Database, + _cycle: &salsa::Cycle<'_>, + _last_provisional_value: &Maybe>, + value: Maybe>, + _key: TKey, +) -> Maybe> { + value +} + +/// The provisional value seen by the query that re-enters a `*_generic_params_data` query. +/// +/// See [generic_params_data_cycle]. `skip_diagnostic` avoids reporting the cycle itself - what +/// actually went wrong is reported by the queries participating in it. +pub fn generic_params_data_initial<'db, TKey>( + _db: &'db dyn Database, + _id: salsa::Id, + _key: TKey, +) -> Maybe> { + Err(skip_diagnostic()) +} + /// Query implementation of [GenericsSemantic::generic_impl_param_trait]. #[salsa::tracked(returns(copy))] fn generic_impl_param_trait<'db>( diff --git a/crates/cairo-lang-semantic/src/items/imp.rs b/crates/cairo-lang-semantic/src/items/imp.rs index 7ab3d099965..b6e740c2014 100644 --- a/crates/cairo-lang-semantic/src/items/imp.rs +++ b/crates/cairo-lang-semantic/src/items/imp.rs @@ -50,7 +50,8 @@ use super::functions::{ }; use super::generics::{ GenericArgumentHead, GenericParamImpl, GenericParamsData, displayable_concrete, - generic_params_to_args, semantic_generic_params, + generic_params_data_cycle, generic_params_data_initial, generic_params_to_args, + semantic_generic_params, }; use super::impl_alias::{ ImplAliasData, impl_alias_generic_params_data_helper, impl_alias_semantic_data_cycle_helper, @@ -483,7 +484,7 @@ struct ImplDeclarationData<'db> { } /// Returns the generic parameters data of an impl definition. -#[salsa::tracked(returns(ref))] +#[salsa::tracked(returns(ref), cycle_fn=generic_params_data_cycle, cycle_initial=generic_params_data_initial)] fn impl_def_generic_params_data<'db>( db: &'db dyn Database, impl_def_id: ImplDefId<'db>, diff --git a/crates/cairo-lang-semantic/src/items/module_type_alias.rs b/crates/cairo-lang-semantic/src/items/module_type_alias.rs index 49d76d4fbf9..7aed63b6a8e 100644 --- a/crates/cairo-lang-semantic/src/items/module_type_alias.rs +++ b/crates/cairo-lang-semantic/src/items/module_type_alias.rs @@ -2,11 +2,11 @@ use std::sync::Arc; use cairo_lang_defs::db::DefsGroup; use cairo_lang_defs::ids::{LanguageElementId, LookupItemId, ModuleItemId, ModuleTypeAliasId}; -use cairo_lang_diagnostics::{Diagnostics, Maybe, MaybeAsRef, ToMaybe}; +use cairo_lang_diagnostics::{Diagnostics, Maybe, MaybeAsRef, ToMaybe, skip_diagnostic}; use cairo_lang_proc_macros::DebugWithDb; use salsa::Database; -use super::generics::GenericParamsData; +use super::generics::{GenericParamsData, generic_params_data_cycle, generic_params_data_initial}; use super::type_aliases::{ TypeAliasData, type_alias_generic_params_data_helper, type_alias_semantic_data_cycle_helper, type_alias_semantic_data_helper, @@ -67,13 +67,20 @@ fn module_type_alias_semantic_data_cycle<'db>( db: &'db dyn Database, _id: salsa::Id, module_type_alias_id: ModuleTypeAliasId<'db>, - _in_cycle: bool, + in_cycle: bool, ) -> Maybe> { + if in_cycle { + // The `in_cycle` variant reads `module_type_alias_generic_params_data` before it branches + // on `in_cycle`, so it can itself be the query the cycle is detected on. Recovering by + // calling it again would re-enter this handler forever, so stop here - what went wrong is + // reported by the queries participating in the cycle. + return Err(skip_diagnostic()); + } module_type_alias_semantic_data(db, module_type_alias_id, true).clone() } /// Returns the generic parameters data of a type alias. -#[salsa::tracked(returns(ref))] +#[salsa::tracked(returns(ref), cycle_fn=generic_params_data_cycle, cycle_initial=generic_params_data_initial)] fn module_type_alias_generic_params_data<'db>( db: &'db dyn Database, module_type_alias_id: ModuleTypeAliasId<'db>, @@ -92,10 +99,17 @@ pub trait ModuleTypeAliasSemantic<'db>: Database { &'db self, id: ModuleTypeAliasId<'db>, ) -> Diagnostics<'db, SemanticDiagnostic<'db>> { - module_type_alias_semantic_data(self.as_dyn_database(), id, false) - .as_ref() - .map(|data| data.diagnostics.clone()) - .unwrap_or_default() + let db = self.as_dyn_database(); + match module_type_alias_semantic_data(db, id, false) { + Ok(data) => data.diagnostics.clone(), + // The data computation fails without reporting the generic params diagnostics - e.g. + // when recovering from a cycle through the alias's generic params - so fall back to + // them, as no other query surfaces them. + Err(_) => module_type_alias_generic_params_data(db, id) + .as_ref() + .map(|data| data.diagnostics.clone()) + .unwrap_or_default(), + } } /// Returns the resolved type of a type alias. fn module_type_alias_resolved_type( diff --git a/crates/cairo-lang-semantic/src/items/structure.rs b/crates/cairo-lang-semantic/src/items/structure.rs index 94c822540cd..dc7eab7bf41 100644 --- a/crates/cairo-lang-semantic/src/items/structure.rs +++ b/crates/cairo-lang-semantic/src/items/structure.rs @@ -14,7 +14,10 @@ use cairo_lang_utils::ordered_hash_map::{Entry, OrderedHashMap}; use salsa::Database; use super::attribute::SemanticQueryAttrs; -use super::generics::{GenericParamsData, semantic_generic_params}; +use super::generics::{ + GenericParamsData, generic_params_data_cycle, generic_params_data_initial, + semantic_generic_params, +}; use super::visibility::Visibility; use crate::diagnostic::SemanticDiagnosticKind::*; use crate::diagnostic::{SemanticDiagnostics, SemanticDiagnosticsBuilder}; @@ -72,7 +75,7 @@ fn struct_declaration_data<'db>( } /// Query implementation of [StructSemantic::struct_generic_params_data]. -#[salsa::tracked(returns(ref))] +#[salsa::tracked(returns(ref), cycle_fn=generic_params_data_cycle, cycle_initial=generic_params_data_initial)] fn struct_generic_params_data<'db>( db: &'db dyn Database, struct_id: StructId<'db>, diff --git a/crates/cairo-lang-semantic/src/items/test.rs b/crates/cairo-lang-semantic/src/items/test.rs index 1c2c576f3cf..e6b21afb6b9 100644 --- a/crates/cairo-lang-semantic/src/items/test.rs +++ b/crates/cairo-lang-semantic/src/items/test.rs @@ -8,6 +8,7 @@ cairo_lang_test_utils::test_file_test!( extern_func: "extern_func", free_function: "free_function", impl_alias: "impl_alias", + impl_def: "impl_def", panicable: "panicable", struct_: "struct", trait_: "trait", diff --git a/crates/cairo-lang-semantic/src/items/tests/enum b/crates/cairo-lang-semantic/src/items/tests/enum index 35d96f1478f..cfb84f9ab65 100644 --- a/crates/cairo-lang-semantic/src/items/tests/enum +++ b/crates/cairo-lang-semantic/src/items/tests/enum @@ -229,3 +229,36 @@ error[E2156]: Inline macro `MyEnum::A` not found. --> lib.cairo:4:1 MyEnum::A(()); ^^^^^^^^^^^^^^ + +//! > ========================================================================== + +//! > Test no ICE when an item-level macro call names an enum variant whose type is a generic enum with a trait bound. + +//! > test_runner_name +test_function_diagnostics(expect_diagnostics: true) + +//! > function_code +fn foo() {} + +//! > function_name +foo + +//! > module_code +enum W> { + X: T, +} +enum E { + A: W, +} +E::A!(()); + +//! > expected_diagnostics +error[E2028]: Cycle detected while resolving generic param. Try specifying the generic impl parameter explicitly to break the cycle. + --> lib.cairo:1:11 +enum W> { + ^^^^^^^^ + +error[E2156]: Inline macro `E::A` not found. + --> lib.cairo:7:1 +E::A!(()); +^^^^^^^^^^ diff --git a/crates/cairo-lang-semantic/src/items/tests/extern_func b/crates/cairo-lang-semantic/src/items/tests/extern_func index 45c999c4e3b..28a4ccb1563 100644 --- a/crates/cairo-lang-semantic/src/items/tests/extern_func +++ b/crates/cairo-lang-semantic/src/items/tests/extern_func @@ -27,3 +27,40 @@ error[E2116]: An extern function must be marked as nopanic. _^ | extern fn bar() -> bad_type; |____________________________^ + +//! > ========================================================================== + +//! > Test no ICE when an item-level macro call names an enum variant whose type comes from a generic extern function with a trait bound. + +//! > test_runner_name +test_function_diagnostics(expect_diagnostics: true) + +//! > function_code +fn foo() {} + +//! > function_name +foo + +//! > module_code +#[allow(extern_outside_corelib)] +extern fn g>(x: T) nopanic; +enum E { + A: g::::Coupon, +} +E::A!(()); + +//! > expected_diagnostics +error[E2028]: Cycle detected while resolving generic param. Try specifying the generic impl parameter explicitly to break the cycle. + --> lib.cairo:2:16 +extern fn g>(x: T) nopanic; + ^^^^^^^^ + +error[E2165]: Coupon cannot be used with extern functions. + --> lib.cairo:4:22 + A: g::::Coupon, + ^^^^^^ + +error[E2156]: Inline macro `E::A` not found. + --> lib.cairo:6:1 +E::A!(()); +^^^^^^^^^^ diff --git a/crates/cairo-lang-semantic/src/items/tests/free_function b/crates/cairo-lang-semantic/src/items/tests/free_function index ae1b34d0b09..69f86c9f025 100644 --- a/crates/cairo-lang-semantic/src/items/tests/free_function +++ b/crates/cairo-lang-semantic/src/items/tests/free_function @@ -53,3 +53,34 @@ error[E2310]: Failed to infer constant. --> lib.cairo:3:5 bar(a) ^^^ + +//! > ========================================================================== + +//! > Test no ICE when an item-level macro call names an enum variant whose type comes from a generic free function with a trait bound. + +//! > test_runner_name +test_function_diagnostics(expect_diagnostics: true) + +//! > function_code +fn foo() {} + +//! > function_name +foo + +//! > module_code +fn g>(x: T) {} +enum E { + A: g::::Coupon, +} +E::A!(()); + +//! > expected_diagnostics +error[E2028]: Cycle detected while resolving generic param. Try specifying the generic impl parameter explicitly to break the cycle. + --> lib.cairo:1:9 +fn g>(x: T) {} + ^^^^^^^^ + +error[E2156]: Inline macro `E::A` not found. + --> lib.cairo:5:1 +E::A!(()); +^^^^^^^^^^ diff --git a/crates/cairo-lang-semantic/src/items/tests/impl_def b/crates/cairo-lang-semantic/src/items/tests/impl_def new file mode 100644 index 00000000000..b73d9820a9d --- /dev/null +++ b/crates/cairo-lang-semantic/src/items/tests/impl_def @@ -0,0 +1,43 @@ +//! > Test no ICE when an item-level macro call names an enum variant whose type comes from a generic impl with a trait bound. + +//! > test_runner_name +test_function_diagnostics(expect_diagnostics: true) + +//! > function_code +fn foo() {} + +//! > function_name +foo + +//! > module_code +trait Tr { + type Ty; +} +impl W> of Tr { + type Ty = T; +} +enum E { + A: Tr::::Ty, +} +E::A!(()); + +//! > expected_diagnostics +error[E2028]: Cycle detected while resolving generic param. Try specifying the generic impl parameter explicitly to break the cycle. + --> lib.cairo:4:24 +impl W> of Tr { + ^^^^^ + +error[E2028]: Cycle detected while resolving generic param. Try specifying the generic impl parameter explicitly to break the cycle. + --> lib.cairo:4:11 +impl W> of Tr { + ^^^^^^^^ + +error[E2301]: Inference cycle detected + --> lib.cairo:8:23 + A: Tr::::Ty, + ^^ + +error[E2156]: Inline macro `E::A` not found. + --> lib.cairo:10:1 +E::A!(()); +^^^^^^^^^^ diff --git a/crates/cairo-lang-semantic/src/items/tests/struct b/crates/cairo-lang-semantic/src/items/tests/struct index f873a9fa238..ceba9a428bc 100644 --- a/crates/cairo-lang-semantic/src/items/tests/struct +++ b/crates/cairo-lang-semantic/src/items/tests/struct @@ -137,3 +137,36 @@ error[E2053]: Cannot have array of type "((), ())" that is zero sized. --> lib.cairo:2:5 member: Array<((), ())>, ^^^^^^^^^^^^^^^^^^^^^^^ + +//! > ========================================================================== + +//! > Test no ICE when an item-level macro call names an enum variant whose type is a generic struct with a trait bound. + +//! > test_runner_name +test_function_diagnostics(expect_diagnostics: true) + +//! > function_code +fn foo() {} + +//! > function_name +foo + +//! > module_code +struct W> { + x: T, +} +enum E { + A: W, +} +E::A!(()); + +//! > expected_diagnostics +error[E2028]: Cycle detected while resolving generic param. Try specifying the generic impl parameter explicitly to break the cycle. + --> lib.cairo:1:13 +struct W> { + ^^^^^^^^ + +error[E2156]: Inline macro `E::A` not found. + --> lib.cairo:7:1 +E::A!(()); +^^^^^^^^^^ diff --git a/crates/cairo-lang-semantic/src/items/tests/trait b/crates/cairo-lang-semantic/src/items/tests/trait index 93fcc6d3a33..df693de42aa 100644 --- a/crates/cairo-lang-semantic/src/items/tests/trait +++ b/crates/cairo-lang-semantic/src/items/tests/trait @@ -1397,3 +1397,41 @@ error[E2031]: Parameter type of impl function `I::foo` is incompatible with `Tr: --> lib.cairo:6:15 fn foo() {} ^^^^^^^^^^^^ + +//! > ========================================================================== + +//! > Test no ICE when an item-level macro call names an enum variant whose type comes from a generic trait function with a trait bound. + +//! > test_runner_name +test_function_diagnostics(expect_diagnostics: true) + +//! > function_code +fn foo() {} + +//! > function_name +foo + +//! > module_code +trait Tr { + fn g>(x: S); +} +enum E { + A: Tr::g::::Coupon, +} +E::A!(()); + +//! > expected_diagnostics +error[E2028]: Cycle detected while resolving generic param. Try specifying the generic impl parameter explicitly to break the cycle. + --> lib.cairo:2:13 + fn g>(x: S); + ^^^^^^^^ + +error[E2301]: Inference cycle detected + --> lib.cairo:5:12 + A: Tr::g::::Coupon, + ^ + +error[E2156]: Inline macro `E::A` not found. + --> lib.cairo:7:1 +E::A!(()); +^^^^^^^^^^ diff --git a/crates/cairo-lang-semantic/src/items/tests/type_alias b/crates/cairo-lang-semantic/src/items/tests/type_alias index 383d75c04ab..f85419423a1 100644 --- a/crates/cairo-lang-semantic/src/items/tests/type_alias +++ b/crates/cairo-lang-semantic/src/items/tests/type_alias @@ -234,3 +234,34 @@ error[E0006]: Type not found. --> lib.cairo:1:14 type Alias = bad_type; ^^^^^^^^ + +//! > ========================================================================== + +//! > Test no ICE when an item-level macro call names an enum variant whose type is a generic type alias with a trait bound. + +//! > test_runner_name +test_function_diagnostics(expect_diagnostics: true) + +//! > function_code +fn foo() {} + +//! > function_name +foo + +//! > module_code +type W> = T; +enum E { + A: W, +} +E::A!(()); + +//! > expected_diagnostics +error[E2028]: Cycle detected while resolving generic param. Try specifying the generic impl parameter explicitly to break the cycle. + --> lib.cairo:1:11 +type W> = T; + ^^^^^^^^ + +error[E2156]: Inline macro `E::A` not found. + --> lib.cairo:5:1 +E::A!(()); +^^^^^^^^^^ diff --git a/crates/cairo-lang-semantic/src/items/trt.rs b/crates/cairo-lang-semantic/src/items/trt.rs index 49841b53a83..0fe88dc6bf5 100644 --- a/crates/cairo-lang-semantic/src/items/trt.rs +++ b/crates/cairo-lang-semantic/src/items/trt.rs @@ -29,7 +29,8 @@ use super::functions::{ InlineConfiguration, }; use super::generics::{ - GenericParamsData, displayable_concrete, generic_params_to_args, semantic_generic_params, + GenericParamsData, displayable_concrete, generic_params_data_cycle, + generic_params_data_initial, generic_params_to_args, semantic_generic_params, semantic_generic_params_ex, }; use super::imp::{GenericsHeadFilter, ImplLongId, TraitFilter}; @@ -939,7 +940,7 @@ fn concrete_trait_impl_concrete_trait_tracked<'db>( // === Trait function Declaration === /// Query implementation of [TraitSemantic::priv_trait_function_generic_params_data]. -#[salsa::tracked(returns(ref))] +#[salsa::tracked(returns(ref), cycle_fn=generic_params_data_cycle, cycle_initial=generic_params_data_initial)] fn priv_trait_function_generic_params_data<'db>( db: &'db dyn Database, trait_function_id: TraitFunctionId<'db>,