test(semantic): pin the macro matcher behaviors that already agree with rustc - #10306
Conversation
e4aab9d to
a7e94c5
Compare
5f7d17c to
9b8111a
Compare
a7e94c5 to
cc43a8c
Compare
9b8111a to
46bd0ab
Compare
PR SummaryLow Risk Overview In In Reviewed by Cursor Bugbot for commit 17e644e. Bugbot is set up for automated code reviews on this repo. Configure here. |
cc43a8c to
9f845a8
Compare
46bd0ab to
929912f
Compare
9f845a8 to
a757f08
Compare
eytan-starkware
left a comment
There was a problem hiding this comment.
@eytan-starkware+AGNT made 6 comments.
Reviewable status: 0 of 2 files reviewed, 5 unresolved discussions (waiting on eytan-starkware, orizi, and TomerStarkware).
a discussion (no related file):
Note: the comments below are from an automatic orizi-review run (Claude agents reviewing in Ori's style, findings adversarially verified before posting). Treat with the usual bot skepticism.
crates/cairo-lang-semantic/src/expr/expansion_test_data/inline_macros line 279 at r1 (raw file):
//! > ========================================================================== //! > Test calls of a parenthesized rule written with every call delimiter (valid).
name says every call delimiter, only bracketed and braced are called. add the paren call or drop "every":
let parenthesized = outer_delim!(1, 2);
let bracketed = outer_delim![1, 2];
crates/cairo-lang-semantic/src/expr/expansion_test_data/inline_macros line 332 at r1 (raw file):
//! > ========================================================================== //! > Test a `+` rule matching at least one capture, next to an empty rule.
this is fallthrough above, one nesting level up - same behavior, a rule whose + matched nothing falls through to the next rule. the only thing it adds is a call that does match the + rule, which fallthrough should be carrying itself. drop this case and add the positive call there:
let matched = fallthrough!([a, b], [c, d]);
let fell_through = fallthrough!([], [a, b]);
(also the only new case in the file with no comment.)
crates/cairo-lang-semantic/src/expr/expansion_test_data/inline_macros line 392 at r1 (raw file):
// broadcast to every capture of the `$v` group it encloses. #[feature("user_defined_inline_macros")] macro bcast {
bcast - the file spells it out as broadcast a few cases up, and here the variable is broadcast. deep_broadcast for the macro.
crates/cairo-lang-semantic/src/expr/expansion_test_data/inline_macros line 417 at r1 (raw file):
// sum that the trailing `0` terminates. #[feature("user_defined_inline_macros")] macro sum {
sum a few cases below sums, on the same pattern as sums, flatten and nested - four macros in this file differing only in the expansion body, two of them one letter apart. rename at least, and the only thing this really adds over flatten is the trailing 0 and the empty non-final group - consider adding flatten!([], [3, 4]) to flatten instead of a fourth macro on that pattern.
crates/cairo-lang-semantic/src/expr/test_data/inline_macros line 3751 at r1 (raw file):
//! > cairo_code // `_` is not an identifier, so an `ident` placeholder does not match it. The first call, which the
every other case in this cluster records the rustc comparison in the comment itself (rustc's macro_rules! rejects the equivalent pattern with ...). this one doesn't, so the cross-check survives only in the commit message. add it:
// `_` is not an identifier, so an `ident` placeholder does not match it. The first call, which the
// rule does match, shows the rejection is the `_` and not the repetition itself; in the second call
// the offending element is not the first.
// rustc's `macro_rules!` rejects the equivalent call with
// `error: no rules expected reserved identifier '_'`.
7cc0ce6 to
fd19862
Compare
db92211 to
7796c97
Compare
65c3f43 to
304290b
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7796c97. Configure here.
7796c97 to
4c77c15
Compare
orizi
left a comment
There was a problem hiding this comment.
@orizi+AGNT made 5 comments and resolved 4 discussions.
Reviewable status: 0 of 2 files reviewed, 1 unresolved discussion (waiting on eytan-starkware+AGNT and TomerStarkware).
crates/cairo-lang-semantic/src/expr/expansion_test_data/inline_macros line 279 at r1 (raw file):
Previously, eytan-starkware+AGNT (Agent AGNT for eytan-starkware) wrote…
name says every call delimiter, only bracketed and braced are called. add the paren call or drop "every":
let parenthesized = outer_delim!(1, 2); let bracketed = outer_delim![1, 2];
Added the paren call.
crates/cairo-lang-semantic/src/expr/expansion_test_data/inline_macros line 332 at r1 (raw file):
Previously, eytan-starkware+AGNT (Agent AGNT for eytan-starkware) wrote…
this is
fallthroughabove, one nesting level up - same behavior, a rule whose+matched nothing falls through to the next rule. the only thing it adds is a call that does match the+rule, whichfallthroughshould be carrying itself. drop this case and add the positive call there:let matched = fallthrough!([a, b], [c, d]); let fell_through = fallthrough!([], [a, b]);(also the only new case in the file with no comment.)
Done - the deeper block is dropped and fallthrough carries matched/fell_through instances.
crates/cairo-lang-semantic/src/expr/expansion_test_data/inline_macros line 392 at r1 (raw file):
Previously, eytan-starkware+AGNT (Agent AGNT for eytan-starkware) wrote…
bcast- the file spells it out asbroadcasta few cases up, and here the variable isbroadcast.deep_broadcastfor the macro.
Renamed to deep_broadcast.
crates/cairo-lang-semantic/src/expr/expansion_test_data/inline_macros line 417 at r1 (raw file):
Previously, eytan-starkware+AGNT (Agent AGNT for eytan-starkware) wrote…
suma few cases belowsums, on the same pattern assums,flattenandnested- four macros in this file differing only in the expansion body, two of them one letter apart. rename at least, and the only thing this really adds overflattenis the trailing0and the empty non-final group - consider addingflatten!([], [3, 4])toflatteninstead of a fourth macro on that pattern.
Half-taken: renamed to nested_sum, but the fold into flatten does not hold - flatten!([], [3, 4]) expands to (,3,4), a parse error; the trailing 0 termination is exactly what lets a non-final group be empty, and the comment now says so.
crates/cairo-lang-semantic/src/expr/test_data/inline_macros line 3751 at r1 (raw file):
Previously, eytan-starkware+AGNT (Agent AGNT for eytan-starkware) wrote…
every other case in this cluster records the rustc comparison in the comment itself (
rustc's macro_rules! rejects the equivalent pattern with ...). this one doesn't, so the cross-check survives only in the commit message. add it:// `_` is not an identifier, so an `ident` placeholder does not match it. The first call, which the // rule does match, shows the rejection is the `_` and not the repetition itself; in the second call // the offending element is not the first. // rustc's `macro_rules!` rejects the equivalent call with // `error: no rules expected reserved identifier '_'`.
Added the rustc comparison line.
304290b to
df4f07e
Compare
a55a4a6 to
3aaa1e4
Compare
df4f07e to
96f2495
Compare
96f2495 to
e1b8458
Compare
3aaa1e4 to
b578992
Compare
e1b8458 to
817e9e3
Compare
b578992 to
7abbd8e
Compare
817e9e3 to
e2134ff
Compare
3f196cb to
fc3616d
Compare
e2134ff to
8fd1650
Compare
fc3616d to
f7538ae
Compare
8fd1650 to
b657e7f
Compare
f7538ae to
9b28d59
Compare
4bc47fa to
42e0536
Compare
9b28d59 to
0e43809
Compare
…th rustc
Tests only, pure append, zero production hunks and zero churn in either golden file.
Thirteen goldens pinning behaviors where Cairo's user-defined inline macros already match
rustc `macro_rules!`, so later work on the matcher and the expander cannot silently regress
them. Twelve in `expr/expansion_test_data/inline_macros` (expansion text) and one in
`expr/test_data/inline_macros` (a rejection, so a diagnostic).
Newly pinned, with the rustc 1.96.0 (ac68faa20 2026-05-25) output each expectation was
cross-checked against. Every rustc program transcribes through `stringify!`, so the
transcriber's own output is observed, and every one includes an invocation because rustc's
matcher and transcriber errors are lazy.
| golden | rustc program | rustc output |
| --- | --- | --- |
| bracketed call of a paren rule | `($($x:expr),*) => { stringify!(($($x,)*)) }`, `m![1, 2]` | `(1, 2,)` |
| braced call of a paren rule | same, `m!{1, 2}` | `(1, 2,)` |
| empty bracketed call of a paren rule | same, `m![]` | `()` |
| later rule after `+` matched nothing | `($([$($x:ident),+]),*) => { 1 }; ($([$($x:ident),*]),*) => { 2 };`, `m!([], [a, b])` | `2` |
| repeating rule ahead of an empty rule | `($($x:ident),+) => { 1 }; () => { 2 };`, `m!(a, b)` | `1` |
| empty call taking the empty rule | same, `m!()` | `2` |
| expansion operator differing from the pattern's | `($($x:expr),*) => { stringify!((0, $($x,)?)) }`, `m!(1, 2)` | `(0, 1, 2,)` |
| the same over no captures at all | same, `m!()` | `(0,)` |
| placeholder broadcast into a deeper block | `($(($k:expr, [$($v:expr),*])),*) => { stringify!(($($(($k * $v),)*)*)) }`, `m!((10, [1, 2]), (20, [3, 4]))` | `((10 * 1), (10 * 2), (20 * 3), (20 * 4),)`, value `(10, 20, 60, 80)` |
| the same with a non-final group of no captures | same, `m!((10, []), (20, [3, 4]))` | `((20 * 3), (20 * 4),)`, value `(60, 80)` |
| doubly nested block flattened into one sum | `($([$($x:expr),*]),*) => { stringify!($($($x +)*)* 0) }`, `m!([1, 2], [3, 4])` | `1 + 2 + 3 + 4 + 0`, value `10` |
| the same with a non-final group matching nothing | same, `m!([], [3, 4])` | `3 + 4 + 0`, value `7` |
| `_` not matched by an ident placeholder | `($($x:ident),*) => { 7 }`, `m!(a, _, b)` | `error: no rules expected reserved identifier '_'` with `note: while trying to match meta-variable $x:ident` |
Cairo's blessed expansion text is the same token sequence as rustc's in every row; it
differs only in the spacing around a spliced placeholder (`1+2+3+4+0`, `((10* 1),...`),
which is the known trivia loss around `$x` and not a difference in what was spliced. Every
value the text evaluates to is the value rustc computes.
Test shape, per the plan's rules: every repetition level in every new case holds two
captures; the offending or empty element is the non-final one wherever the case has one
(`[]` first in the fallthrough, `sum` and `bcast` cases, `_` second in the `_` case); each
behavior has an explicit zero-match or empty-group case; and the `_` case calls the macro
once with a matching argument list and once with `_`, so its single E2158 shows the
rejection is the `_` rather than the repetition.
Because these pin existing behavior there is no fix to revert, so each expected block was
shown load-bearing by corrupting it and observing the failure. All thirteen fail as an
`expanded_code` / `expected_diagnostics` mismatch on exactly their own case - never a panic
and never a diagnostics-expectation error.
Two throwaway production perturbations, reverted and not part of this commit, additionally
show the pins are sensitive to the behavior they name rather than to arbitrary text:
* Making `is_macro_rule_match` return `None` for a braced or bracketed call reddens exactly
the three outermost-delimiter cases and nothing else in the file.
* Capping an expansion repetition at one group when its operator is `?` reddens exactly the
differing-operator case and nothing else in the file.
Not pinned, with reasons:
* Two cross-check rows are not expressible on this base. A transcriber separator that
differs from the pattern's needs a non-comma separator, which the grammar does not have
(`($($x:ident),*) => { ($($x);*) }` is an E1031 parse error), and rustc's metavariable
expressions are still unstable there, so Cairo's rejection of `${count(x)}` is not
agreement with a rustc behavior that exists.
* Nine rows already had a golden and were only re-verified on this base.
* No E2199 sibling-zip case is added; that behavior needs its own design decision.
`$($($x +)*)* 0` is pinned as the accepting expansion it is in rustc, not as an error.
Gates: `cargo test --profile=ci-dev -p cairo-lang-semantic` (106 passed),
`./scripts/rust_fmt.sh --check`, `./scripts/clippy.sh --profile=ci-dev`,
`./scripts/validate_error_codes.sh`,
`cargo run --profile=ci-dev --bin cairo-test -- tests/bug_samples --starknet` (68 passed),
and `cargo run --profile=ci-dev --bin cairo-test -- corelib/` (737 passed) - the last
because no other gate compiles `corelib/src/test/`.
42e0536 to
e20bda1
Compare
0e43809 to
17e644e
Compare


Tests only, pure append, zero production hunks and zero churn in either golden file.
Thirteen goldens pinning behaviors where Cairo's user-defined inline macros already match
rustc
macro_rules!, so later work on the matcher and the expander cannot silently regressthem. Twelve in
expr/expansion_test_data/inline_macros(expansion text) and one inexpr/test_data/inline_macros(a rejection, so a diagnostic).Newly pinned, with the rustc 1.96.0 (ac68faa20 2026-05-25) output each expectation was
cross-checked against. Every rustc program transcribes through
stringify!, so thetranscriber's own output is observed, and every one includes an invocation because rustc's
matcher and transcriber errors are lazy.
($($x:expr),*) => { stringify!(($($x,)*)) },mm!{1, 2}(1, 2,)m![]()+matched nothing($([$($x:ident),+]),*) => { 1 }; ($([$($x:ident),*]),*) => { 2 };,m!([], [a, b])2($($x:ident),+) => { 1 }; () => { 2 };,m!(a, b)1m!()2($($x:expr),*) => { stringify!((0, $($x,)?)) },m!(1, 2)(0, 1, 2,)m!()(0,)($(($k:expr, [$($v:expr),*])),*) => { stringify!(($($(($k * $v),)*)*)) },m!((10, [1, 2]), (20, [3, 4]))((10 * 1), (10 * 2), (20 * 3), (20 * 4),), value(10, 20, 60, 80)m!((10, []), (20, [3, 4]))((20 * 3), (20 * 4),), value(60, 80)($([$($x:expr),*]),*) => { stringify!($($($x +)*)* 0) },m!([1, 2], [3, 4])1 + 2 + 3 + 4 + 0, value10m!([], [3, 4])3 + 4 + 0, value7_not matched by an ident placeholder($($x:ident),*) => { 7 },m!(a, _, b)error: no rules expected reserved identifier '_'withnote: while trying to match meta-variable $x:identCairo's blessed expansion text is the same token sequence as rustc's in every row; it
differs only in the spacing around a spliced placeholder (
1+2+3+4+0,((10* 1),...),which is the known trivia loss around
$xand not a difference in what was spliced. Everyvalue the text evaluates to is the value rustc computes.
Test shape, per the plan's rules: every repetition level in every new case holds two
captures; the offending or empty element is the non-final one wherever the case has one
(
[]first in the fallthrough,sumandbcastcases,_second in the_case); eachbehavior has an explicit zero-match or empty-group case; and the
_case calls the macroonce with a matching argument list and once with
_, so its single E2158 shows therejection is the
_rather than the repetition.Because these pin existing behavior there is no fix to revert, so each expected block was
shown load-bearing by corrupting it and observing the failure. All thirteen fail as an
expanded_code/expected_diagnosticsmismatch on exactly their own case - never a panicand never a diagnostics-expectation error.
Two throwaway production perturbations, reverted and not part of this commit, additionally
show the pins are sensitive to the behavior they name rather than to arbitrary text:
is_macro_rule_matchreturnNonefor a braced or bracketed call reddens exactlythe three outermost-delimiter cases and nothing else in the file.
?reddens exactly thediffering-operator case and nothing else in the file.
Not pinned, with reasons:
differs from the pattern's needs a non-comma separator, which the grammar does not have
(
($($x:ident),*) => { ($($x);*) }is an E1031 parse error), and rustc's metavariableexpressions are still unstable there, so Cairo's rejection of
${count(x)}is notagreement with a rustc behavior that exists.
$($($x +)*)* 0is pinned as the accepting expansion it is in rustc, not as an error.Gates:
cargo test --profile=ci-dev -p cairo-lang-semantic(106 passed),./scripts/rust_fmt.sh --check,./scripts/clippy.sh --profile=ci-dev,./scripts/validate_error_codes.sh,cargo run --profile=ci-dev --bin cairo-test -- tests/bug_samples --starknet(68 passed),and
cargo run --profile=ci-dev --bin cairo-test -- corelib/(737 passed) - the lastbecause no other gate compiles
corelib/src/test/.