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

fix(lowering): dedup panic_destruct calls for a var at a shared panic location - #10205

Merged
orizi merged 1 commit into
mainfrom
orizi/07-17-fix_lowering_dedup_panic_destruct_calls_for_a_var_at_a_shared_panic_location
Jul 18, 2026
Merged

orizi merged 1 commit into
mainfrom
orizi/07-17-fix_lowering_dedup_panic_destruct_calls_for_a_var_at_a_shared_panic_location

Conversation

@orizi

@orizi orizi commented Jul 17, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Deduplicate DestructionEntry items by var_id before generating panic-destruct calls, preventing the same variable from being destructed more than once when control-flow arms converge on a shared panic path.


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?

When multiple control-flow branches converge at a shared panic site, the lowering pass could emit duplicate panic_destruct calls for the same variable. This produced redundant (and potentially incorrect) destructor invocations in the lowered IR.


What was the behavior or documentation before?

The destructions list was iterated as-is, so a variable that appeared in the destruction list more than once (due to branch convergence) would have its panic destructor emitted multiple times.


What is the behavior or documentation after?

Before iterating over destructions, entries are deduplicated by var_id using unique_by. Each variable's panic destructor is now emitted exactly once, even when multiple branches share the same panic exit point.

A new test case (Panic destruct is not duplicated when arms converge on a shared panic) verifies that a Felt252Dict-wrapping struct with a custom PanicDestruct impl is squashed only once in the flat lowering output when an if/else converges before a panic_with_felt252 call.


Related issue or discussion (if any)


Additional context

The fix is a one-liner using unique_by from the itertools crate, applied directly to the destructions iterator in add_destructs.

… location

When several control-flow arms converge on a single block that
materializes the `Panic`, `PanicState::merge` concatenates their
panic-location lists without deduplication. A variable that is live into
that convergence then gets a `PanicDeconstructionEntry` per duplicate
location, so `add_destructs` emits two `panic_destruct` calls that both
consume the same variable.

For panic-destruct-only types (a manual `PanicDestruct` impl, no `Drop`/
`Destruct`) this double-move reaches sierra generation as `dup<T>` on a
non-duplicatable type and ICEs, e.g. `dup<Felt252Dict<u64>>`. The borrow
checker uses a scalar `PanicState` so it never observes the duplication.

Dedup the destructions per group (by the destructed variable) in
`add_destructs`, where entries are already grouped by location, so each
variable is panic-destructed at most once per convergence point.

Adds a `test_data/destruct` golden covering an `if/else` that converges on
a shared `panic!` over a `Felt252Dict`-wrapping panic-destruct-only type.
@reviewable-StarkWare

Copy link
Copy Markdown

This change is Reviewable

orizi commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@orizi
orizi marked this pull request as ready for review July 17, 2026 08:42
@cursor

cursor Bot commented Jul 17, 2026 •

Copy link
Copy Markdown

PR Summary

Low Risk
Small, localized change in the destructor-insertion pass with a targeted regression test; no auth or data-path changes.

Overview
Fixes duplicate panic destructor emission in lowered IR when several control-flow paths merge at the same panic site.

In add_destructs, each grouped batch of DestructionEntry values is now filtered with unique_by on var_id (for both plain and panic entries) before generating destructor calls. A variable that showed up more than once in the list—typically because branch convergence duplicated panic-drop bookkeeping—gets one panic_destruct (or plain destruct) instead of several.

A new lowering snapshot test covers an if/else that joins before panic_with_felt252, with a Wrap type whose PanicDestruct squashes an inner Felt252Dict; the expected flat IR has a single squash on the shared panic block.

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

@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 2 files and all commit messages, and made 1 comment.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on eytan-starkware).

@orizi
orizi added this pull request to the merge queue Jul 18, 2026
Merged via the queue into main with commit d83ad6f Jul 18, 2026
55 checks passed
@orizi
orizi deleted the orizi/07-17-fix_lowering_dedup_panic_destruct_calls_for_a_var_at_a_shared_panic_location branch July 18, 2026 11:36
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.

3 participants