mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-27 04:49:43 +08:00
fix(swift): a call written after try! links what it calls on Windows (#2683)
The Windows kernels read the `!` of every `try!` as a logical not, so `try! Message2(data: d)` became a call of `! Message2` that never resolves, and a call through a receiver lost it: `try! Settings.Defaults.load()` was a bare `load`. The cause is the grammar's C, not the walker. tree-sitter-swift 0.7.3's external scanner steps aside for the `!` of `try!` through a 64-bit mask whose entry is built as `1UL << FAKE_TRY_BANG`, bit 32. `unsigned long` is 32 bits on Windows and MSVC folds the overflowing shift to 0 (warning C4293), so the scanner never stepped aside: `try` parsed alone, then a prefix `!` on the callee. macOS and Linux have 64-bit longs, and clang's wasm32 build folds the shift to bit 31 (`_directive_endif`, valid at every expression start), so the wasm and the other kernels have always read `try!` right. The kernel now compiles the crate tarball's src/ itself, from codegraph-kernel/grammars/swift, with upstream 0.7.4's one-line fix (`1ULL`), as it already does for the Kotlin, Lua, Scala and Dart grammars. The patch and its provenance are in docs/grammars/tree-sitter-swift.patch and .md. parser.c is unchanged, so the node-kind and field tables still match the wasm, which is untouched. TortureTry.swift pins calls after try!, try? and try on both engines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
22e9f7b337
commit
c58f0417c6
@@ -43,6 +43,12 @@ at survey time: exactly 348) ride it (§Dedicated property branch).
|
||||
|
||||
## Grammar prep (NOT staged — land FIRST, before any walker exists)
|
||||
|
||||
> **Update 2026-10-19:** the kernel no longer depends on the crate. It
|
||||
> compiles the same tarball's `src/` from `codegraph-kernel/grammars/swift/`
|
||||
> with a one-line scanner patch, because the crate's MSVC build misread every
|
||||
> `try!` on Windows (`docs/grammars/tree-sitter-swift.md`). The wasm below is
|
||||
> unchanged.
|
||||
|
||||
swift is **not** in `VENDORED_WASM_LANGS` (grammars.ts:291) — production loads
|
||||
`require.resolve('tree-sitter-wasms/out/tree-sitter-swift.wasm')` (mapping
|
||||
`swift: 'tree-sitter-swift.wasm'` at grammars.ts:34; `.swift` → swift at
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# tree-sitter-swift — provenance & the kernel's scanner patch
|
||||
|
||||
The kernel's vendored C (`codegraph-kernel/grammars/swift/`) is the `src/` of
|
||||
the [alex-pinkus/tree-sitter-swift](https://github.com/alex-pinkus/tree-sitter-swift)
|
||||
(MIT) **0.7.3 crates.io tarball** — the same files
|
||||
`src/extraction/wasm/tree-sitter-swift.wasm` is built from (see
|
||||
`docs/design/swift-kernel-port-checklist.md` §Grammar prep for why the
|
||||
tarball and not the tag) — with the patch in `tree-sitter-swift.patch`
|
||||
applied to `src/scanner.c`. The wasm is built from the unpatched tarball.
|
||||
|
||||
| file | upstream sha256 | patched sha256 |
|
||||
|---|---|---|
|
||||
| `src/parser.c` | `d3edff6effe31b9a507f496577407987343b101b23eb7bee7a9b050e8ab5d27a` | unchanged |
|
||||
| `src/scanner.c` | `f3d6271d64f58c39eed544104a70ca2cf9ecbf80c5d900620f1afd38836542cb` | `8acafef098ea4a52ebfc4cdf2fe26706113a22ac8ba2faf7d952755ff350cad6` |
|
||||
|
||||
## What the patch fixes
|
||||
|
||||
The external scanner produces its own `!` token, and steps aside for a `!`
|
||||
written straight after `try` so the parser can read `try!`. It finds those
|
||||
positions through a 64-bit mask whose entry for `!` is built as
|
||||
`1UL << FAKE_TRY_BANG`, bit 32. Where `unsigned long` is 32 bits that shift
|
||||
overflows, and each compiler folds it differently:
|
||||
|
||||
- **MSVC** — both Windows kernels (`x86_64`/`aarch64-pc-windows-msvc`) — folds
|
||||
it to 0 (warning C4293). The scanner never steps aside, so
|
||||
`try! Message2(data: d)` parsed as `try` followed by a call of `!Message2`:
|
||||
the call was named `! Message2` and linked nothing, and a call through a
|
||||
type, `try! Settings.Defaults.load()`, lost its receiver.
|
||||
- **clang for wasm32** (the wasm) folds it to bit 31, `_directive_endif`,
|
||||
which is valid at every expression start — right after `try` too — so the
|
||||
wasm reads `try!` correctly. Its one other effect: a prefix `!` at an
|
||||
expression start is lexed by the parser's own lexer, which leaves an
|
||||
anonymous `!` token under `bang` where the scanner's token is hidden. No
|
||||
walker reads it.
|
||||
- **macOS and Linux** kernels (64-bit `unsigned long`) were always correct.
|
||||
|
||||
The patch is upstream 0.7.4's one-line fix, `1ULL`. Measured on 2026-10-09
|
||||
over 1,172 Swift files (Alamofire, SDWebImage, protobuf, realm-swift,
|
||||
swift-nio, vapor and six smaller projects): the patched native build parses
|
||||
every error-free file to the same tree as the wasm, apart from that anonymous
|
||||
`!`. The 8 files that differ have parse errors on both, and the kernel defers
|
||||
a file with parse errors to the wasm. The unpatched MSVC build misparsed 157
|
||||
error-free files, every one at a `try!`.
|
||||
|
||||
## Rebuild
|
||||
|
||||
```
|
||||
curl -sL https://crates.io/api/v1/crates/tree-sitter-swift/0.7.3/download -o ts-swift-0.7.3.crate
|
||||
tar xzf ts-swift-0.7.3.crate && cd tree-sitter-swift-0.7.3
|
||||
git apply /path/to/codegraph/docs/grammars/tree-sitter-swift.patch
|
||||
cp src/parser.c src/scanner.c /path/to/codegraph/codegraph-kernel/grammars/swift/
|
||||
cp src/tree_sitter/*.h /path/to/codegraph/codegraph-kernel/grammars/swift/tree_sitter/
|
||||
```
|
||||
|
||||
Then rebuild the kernel (`npm run build:kernel`) and run
|
||||
`__tests__/kernel-grammar-parity.test.ts` and `scripts/kernel-parity.mjs
|
||||
--lang swift` on a Swift repo: the wasm and the kernel must parse the same.
|
||||
A bump to a release that carries the fix (0.7.4 or later) can drop the patch
|
||||
and the vendored copy: pin the crate in `codegraph-kernel/Cargo.toml` again
|
||||
and rebuild the wasm from the same tarball, together.
|
||||
@@ -0,0 +1,13 @@
|
||||
--- a/src/scanner.c 2026-10-09 00:00:00
|
||||
+++ b/src/scanner.c 2026-10-09 00:00:00
|
||||
@@ -128,7 +128,9 @@
|
||||
0, // EQ_EQ,
|
||||
0, // PLUS_THEN_WS,
|
||||
0, // MINUS_THEN_WS,
|
||||
- 1UL << FAKE_TRY_BANG, // BANG,
|
||||
+ // 1ULL, as upstream has it from 0.7.4: 1UL << 32 overflows where unsigned
|
||||
+ // long is 32 bits (MSVC), and `try!` lost its `!`. (codegraph patch)
|
||||
+ 1ULL << FAKE_TRY_BANG, // BANG,
|
||||
0, // THROWS_KEYWORD,
|
||||
0, // RETHROWS_KEYWORD,
|
||||
0, // DEFAULT_KEYWORD,
|
||||
Reference in New Issue
Block a user