fix: grow the ts_lsp AST walk stacks so wide files keep every declaration - #2091
fix: grow the ts_lsp AST walk stacks so wide files keep every declaration#2091CaptainMittens wants to merge 2 commits into
Conversation
…tion Three walks in internal/cbm/lsp/ts_lsp.c held at most 256 AST nodes in a fixed array and stopped pushing when it filled. Nothing reported the stop, so the passes answered as if they had seen the whole file. In rebuild_signatures_from_ast and convert_signature_type_params the seeding loop alone can fill all 256 slots, because it pushes every top-level child of the file. A file with more than 256 top-level declarations therefore skipped every declaration past that point: each one kept whatever signature the first extraction pass had guessed, and a generic function past the cap kept NAMED instead of TYPE_PARAM, so calls through it stopped resolving. In infer_return_type_from_body the same cap made a wide function body answer "unknown return type" for a return the walk had never reached. The repo already carries the module that solves this: internal/cbm/extract_node_stack.h, written for GitHub issue DeusData#199 to replace fixed TSNode stack[] arrays that silently drop subtrees. Nine extract files use it; ts_lsp.c was never converted. This converts it. The header gains ts_nstack_init_arena, which takes an arena directly, because the LSP passes hold a TSLSPContext rather than a CBMExtractCtx. ts_nstack_init keeps its context argument, which is what makes handing over the wrong arena a type error, and now delegates to the new function. Traversal order changes from last-child-first to first-child-first, because ts_nstack_push_children reverses on push. That also drops an O(N^2) ts_node_child(n, i) loop for one cursor pass. For infer_return_type_from_body the new order matches the comment the function already carried: it finds the first return, where the old code found the last. New test tslsp_stress_declarations_past_stack_cap makes the same claim as tslsp_generic_identity_inference, 300 declarations deeper in the file. Without this change it fails with "MISSING resolved call: caller~.go -> callee~use"; with it the ts_lsp suite is 304 passed, 0 failed. Signed-off-by: Joshua Richter <jrichter5781@gmail.com>
|
Thanks for opening this — it has been seen, and it is queued. This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence. Current review status: working through a backlog. What that means for this PR, concretely:
Things that will genuinely speed it up whenever review does happen:
If this fixes a bug, a reproduction we can run is worth more than a description of the symptom. Thanks for contributing, and sorry in advance for the wait. |
The first commit converted three walks in ts_lsp.c but tested only two of them. infer_return_type_from_body was changed without a test of its own. tslsp_stress_return_past_stack_cap makes the same claim as the existing tslsp_return_inferred_local, with the return placed after 300 statements — more than the 256 slots the old fixed array held, so the walk used to stop before reaching it and answer "unknown return type". Without the fix the suite is 303 passed, 2 failed, the second failure being this test. With it, 305 passed. Signed-off-by: Joshua Richter <jrichter5781@gmail.com>
|
Three things say it is unrelated:
I cannot re-run the job myself ( |
The problem
Three AST walks in
internal/cbm/lsp/ts_lsp.cheld at most 256 nodes in a fixedTSNode stack[256]and stopped pushing when it filled. Nothing reported the stop, so each pass answered as if it had seen the whole file.In
rebuild_signatures_from_astandconvert_signature_type_paramsthe seeding loop alone can fill all 256 slots, because it pushes every top-level child of the file. A file with more than 256 top-level declarations therefore skipped every declaration past that point. Each one kept whatever signature the first extraction pass had guessed, and a generic function past the cap keptNAMEDwhere it neededTYPE_PARAM, so calls through it stopped resolving.In
infer_return_type_from_bodythe same cap made a wide function body answer "unknown return type" for areturnthe walk had never reached.The fix
The repo already carries the module that solves this:
internal/cbm/extract_node_stack.h, written for #199 to replace fixedTSNode stack[]arrays that silently drop AST subtrees. Nine extract files use it.ts_lsp.cwas never converted. This converts it.The header gains
ts_nstack_init_arena, which takes an arena directly, because the LSP passes hold aTSLSPContextrather than aCBMExtractCtx.ts_nstack_initkeeps its context argument — that argument is what makes handing over the wrong arena a type error — and now delegates to the new function, so its behaviour is unchanged.Two things follow from using the shared module:
ts_nstack_push_childrenreverses on push. Forinfer_return_type_from_bodythe new order matches the comment the function already carried: it finds the firstreturn, where the old code found the last.O(N^2)loop goes away.ts_nstack_push_childrendoes a single cursor pass instead ofts_node_child(n, i)per child.Which arena
The stacks are cut from
ctx->arena.collect_childrenatts_lsp.c:201already allocates the same kind of per-file scratch from that arena, and the per-file scratch arena added in #1997 never reachescbm_run_ts_lsp—cbm.c:1690passesa. Threading a second arena into this file would touch every allocation in it, which is a larger change than this fix needs.Test
Two tests, one per observable site. Each repeats an existing passing test's claim, moved past the old cap:
tslsp_stress_declarations_past_stack_cap— the claim oftslsp_generic_identity_inference, 300 top-level declarations deeper. Coversconvert_signature_type_params.tslsp_stress_return_past_stack_cap— the claim oftslsp_return_inferred_local, with thereturnbehind 300 statements. Coversinfer_return_type_from_body.Without this change the suite is
303 passed, 2 failed, both failures being these two. With it,305 passed, 0 failed.rebuild_signatures_from_asthas no test of its own: it shares the seeding shape withconvert_signature_type_params, and I could not find an observable difference it produces alone that the first test does not already cover.The full local suite is
7949 passed, 2 failed, 7 skipped. Both failures aresubprocess_run_cleanandsubprocess_run_exit_nonzero, which returnCBM_PROC_SPAWN_FAILEDbecause my local sandbox blocksfork/execof/bin/sh. Nothing in this diff reachesforkorexec, so they are unrelated to it; I did not re-run the full suite on the reverted tree, only thets_lspsuite.