fix(semantic): reject the malformed macro rule declarations that silently do nothing - #10304
Conversation
ac7ee75 to
a53a9fc
Compare
bd8be0e to
91fa83e
Compare
| } | ||
| SemanticDiagnosticKind::MacroPlaceholderNamedAfterResolverModifier(name) => { | ||
| format!( | ||
| "`${}` is a resolver modifier, so a macro placeholder may not be named after \ |
There was a problem hiding this comment.
the explaination seems like too much.
There was a problem hiding this comment.
Shortened both messages to the bare statement.
There was a problem hiding this comment.
Shortened to the bare statement.
| "Macro repetition block is empty, so it matches nothing.".into() | ||
| } | ||
| SemanticDiagnosticKind::MacroRuleWithUnparsablePattern => { | ||
| "This macro rule's pattern could not be parsed, so the rule can never match a call." |
There was a problem hiding this comment.
the explaination seems like too much.
There was a problem hiding this comment.
Shortened to the bare statement.
PR SummaryMedium Risk Overview New diagnostics (E2205–E2208): pattern placeholders named Declaration logic in Reviewed by Cursor Bugbot for commit fb771d3. Bugbot is set up for automated code reviews on this repo. Configure here. |
a53a9fc to
e2eb1e2
Compare
c1f115d to
967a7ef
Compare
e2eb1e2 to
09a334a
Compare
orizi
left a comment
There was a problem hiding this comment.
@orizi+AGNT made 2 comments and resolved 2 discussions.
Reviewable status: 0 of 3 files reviewed, all discussions resolved.
| } | ||
| SemanticDiagnosticKind::MacroPlaceholderNamedAfterResolverModifier(name) => { | ||
| format!( | ||
| "`${}` is a resolver modifier, so a macro placeholder may not be named after \ |
There was a problem hiding this comment.
Shortened to the bare statement.
| "Macro repetition block is empty, so it matches nothing.".into() | ||
| } | ||
| SemanticDiagnosticKind::MacroRuleWithUnparsablePattern => { | ||
| "This macro rule's pattern could not be parsed, so the rule can never match a call." |
There was a problem hiding this comment.
Shortened to the bare statement.
09a334a to
9719407
Compare
967a7ef to
37217a1
Compare
37217a1 to
60ea5f0
Compare
1807ca6 to
e6ca70b
Compare
c860e0c to
4e8aa3e
Compare
eytan-starkware
left a comment
There was a problem hiding this comment.
@eytan-starkware+AGNT made 7 comments.
Reviewable status: 0 of 3 files reviewed, 6 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/test_data/inline_macros line 3282 at r3 (raw file):
//! > ========================================================================== //! > Test a pattern capturing into the name `$defsite`.
every new case here is a top-level pattern element. check_pattern_elements recurses into repetitions and subtrees and none of that recursion is pinned - add ($($defsite:ident)*), ([$defsite:ident]) and a ?-with-separator nested inside an outer repetition.
crates/cairo-lang-semantic/src/items/macro_declaration.rs line 196 at r3 (raw file):
/// `Err` if any was reported, for the caller to mark the rule with - a defective element makes the /// rule's meaning unclear, so it must not expand. fn check_pattern_elements<'db>(
third full traversal of the pattern with the same four match arms - PatternPlaceholders::collect right below already visits every Param/Repetition/Subtree and already computes the placeholder name (so check_placeholder_name re-interns it). fold the name check into collect - it has both the name and the ptr - and this shrinks to the two repetition checks.
crates/cairo-lang-semantic/src/items/macro_declaration.rs line 259 at r3 (raw file):
diagnostics: &mut SemanticDiagnostics<'db>, ) -> Maybe<()> { let ast::OptionTerminalComma::TerminalComma(separator) = repetition.separator(db) else {
let-chain:
if let ast::OptionTerminalComma::TerminalComma(separator) = repetition.separator(db)
&& matches!(repetition.operator(db), ast::MacroRepetitionOperator::ZeroOrOne(_))
{
return Err(diagnostics.report(
separator.stable_ptr(db).untyped(),
SemanticDiagnosticKind::MacroRepetitionSeparatorWithZeroOrOne,
));
}
Ok(())
crates/cairo-lang-semantic/src/items/macro_declaration.rs line 408 at r3 (raw file):
// which a reused name leaves ambiguous - checking it then reports the ambiguity as // a defect of the expansion, which it is not. if placeholders.reused_names.is_empty() {
this was rule_err.is_ok(), which for an unparsed pattern was always true, so the expansion was checked. now it's reused_names.is_empty(), which for an unparsed pattern depends on whether recovery happened to leave two nameless placeholders - i.e. a coin flip on whether a dropped rule's expansion gets diagnostics.
make it explicit: hoist the !pattern_is_parsed report + continue to the top of the loop, right after let pattern = rule_syntax.lhs(db);. then the if pattern_is_parsed wrapper, the nameless-placeholders comment above it and this whole question go away.
crates/cairo-lang-semantic/src/items/macro_declaration.rs line 426 at r3 (raw file):
// it. It is reported so that a call written for it points at the parse error rather // than failing with a bare "no matching rule". diagnostics.report(
the comment says this is so "a call written for it points at the parse error rather than failing with a bare 'no matching rule'" - but it doesn't. look at the pair golden: E1008 from the parser on the same rule, then this E2208 on an overlapping span, then the same E2158 on the call, unchanged. three diagnostics for one typo, and the confusing one is still there.
fix the comment, or make it actually replace the E2158.
crates/cairo-lang-semantic/src/items/macro_declaration.rs line 613 at r3 (raw file):
if let Some(repetition) = ast::MacroRepetition::cast(db, node) { self.rule_err =
expand_repetition never looks at the operator - in an expansion ? is just *. so $(...),? on the rhs today expands over all the driver's groups and emits the separator between them, correctly. this call turns working code into an error, and it isn't "silently does nothing" as the PR title claims. the doc's "allows at most one group" rationale only holds for the pattern.
either make the expansion honor ? (fail when the driver has more than one group) and then reject the separator, or keep the check pattern-only and drop this call.
4e8aa3e to
bb682b9
Compare
2dd6ba4 to
5ca0569
Compare
…ntly do nothing A pattern capturing into `$defsite` / `$callsite`, a `?` repetition taking a separator and an empty `$()` body are all accepted today and then contribute nothing, and a rule whose pattern has a parse error is dropped silently, so every call written for it fails with a bare "no matching rule".
bb682b9 to
fb771d3
Compare
5ca0569 to
9753276
Compare

A pattern capturing into
$defsite/$callsite, a?repetition taking aseparator and an empty
$()body are all accepted today and then contributenothing, and a rule whose pattern has a parse error is dropped silently, so
every call written for it fails with a bare "no matching rule".