Preserve attribute arguments and actor-handler attrs in the AST#80
Merged
StreamDemon merged 1 commit intoJul 2, 2026
Merged
Conversation
`@mailbox(capacity: 2048)` and `@supervisor(strategy: "one_for_one")`
lost their arguments at parse time — the parser skipped everything
inside the parens — and attributes on actor handlers were dropped
outright. Nothing downstream (semantic analysis, diagnostics) could
ever see them.
`Attribute` now carries `args: Vec<AttrArg>` plus a span covering `@`
through the closing paren, with `AttrArg` mirroring the §16 grammar
(`attr_arg = IDENT [ ":" expr | "=" expr | "(" expr ")" ] | expr`).
Only the `IDENT ":"` form needs lookahead; the `=` and call forms are
valid expressions, so they parse as expressions and canonicalize to the
most specific attr shape afterwards.
Actor handlers become `Handler { attrs, function }`, since a handler is
a `fn_def` and §16 puts attrs on `fn_def` itself. The now-unused
`skip_balanced_after_open` helper is removed.
There was a problem hiding this comment.
No issues found across 2 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Architecture diagram
sequenceDiagram
participant Src as Source Text
participant Parser as Parser
participant Tokenizer as Token Stream
participant AST as AST Node
participant Client as API Consumer
Note over Src,Client: Attribute Parsing Flow
Src->>Tokenizer: Lex tokens
Tokenizer-->>Parser: Token stream
Parser->>Parser: attrs() method
Note over Parser: Reads @ token, expects ident
alt @IDENT with arguments
Parser->>Parser: Match LParen
Parser->>Parser: attr_args() loop
loop For each arg
Parser->>Parser: Lookahead for IDENT + Colon
alt IDENT followed by Colon
Parser->>AST: Create AttrArg::Named { name, value }
else Other expression forms
Parser->>Parser: Parse as delimited_expr()
Parser->>Parser: classify_attr_expr() canonicalization
alt Single ident path
Parser->>AST: Create AttrArg::Ident
else Assignment expression
Parser->>AST: Create AttrArg::Assigned
else Single-arg call expression
Parser->>AST: Create AttrArg::Call
else Other expression
Parser->>AST: Create AttrArg::Expr
end
end
opt Comma separator
Parser->>Parser: Eat comma, continue loop
end
end
Parser->>Parser: Expect RParen
Parser->>AST: Store args, compute span (@ to )
else @IDENT without arguments
Parser->>AST: Store empty args, span covers name only
end
Parser->>AST: Return Attribute { name, args, span }
Note over Parser,AST: Actor Handler Parsing Flow
Parser->>Parser: Actor body: handlers loop
loop For each handler element
Parser->>Parser: Skip doc comments
Parser->>Parser: Parse attrs() for handler
alt @mailbox or other handler attrs present
Parser->>AST: Collect Vec{Attribute} for handler
else No handler attrs
Parser->>AST: Empty vec
end
Parser->>Parser: Parse visibility & async
alt fn keyword found
Parser->>Parser: Parse function_after_mods()
Parser->>AST: Create Handler { attrs, function }
else Field declaration
Parser->>Parser: Parse ident : type
Note over Parser: Handler attrs before fields are discarded (per spec)
end
end
Parser->>AST: Return Actor with Vec{Handler}
Note over AST,Client: Consumer Usage
Client->>AST: Access attribute args
alt Named args pattern
Client->>Client: Match AttrArg::Named for configuration
else Ident pattern
Client->>Client: Match AttrArg::Ident for derive list
end
Client->>AST: Access handler attributes
Client->>Client: Read handler.attrs for mailbox config
opt Backward compatibility
Client->>Client: Access handler.function for signature
end
Auto-approved: Preserves attribute arguments and handler attrs in AST; adds AttrArg enum and Handler struct. Low risk: purely additive, well-tested, and no behavior change.
Re-trigger cubic
12 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Attributenow preserves its arguments:args: Vec<AttrArg>plus aspancovering@through the closing paren. Previously@mailbox(capacity: 2048)/@supervisor(strategy: "one_for_one")dropped everything inside the parens at parse time.AttrArgmirrors the §16 grammar (attr_arg = IDENT [ ":" expr | "=" expr | "(" expr ")" ] | expr). OnlyIDENT ":"needs lookahead; the=and call alternatives are valid expressions, so they parse as expressions and canonicalize to the most specific attr form afterwards (self/Selfexcluded — they are keywords, notIDENT).Handler { attrs, function }— a handler is afn_def(§16), so its attrs (@mailbox(...)) are no longer dropped outright. Item-position attrs stay hoisted onItem.attrsduring bootstrap.skip_balanced_after_openhelper is removed.Fifth sub-PR of the enhancement wave (PR #71 roadmap: "Preserve attribute arguments in the AST"). Known deferral: attrs written before an actor field are still discarded — §16 gives fields no attrs, and rejecting them is a behavior change outside this wave's scope (same tolerance item-position attrs already have on
mod/use/const).Related Issue
None (PR #71 roadmap item). Issue #78 (spurious type-arg error) was found while designing
attr_argand is tracked separately — it is a behavior fix, so it deliberately does not ride this wave.Spec Sections Affected
None — implementation quality only; parsing follows the existing §16
attrs/attr_args/attr_argproductions.Checklist
docs/pages — N/A, no behavior changeBuild Targets Tested
cargo fmt --all -- --check,cargo clippy --workspace --all-targets -- -D warnings,cargo test --workspaceall green locally (54 tests).Test Plan
attribute_arguments_are_preserved—@derive(Debug, Eq)idents + full attribute span.attribute_named_args_are_preserved—@supervisor(strategy: "one_for_one", max_restarts: 5)named args with literal payloads.attribute_assigned_call_and_expr_args_are_preserved—=, call, and bare-expr alternatives.bare_attribute_has_no_args_and_name_span—@testspan anchors.actor_handler_attributes_are_preserved—@mailbox(capacity: 2048)lands onHandler.attrswith span anchored to the@.Summary by cubic
Keep attribute arguments and handler attributes in the AST. This lets tools and analyzers read attribute payloads and source spans.
New Features
Attributenow includesargs: Vec<AttrArg>and aspanthat covers@through the closing).AttrArgsupportsIdent,Named,Assigned,Call, andExprper §16; the parser canonicalizes=and call forms after parsing.Actor.handlersnow holdHandler { attrs, function }instead of bareFunction.Migration
Actor.handlers: Vec<Function>toVec<Handler>; access the function viahandler.functionand its attrs viahandler.attrs.Attribute.argsandAttribute.spaninstead of assuming no arguments.Written for commit b34be49. Summary will update on new commits.