Skip to content

fix(semantic): reject a + expansion repetition over zero groups - #10315

Open
orizi wants to merge 1 commit into
graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensivefrom
graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group
Open

orizi wants to merge 1 commit into
graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensivefrom
graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group

Conversation

@orizi

@orizi orizi commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

A $( ... )+ block in a macro expansion promises at least one
repetition, but a call matching zero groups silently expanded it to
nothing. Report the new E2210 instead, as rustc does ("this must repeat
at least once"). * and ? blocks over zero groups stay valid.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

@reviewable-StarkWare

Copy link
Copy Markdown

This change is Reviewable

orizi commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

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

@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from 9fd42a9 to b559512 Compare August 4, 2026 08:41
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from 94fdd8f to 11ce2dc Compare August 4, 2026 08:41
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from b559512 to 71fa44b Compare August 4, 2026 08:56
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch 2 times, most recently from f874dc3 to 4226edc Compare August 5, 2026 10:54
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from 71fa44b to 61861f5 Compare August 5, 2026 10:54
@orizi
orizi marked this pull request as ready for review August 5, 2026 11:10
@cursor

cursor Bot commented Aug 5, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes user-defined macro expansion semantics and may break macros that silently expanded invalid +/? blocks; diagnostics are localized to the semantic macro expander.

Overview
Macro expansion now enforces the repetition operator on $(...) blocks in a rule’s expansion, not just how many groups the call captured. A + block must expand at least once (zero matching groups → E2210), and a ? block may expand at most once (more than one group → E2210). * behavior is unchanged.

MacroExpansionError is split into declaration/expansion failures vs. repetition-count mismatch; mismatch diagnostics are anchored on the macro call site (callers pass call_ptr from expr expansion and macro_call). Messages and error code E2210 are wired in SemanticDiagnosticKind.

Tests are updated so a ? expansion under a * pattern errors on multi-argument calls, plus new cases for +/*/? over zero or multiple groups.

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

@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from 4226edc to 846bfe2 Compare August 5, 2026 15:15
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from 460d19f to 2d6c678 Compare August 17, 2026 18:40
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from 5545a66 to c19648b Compare August 17, 2026 19:07
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch 2 times, most recently from c6ccdef to a454a87 Compare August 23, 2026 08:43
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from c19648b to 0fa0009 Compare August 23, 2026 08:43
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from a454a87 to d5a0d2d Compare August 23, 2026 08:50
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from 0fa0009 to 175bdc0 Compare August 23, 2026 08:50
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from d5a0d2d to d621f68 Compare August 23, 2026 10:31
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from 175bdc0 to d9fcfe4 Compare August 23, 2026 10:31
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from d621f68 to 8b23a11 Compare August 23, 2026 11:22
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from d9fcfe4 to bc5a48e Compare August 23, 2026 11:22

@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+AGNT made 5 comments and resolved 5 discussions.
Reviewable status: 0 of 6 files reviewed, all discussions resolved (waiting on TomerStarkware).


crates/cairo-lang-semantic/src/diagnostic.rs line 1568 at r4 (raw file):

Previously, eytan-starkware+AGNT (Agent AGNT for eytan-starkware) wrote…

_ hands E2202 to whatever variant gets added next, silently. also this is the only arm in the whole error_code match that looks inside a kind - everywhere else is one code per kind. at minimum list them:

                MacroExpansionFailure::MissingRepetitionDriver
                | MacroExpansionFailure::ConflictingRepetitionDrivers
                | MacroExpansionFailure::MissingCapture(_) => error_code!(E2202),

Gone with the redesign - MacroExpansionFailed(_) is one code again and the new kind carries its own.


crates/cairo-lang-semantic/src/expr/test_data/inline_macros line 4105 at r4 (raw file):

Previously, eytan-starkware+AGNT (Agent AGNT for eytan-starkware) wrote…

expansion_test_data/inline_macros:363 still pins "The operator of an expansion repetition is ignored" as the rule. it isn't, as of this PR. update that comment (and its test name) while the + case is being carved out, otherwise the two files document opposite invariants.

Updated - the golden is now "Test an expansion repetition whose operator differs from the pattern's, within its count." and its comment states the enforced promise and the rustc decl-time divergence.


crates/cairo-lang-semantic/src/items/macro_declaration.rs line 1081 at r4 (raw file):

Previously, eytan-starkware+AGNT (Agent AGNT for eytan-starkware) wrote…

"reachable by design" is exactly why it doesn't belong in this enum. MacroExpansionFailure is documented as the defensive backstop for things no program reaches; putting the one user-facing failure in it is what forces this doc caveat and the nested match in error_code. give it its own SemanticDiagnosticKind and have MacroExpansionError::report map to it - then this paragraph and the _ => arm both go away.

Done - the variant left MacroExpansionFailure entirely. The reachable failure is its own SemanticDiagnosticKind::MacroExpansionRepetitionCountMismatch (covering both ends of the operator's promise), constructed as its own MacroExpansionError variant and mapped by report; the caveat paragraph and the nested error_code match are both gone.


crates/cairo-lang-semantic/src/items/macro_declaration.rs line 1278 at r4 (raw file):

Previously, eytan-starkware+AGNT (Agent AGNT for eytan-starkware) wrote…

the ? half of this is still silently wrong. ? promises at most once, and nothing here caps the loop - ($($x:ident),*) => { $($x + )? 0 } on m!(a, b) expands to a + b + 0 with no diagnostic (verified against expand_inline_macros). and a ? block can't carry a separator, so the extra groups are emitted glued. if the operator's promise is enforced, enforce both ends here:

        let group_count = self.group_count(repetition)?;
        let valid = match repetition.operator(db) {
            ast::MacroRepetitionOperator::OneOrMore(_) => group_count >= 1,
            ast::MacroRepetitionOperator::ZeroOrOne(_) => group_count <= 1,
            _ => true,
        };
        if !valid {

or say why ? is deliberately left alone.

Enforced on both ends as suggested - + requires at least one group, ? allows at most one - and the mixed-operator golden now pins all three counts, with mixed_op!(1, 2) rejected at the call.


crates/cairo-lang-semantic/src/items/macro_declaration.rs line 1284 at r4 (raw file):

Previously, eytan-starkware+AGNT (Agent AGNT for eytan-starkware) wrote…

this is the first MacroExpansionFailure a user can actually hit, and it reports on the declaration only. a call to a macro declared in another file puts the error in that file, with nothing at the call and no hint which call triggered it - rustc points at the definition too, but adds in this macro invocation. both callers (compute.rs:836, macro_call.rs:165) have the call syntax; worth carrying it into the report.

Done - report now takes the call's stable pointer from both callers and anchors the count-mismatch diagnostic on the call that determined the group count (Cairo diagnostics are single-span, so the call site wins over the declaration; the message names the block's operator instead). The defensive failures stay on the expansion node.

@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from bc5a48e to 6c36c5a Compare August 23, 2026 12:03
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from 8b23a11 to fb44fb8 Compare August 23, 2026 12:03
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from 6c36c5a to 629b2a8 Compare August 25, 2026 12:30
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from fb44fb8 to 083c15c Compare August 25, 2026 12:30
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from 629b2a8 to 8eefe56 Compare August 26, 2026 19:59
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from 0d8844c to ca492eb Compare August 27, 2026 04:32
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from 8eefe56 to 1f73148 Compare August 27, 2026 04:32
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from ca492eb to 77b3591 Compare August 27, 2026 13:33
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch 3 times, most recently from b15aded to d595d86 Compare August 28, 2026 12:58
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from 2bc894b to 8b3f58b Compare August 28, 2026 12:58
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from 8b3f58b to ce3f35c Compare September 14, 2026 04:51
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from d595d86 to a991f8b Compare September 14, 2026 04:51
…their operator's promise

A `$( ... )+` block in a macro expansion promises at least one repetition, but
a call matching zero groups silently expanded it to nothing; a `$( ... )?`
block promises at most one, but a call matching more silently expanded it once
per group. Both ends now report the new E2210 at the call that determined the
count. `*` blocks and zero-group `?` blocks stay valid, and an expansion
operator still does not have to match its driver's.

rustc reports "this must repeat at least once" on the `+` end; the `?` end is
Cairo's own - rustc only lints the operator mismatch (allow-by-default
`meta_variable_misuse`) and silently expands its `?` block once per group. The
`?` change reverses behavior a golden previously pinned as valid: the
mixed-operator test now pins all three counts, the two-group call rejected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/doc-expansion-error-defensive branch from ce3f35c to ea8bb08 Compare September 14, 2026 06:56
@orizi
orizi force-pushed the graph-plan/2026-08-03-macro-fixes/expansion-plus-requires-group branch from a991f8b to 26c8e7b Compare September 14, 2026 06:56
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