BridgeJS: Fix for-loop emission in stack codegen#716
Merged
krodak merged 1 commit intoswiftwasm:mainfrom Apr 9, 2026
Merged
Conversation
Three `StackCodegen` helpers built their `for`-loops from separate
`CodeBlockItemSyntax` fragments ("for ... {", body, "}"). swift-syntax
603's formatter then renders such partial statements with the closing
brace glued to the previous line. Combine each for-loop into a single
multi-line `CodeBlockItemSyntax` so the formatter produces consistent
output across swift-syntax 600-603.
Also fix a latent bug in `StructCodegen.generateStructLowerCode` and
`EnumCodegen.generatePayloadPushingCode`: they concatenated lowering
statements via `CodeBlockItemListSyntax(statements).description` which
does not insert separators between items that lack leading trivia. The
thunk builder path was fine because `append` explicitly adds `.newline`
trivia, but any multi-statement lowering routed through a struct field
or enum payload was silently glued onto a single line. Iterate over the
statements and write each one individually through the printer.
Add regression coverage for the previously untested codepaths:
- `[String: MyProtocol]` as a function return, class property getter,
and parameter (exercises `lowerProtocolDictionaryStatements`).
- A `@JS struct` field of type `[String: Int?]` (exercises
`lowerDictionaryStatementsInline` via `generateStructLowerCode`).
148e65b to
9f149cc
Compare
kateinoigakukun
approved these changes
Apr 9, 2026
This was referenced Apr 9, 2026
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.
Overview
Three
StackCodegenhelpers inExportSwift.swiftbuilt theirfor-loops out of separateCodeBlockItemSyntaxfragments ("for … {", one item per body line,"}"). Each fragment was passed through swift-syntax individually, so none of them parsed as a well-formed statement on its own. swift-syntax 600-602's formatter rendered them leniently, but 603 glues the closing brace onto the previous line, producing output like:This was flagged by @kateinoigakukun on #714 for
lowerProtocolArrayStatements. Two sibling helpers (lowerProtocolDictionaryStatements,lowerDictionaryStatementsInline) have the same structural bug but no snapshot coverage, so they went unnoticed. While chasing the fix I also hit a latent trivia bug inStructCodegenandEnumCodegenthat only surfaces onceStackCodegen.lowerStatementsstarts returning multi-statement results from a struct or enum codepath.This PR fixes all four problems and adds regression coverage for the previously untested shapes.
1. Emit each lowering
for-loop as a singleCodeBlockItemSyntax.lowerProtocolArrayStatements,lowerProtocolDictionaryStatements, andlowerDictionaryStatementsInlinenow build the loop via a multi-line string literal so swift-syntax parses a completeforstatement. This matches the pattern already used for the nullable protocol return lowering in_lowerReturnValue. The formatter now produces consistent output on swift-syntax 600-603:lowerDictionaryStatementsInlineis the trickier case because its body splices in sub-statements from recursivelowerStatementscalls for the key and value. The dispatch inlowerDictionaryStatementsonly routes.nullableand.closurevalue types into this helper, and both of those paths return single-line lowerings, so the body can be joined as plain indented lines without worrying about nested multi-statement output.2. Iterate lowering statements individually in struct/enum consumers.
StructCodegen.generateStructLowerCodeandEnumCodegen.generatePayloadPushingCodepreviously wrote lowering output viaCodeBlockItemListSyntax(statements).description, which concatenates items without inserting separators when they lack leading trivia.ExportedThunkBuilder.appendsidesteps the problem by explicitly attaching.newlinetrivia to each appended item, but the struct and enum paths had no equivalent step, so any multi-statement lowering (such as the array/dictionary of protocol cases) would be collapsed onto a single line. Iterate the statements and pass each one throughprinter.write(multilineString:)so the printer takes care of line breaks and indentation.3. Regression coverage for the previously untested shapes.
Protocol.swift: add@JS func processDelegatesByName(_:) -> [String: MyViewControllerDelegate]and avar delegatesByName: [String: MyViewControllerDelegate]property onDelegateManagerto exerciselowerProtocolDictionaryStatementsvia both the function-return thunk and the class property getter.DictionaryTypes.swift: add@JS struct Counters { var name: String; var counts: [String: Int?] }and a matchingroundtripCountersfunction to exerciselowerDictionaryStatementsInlineviagenerateStructLowerCode.Without the fixes, the new struct snapshot lands as glued output like:
With the fixes, it renders as:
Verification
Ran the BridgeJS test suite against every swift-syntax version the CI matrix currently exercises, plus 603 which #714 is preparing to add:
All 105-106 tests pass and the snapshots are stable across every version. The fixes leave the codegen output structurally identical for every test input that doesn't exercise the bug, so no unrelated snapshot drift.
Relationship to #714
#714 relaxes the
swift-syntaxconstraint to allow 603 and adds a CI entry for it. Its first snapshot-delta fix already coveredlowerProtocolArrayStatements- this PR can either land independently to eliminate the remaining latent bugs before that matrix entry flips on, or be rebased on top of it so only the two additional helpers plus the struct/enum consumer fix remain.