fix(semantic): const_values_eq must canonicalize felt252 inside compounds - #10037
Conversation
…unds const_values_eq only canonicalized cross-representation felt252 for the top-level Int case; NonZero/Struct/Enum fell through to `false`. Since the PartialEq const-fold shortcut keys on the generic eq trait fn, this mis-folded `==`/`!=` on NonZero<felt252>, tuples and Option<felt252> whenever the operands were field-equal but stored in different forms (e.g. -1 vs PRIME-1). Recurse structurally into Struct/Enum/NonZero. Add regression tests for all three. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This stack of pull requests is managed by Graphite. Learn more about stacking. |
PR SummaryLow Risk Overview
Regression coverage adds three cross-form equality constants in the constant expression test data. Reviewed by Cursor Bugbot for commit 1304d8d. Bugbot is set up for automated code reviews on this repo. Configure here. |
eytan-starkware
left a comment
There was a problem hiding this comment.
@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/items/constant.rs line 1252 at r1 (raw file):
self.const_values_eq(*a_value, *b_value) } _ => false,
For generics we separate -1 and Prime-1 into two different types, correct?
orizi
left a comment
There was a problem hiding this comment.
@orizi made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on eytan-starkware and TomerStarkware).
crates/cairo-lang-semantic/src/items/constant.rs line 1252 at r1 (raw file):
Previously, eytan-starkware wrote…
For generics we separate -1 and Prime-1 into two different types, correct?
yes - for the time being.
eytan-starkware
left a comment
There was a problem hiding this comment.
@eytan-starkware made 1 comment and resolved 1 discussion.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on TomerStarkware).

Summary
const_values_eqpreviously only handled the case where both sides wereConstValue::Int, returningfalsefor any other variant pair. This meant thatfelt252values nested inside structs, enums, orNonZerowrappers were compared by identity rather than by field-element value, causing-1andPRIME - 1to be treated as unequal even though they represent the same field element.The function now recurses into
ConstValue::Struct,ConstValue::Enum, andConstValue::NonZerovariants, applying field-element canonicalization at every level where afelt252integer may appear.Type of change
Please check one:
Why is this change needed?
The
PartialEqoperator forfelt252must agree with the field, meaning-1and0x800000000000011000000000000000000000000000000000000000000000000(i.e.,PRIME - 1) are the same value. The previous implementation only canonicalized top-levelfelt252integers, so equality checks onNonZero<felt252>, tuples containingfelt252, or enums wrappingfelt252would incorrectly returnfalsewhen comparing these two representations.What was the behavior or documentation before?
Constant expressions such as:
would fail constant evaluation because the structural wrappers were compared by identity rather than recursively by field value.
What is the behavior or documentation after?
The above constant expressions now evaluate correctly.
const_values_eqrecurses into structs, enums, andNonZerowrappers, canonicalizingfelt252integers at every nesting level before comparing.Related issue or discussion (if any)
N/A
Additional context
Test cases for all three new cross-form equality scenarios (
NonZero<felt252>, tuple, and enum) have been added to the constant expression test data.