Skip to content

Fix tuple codec helpers to avoid LSP stack overflows#7611

Merged
JoshuaBatty merged 3 commits intomasterfrom
lsp-bug
May 4, 2026
Merged

Fix tuple codec helpers to avoid LSP stack overflows#7611
JoshuaBatty merged 3 commits intomasterfrom
lsp-bug

Conversation

@JoshuaBatty
Copy link
Copy Markdown
Member

@JoshuaBatty JoshuaBatty commented Apr 29, 2026

Summary

I reproduced an LSP crash where opening and incrementally editing fuel-o2-exports/contracts/order-book/src/main.sw could abort the server and leave stale semantic highlighting behind in the client.

Daniel pointed out that the generated tuple helpers in std::codec are emitted as one large left-associative && chain. This change fixes the root recursion pressure there instead of carrying the LSP stack-size workaround.

The generator change is in sway-lib-std/generate.sh, and the regenerated output is checked in at sway-lib-std/src/codec.sw. The snapshot updates are included because the generated helper shape changes source spans, IR local numbering, bytecode size, and a few gas values in the affected e2e snapshot outputs.

Root cause

The LSP crash was a stack overflow while processing generated std::codec tuple code. The tuple triviality helpers were emitted as deeply left-associated && expressions, e.g. one expression chaining checks across all tuple elements.

Because && is left-associative, that produces a deeply left-leaning AST. Recursive compiler and LSP passes then consume one stack frame per node while lowering, traversing, or building semantic-token state. On the fuel-o2-exports order-book repro, that was enough to bring down the language server and leave stale semantic highlighting in the editor.

The earlier LSP stack-size mitigation kept the process alive by giving those recursive paths more stack. Daniel's suggestion fixes the source-level shape that was creating the stack pressure in the first place.

Why this mitigates it

The tuple helpers now use:

let r = __runtime_mem_id::<Self>() == __encoding_mem_id::<Self>();
let r = r && is_encode_trivial::<A>();
let r = r && is_encode_trivial::<B>();
r

instead of one large chained expression.

That keeps each expression shallow, so compiler and LSP recursion does not scale with the full tuple arity in a single left-deep AST. The language server no longer needs the stack-size workaround for this repro.

Validation

  • regenerated sway-lib-std/src/codec.sw from sway-lib-std/generate.sh
  • verified regeneration produced no extra generated-file diff beyond the checked-in codec.sw
  • verified no generated left-deep tuple triviality chains remain
  • RUSTUP_TOOLCHAIN=1.93.0 cargo build -p forc-lsp --release
  • tested in an isolated VS Code session using the rebuilt target/release/forc-lsp
  • opened fuel-o2-exports/contracts/order-book/src/main.sw
  • exercised the original edit/semantic-highlighting path
  • observed 225 textDocument/didChange notifications and 11 textDocument/semanticTokens/range requests
  • no panic, stack overflow, abort, server exit, or stale-highlighting failure reproduced
  • updated the affected e2e stdout.snap files after CI snapshot drift
  • RUSTUP_TOOLCHAIN=1.93.0 cargo run --locked --release --bin test -- --locked --kind snapshot

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 29, 2026

PR Summary

Medium Risk
Touches generated AbiEncode/AbiDecode implementations for tuples in the standard library; while intended to be semantics-preserving, any mistake could impact ABI (de)serialization behavior across many users.

Overview
Refactors the generated tuple implementations in sway-lib-std/src/codec.sw so is_encode_trivial/is_decode_trivial are built as a series of let r = r && ...; statements instead of a single long left-associative && expression, reducing AST recursion pressure that was crashing the LSP on large tuples.

Updates sway-lib-std/generate.sh to require/use GNU sed (auto-detecting gsed on macOS) and to emit the new tuple helper shape, and refreshes affected e2e snapshot outputs (*.stdout.snap) to match changed spans/IR numbering and minor size/gas deltas.

Reviewed by Cursor Bugbot for commit 692b463. Bugbot is set up for automated code reviews on this repo. Configure here.

@JoshuaBatty JoshuaBatty changed the title [Joshua] Mitigate LSP stack overflows in compile and traversal workers [fix] Mitigate LSP stack overflows in compile and traversal workers Apr 29, 2026
@JoshuaBatty JoshuaBatty requested a review from a team April 29, 2026 21:18
@JoshuaBatty JoshuaBatty added the language server LSP server label Apr 29, 2026
@JoshuaBatty JoshuaBatty self-assigned this Apr 29, 2026
@JoshuaBatty JoshuaBatty changed the title [fix] Mitigate LSP stack overflows in compile and traversal workers [Joshua] Mitigate LSP stack overflows in compile and traversal workers Apr 29, 2026
@JoshuaBatty JoshuaBatty changed the title [Joshua] Mitigate LSP stack overflows in compile and traversal workers Mitigate LSP stack overflows in compile and traversal workers Apr 29, 2026
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 29, 2026

Merging this PR will not alter performance

✅ 25 untouched benchmarks


Comparing lsp-bug (567cc73) with master (27f3d99)

Open in CodSpeed

@JoshuaBatty JoshuaBatty changed the title Mitigate LSP stack overflows in compile and traversal workers [Joshua] Mitigate LSP stack overflows in compile and traversal workers Apr 29, 2026
@JoshuaBatty JoshuaBatty changed the title [Joshua] Mitigate LSP stack overflows in compile and traversal workers Mitigate LSP stack overflows in compile and traversal workers Apr 29, 2026
@JoshuaBatty JoshuaBatty marked this pull request as ready for review April 29, 2026 23:29
@JoshuaBatty JoshuaBatty requested a review from a team as a code owner April 29, 2026 23:29
@JoshuaBatty JoshuaBatty enabled auto-merge (squash) April 30, 2026 05:06
@xunilrj
Copy link
Copy Markdown
Contributor

xunilrj commented May 2, 2026

Would make sense to break the one big expression into multiple ones?

@JoshuaBatty JoshuaBatty changed the title Mitigate LSP stack overflows in compile and traversal workers Fix tuple codec helpers to avoid LSP stack overflows May 3, 2026
@JoshuaBatty JoshuaBatty requested a review from a team as a code owner May 3, 2026 21:36
@JoshuaBatty JoshuaBatty added compiler General compiler. Should eventually become more specific as the issue is triaged lib: std Standard library labels May 3, 2026
@JoshuaBatty JoshuaBatty disabled auto-merge May 3, 2026 22:51
@JoshuaBatty JoshuaBatty marked this pull request as draft May 3, 2026 22:51
@JoshuaBatty
Copy link
Copy Markdown
Member Author

Would make sense to break the one big expression into multiple ones?

Great idea, thanks for pointing this out. I switched the fix over to your suggested approach and removed the LSP stack-size workaround. The tuple codec helpers now avoid the single left-deep && expression and emit shallow statement sequences instead, which fixes the stack pressure at the source rather than just giving the LSP more stack. I also validated this against the original order-book repro and couldn’t reproduce the LSP crash anymore.

@JoshuaBatty JoshuaBatty marked this pull request as ready for review May 3, 2026 23:27
@JoshuaBatty JoshuaBatty requested a review from bitzoic May 3, 2026 23:28
@JoshuaBatty JoshuaBatty merged commit c53e7e0 into master May 4, 2026
41 checks passed
@JoshuaBatty JoshuaBatty deleted the lsp-bug branch May 4, 2026 03:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compiler General compiler. Should eventually become more specific as the issue is triaged language server LSP server lib: std Standard library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants