Skip to content

fix(macros): diagnose tuple-pattern @State/@Persisted; letToVar FixIt; pin untested guards#261

Merged
zzal merged 1 commit into
mainfrom
fix/macro-guardrails
Jul 20, 2026
Merged

fix(macros): diagnose tuple-pattern @State/@Persisted; letToVar FixIt; pin untested guards#261
zzal merged 1 commit into
mainfrom
fix/macro-guardrails

Conversation

@zzal

@zzal zzal commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Audit backlog B9 (Part-4 Mediums).

  • Tuple/wildcard silent swallow (the one silent-guarantee-break found): @State var (a, b) = (0, 1) hit the peer's entry guard and returned [] with no diagnostic, while the compiler skips the accessor role for those patterns entirely — the property compiled as plain, non-reactive storage. Both @State and @Persisted peers now diagnose the pattern first (ported from @MutationState/@ReducerState).
  • @Persisted requiresVar now attaches the letToVar FixIt its three siblings have (FixItSpec-asserted).
  • @Query member names tightened from named(queryKey), arbitrary to named(queryKey), named(init) — symmetric with @Mutation, and host-proven by MacroConsumerChecks/integration tests.
  • prefixMustBeLiteral (the only plugin diagnostic with zero assertions) gets goldens for a variable prefix and an interpolated prefix.
  • New PeerGuardDirectTests: direct invocation of the peer expansions on parsed syntax — the only vehicle for these guards, since assertMacroExpansion injects its own multi-binding error (which the real compiler never emits) and never exercises the tuple path.

Whole-package swift test: 1904 tests, 352 suites, green.

🤖 Generated with Claude Code

…; pin untested guards

A tuple or wildcard binding (@State var (a, b) = (0, 1)) hit the peer
macro's entry guard and returned [] with no diagnostic — and the
compiler never runs the accessor role for those patterns, so the
property compiled as plain, non-reactive storage: no cell, no HMR
snapshot, no persistence. Both peers now diagnose the pattern first
(the @MutationState/@ReducerState guard, ported), because every later
'accessor path diagnosed it' bail is silent for these shapes.

Also: @persisted's requiresVar gains the letToVar FixIt its three
sibling macros already attach; @query's member names list drops
 for the exact  (matching
@mutation); prefixMustBeLiteral — the one plugin diagnostic with zero
assertions — gets goldens for a variable and an interpolated prefix.

New PeerGuardDirectTests invoke the peer expansions directly on parsed
syntax: assertMacroExpansion cannot reach these guards (it injects its
own multi-binding error the real compiler never emits, and tuple
shapes bypass the harness's accessor run).

Whole-package swift test: 1904 green — MacroConsumerChecks host-compile
the tightened @query names list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 Bundle size

Artifact Baseline This PR Δ
App.wasm 5.06 MB 5.23 MB +3.45%
App.wasm (gzip) 1.80 MB 1.87 MB +3.56%
JS runtime 54.5 KB 54.5 KB +0.00%
JS runtime (gzip) 11.3 KB 11.3 KB +0.00%
Total (gzip) 1.81 MB 1.88 MB +3.54%

✅ Within budget (≤5% growth allowed).

Baseline: Swift 6.3, WASM SDK 6.3-RELEASE, measured 2026-06-18.

@zzal
zzal merged commit a5ef558 into main Jul 20, 2026
16 of 18 checks passed
@zzal
zzal deleted the fix/macro-guardrails branch July 20, 2026 01:22
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.

1 participant