Sitelet https://github.com/starkware-libs/cairo/pull/10175
Skip to content

bugfix(semantic): Detect non-instantiable array elements nested in a type. - #10175

Merged
orizi merged 1 commit into
mainfrom
orizi/06-29-bugfix_semantic_detect_non-instantiable_array_elements_nested_in_a_type
Jun 30, 2026
Merged

orizi merged 1 commit into
mainfrom
orizi/06-29-bugfix_semantic_detect_non-instantiable_array_elements_nested_in_a_type

Conversation

@orizi

@orizi orizi commented Jun 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Extends the phantom-type and zero-sized-array diagnostic checks to cover types that transitively contain a bad Array element, rather than only catching a direct Array<Ph> or Array<()>. For example, Span<Ph> (which wraps Array<Ph>) and mutually-recursive struct chains that eventually reach a phantom array element are now diagnosed correctly.

The core change introduces a new array_element_violation salsa-tracked query that walks the full type structure — structs, enums, tuples, snapshots, fixed-size arrays, closures, Box/Nullable wrappers — looking for an Array whose element is phantom or zero-sized. A dedicated cycle handler (array_element_violation_cycle) is added to handle types that are recursive through an array element (e.g. struct A { a: Array<A> }), using an explicit work-stack with a visited set to avoid salsa caching false negatives mid-cycle.

New test cases cover: Span<Ph>, Span<()>, a phantom array reachable through a cycle of array-recursive structs, and a self-recursive array type with no bad element (which must not produce a diagnostic).


Type of change

Please check one:

  • Bug fix (fixes incorrect behavior)
  • New feature
  • Performance improvement
  • Documentation change with concrete technical impact
  • Style, wording, formatting, or typo-only change

Why is this change needed?

Previously, the diagnostic for phantom or zero-sized array elements was only triggered when the Array<...> appeared directly as the type being checked. Wrapping the array in another type — most commonly Span<Ph>, which is {base: Array<Ph>, len: usize} — silently bypassed the check, allowing invalid types to pass semantic validation without an error.


What was the behavior or documentation before?

Span<Ph> and similar types that nest a bad Array inside a struct or other wrapper were accepted without any diagnostic.


What is the behavior or documentation after?

Any type that transitively contains an Array whose element is phantom or zero-sized is rejected with the appropriate E2019 or E2053 diagnostic, regardless of how deeply the array is nested. Self-recursive array types with no bad element continue to be accepted.


Related issue or discussion (if any)


Additional context

The cycle handler is necessary because salsa's default cycle recovery would cache a None (no violation) for the first type encountered in a cycle, even if a violation is reachable only after traversing the rest of the cycle. The iterative stack-based fallback avoids re-entering the query during cycle resolution.

@reviewable-StarkWare

Copy link
Copy Markdown

This change is Reviewable

orizi commented Jun 29, 2026 •

Copy link
Copy Markdown
Collaborator Author

@orizi
orizi requested a review from eytan-starkware June 29, 2026 08:35
@orizi
orizi requested a review from TomerStarkware June 29, 2026 08:36
@orizi
orizi marked this pull request as ready for review June 29, 2026 08:36
@cursor

cursor Bot commented Jun 29, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes core type diagnostic logic in the semantic layer; incorrect traversal or cycle handling could miss invalid types or over-report, but scope is limited to array-element instantiation checks with targeted tests.

Overview
Semantic validation now flags types that transitively contain an Array whose element is phantom or zero-sized, not only when the type is literally Array<...>.

add_type_based_diagnostics delegates to a new memoized array_element_violation query that walks structs, enums, tuples, snapshots, fixed-size arrays, closures, and Box/Nullable wrappers. Violations still surface as E2019 or E2053 via ArrayElementViolation. Recursive types that loop through array elements use array_element_violation_cycle (explicit stack + visited set) so salsa does not cache a false negative mid-cycle.

New attribute diagnostic tests cover Span<Ph>, Span<()>, phantom arrays reachable through mutually recursive struct chains, and struct A { a: Array<A> } with no bad element (must stay clean).

Reviewed by Cursor Bugbot for commit 6271ff2. Bugbot is set up for automated code reviews on this repo. Configure here.

@eytan-starkware eytan-starkware left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eytan-starkware reviewed 2 files and all commit messages, and made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on orizi and TomerStarkware).


crates/cairo-lang-semantic/src/types.rs line 1003 at r1 (raw file):

/// `Array<T>` is only diagnosed once `T` is concretely disallowed.
#[salsa::tracked(cycle_result=array_element_violation_cycle)]
fn array_element_violation<'db>(

Consider removing the cyclic query entirely. is_phantom is already a query, and we can have the non-cyclic function be a query as well, covering most of the cases well

@TomerStarkware TomerStarkware left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

@TomerStarkware reviewed all commit messages and made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on orizi).

@orizi
orizi force-pushed the orizi/06-28-bugfix_semantic_reject_arrays_of_phantom_elements branch from 34a8d80 to 8da02ab Compare June 29, 2026 13:13
@orizi
orizi force-pushed the orizi/06-29-bugfix_semantic_detect_non-instantiable_array_elements_nested_in_a_type branch from 4934dd4 to 4d5cec3 Compare June 29, 2026 13:13

@orizi orizi left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@orizi made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on eytan-starkware).


crates/cairo-lang-semantic/src/types.rs line 1003 at r1 (raw file):

Previously, eytan-starkware wrote…

Consider removing the cyclic query entirely. is_phantom is already a query, and we can have the non-cyclic function be a query as well, covering most of the cases well

i considered - but i rather avoid this recalculation for most types.
the main case would not have that.

…type.

Generalize the array-element check to recurse through a type's concrete structure -
struct members, enum variants, tuple / snapshot / fixed-size-array / closure-capture
components, the type wrapped by a `Box`/`Nullable`, and nested array elements -
instead of inspecting only the top-level type. This catches a phantom or zero-sized
array element reached through a wrapper, e.g. `Span<Ph>` and `Span<[(); 0]>` (which
nest `Array<...>`), closing the gap where `.span()` of a zero-sized array gave no
diagnostic (#9896).

The search is a memoized query that recurses on itself for the common acyclic case.
A type recursive through an array element makes the query cyclic; rather than a fixed
`cycle_result` (which would cache a false negative for whichever participant is
computed first), the cycle handler re-runs the same traversal with an explicit
work-stack and visited set - it never re-enters the query, so every participant gets
a complete result. Only concrete types are searched; a generic `Array<T>` is
diagnosed once T is concretely a disallowed type.
@orizi
orizi changed the base branch from orizi/06-28-bugfix_semantic_reject_arrays_of_phantom_elements to graphite-base/10175 June 29, 2026 13:25
@orizi
orizi force-pushed the graphite-base/10175 branch from 8da02ab to bb80200 Compare June 29, 2026 13:25
@orizi
orizi force-pushed the orizi/06-29-bugfix_semantic_detect_non-instantiable_array_elements_nested_in_a_type branch from 4d5cec3 to 6271ff2 Compare June 29, 2026 13:25
@orizi
orizi changed the base branch from graphite-base/10175 to main June 29, 2026 13:25

@eytan-starkware eytan-starkware left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

@eytan-starkware reviewed 1 file and all commit messages, made 1 comment, and resolved 1 discussion.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on orizi).

@orizi
orizi added this pull request to the merge queue Jun 30, 2026
Merged via the queue into main with commit ba165bb Jun 30, 2026
106 checks passed
@orizi
orizi deleted the orizi/06-29-bugfix_semantic_detect_non-instantiable_array_elements_nested_in_a_type branch July 5, 2026 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants