Repository navigation
[TypeScript] Same-name overload signatures collapse to one — detector.py drops 6 of 7 bodyless pipeable overloads #2278
Description
Follow-up/continuation of #2219 — the ledger shape typescript/function/existence/agree[ctags,tree_sitter]_vs[gitgalaxy] (7 occurrences) is still still_reproduces: true after re-reconciling today, even though #2219's regex fix (widening the arrow-function branch's generics tolerance) is confirmed landed and working for the standalone-function case. Root-caused precisely this time, and it's a different bug from #2219 despite sharing a symptom.
Real example, fp-ts/pipeable.ts:2344-2520 — 7 consecutive TypeScript function-overload signatures, 6 bodyless (terminated by the next /** @deprecated */ / next overload, no {), 1 with a real body:
export function pipeable<F extends URIS3, I>(
I: { readonly URI: F } & I
): (I extends Chain3<F>
? PipeableChain3<F>
...
: {}) &
(I extends Contravariant3<F> ? PipeableContravariant3<F> : {}) &
...
/** @deprecated */
export function pipeable<F extends URIS3, I, E>(
...
// ... 5 more overloads, same shape ...
export function pipeable<F, I>(I: { readonly URI: F } & I): Record<string, unknown> {
const r: any = {}
if (isFunctor<F>(I)) {
...
}tree-sitter and ctags both correctly report all 7 as distinct pipeable occurrences (confirmed via the ledger's own last_seen_examples, lines 2344/2374/2404/2433/2463/2490/2520 — all present in both other tools' readings).
Confirmed NOT a regex miss — tested LANGUAGE_DEFINITIONS["typescript"]["rules"]["func_start"] directly against the isolated overload text: it matches pipeable fine, including the multi-line generic-bound signature. This is the same regex #2219 already fixed for the single-signature case.
Confirmed a detector.py body-slicing/dedup bug, via galaxyscope --db-only against fp-ts/pipeable.ts (step 2b of this repo's tri-comparison-ledger-sweep skill):
SELECT struct_func_start, function_count FROM file_data WHERE file_path LIKE '%pipeable.ts%';
-- struct_func_start=224 function_count=217 (raw regex signal vs. named list: off by exactly 7)
SELECT func_name, start_line FROM function_data WHERE func_name = 'pipeable';
-- only ONE row: (pipeable, 2520) -- the sole body-bearing overloadThe raw signal count (computed independently of body-slicing) sees all 7 pipeable matches; the named list that actually reaches function_data (and therefore every downstream consumer — LLM briefs, SARIF, risk scoring) keeps only the one WITH a real {...} body, at line 2520. The 6 bodyless overload signatures are silently swallowed somewhere in detector.py's per-function slicing/naming path — most likely a same-name dedup or a brace-matching step that treats the bodyless overloads as incomplete/orphaned matches and drops them rather than emitting a signature-only occurrence for each.
Suspected mechanism (not yet pinned to an exact line): each bodyless overload's return-type annotation contains literal {} (empty-object-type intersection members, e.g. : {}) &) — if _slice_by_braces treats the first { after a func_start match as the body opener regardless of whether it's really a block vs. a type-level brace, it would misattribute/consume the wrong span and could plausibly explain the collapse, but this needs a real detector.py trace to confirm rather than staying a guess.
Confirmed scope: exactly 7 occurrences, all in this one file/shape (multi-overload same-name function declarations with a type-heavy bodyless signature) — the ledger's own capped example list already has the complete set (7 ≤ the 10-example cap), so this is unlikely to be under-counted.
Why not fixed inline: root cause is inside detector.py's shared slicing/naming path, not an isolated per-language regex — needs an actual trace through that code before a safe fix, and any fix there risks rippling into every Mode B language's overload/bodyless-declaration handling, not just TypeScript. Filing per this repo's scope discipline (diagnose precisely, fix separately) rather than shipping an unverified change to shared slicing logic.
Activity
squid-protocol commentedon Aug 26, 2026
Second confirmed instance of the same mechanism, found continuing the same sweep:
vscode/instantiationService.ts:116-118—Same shape as
pipeable: 2 bodyless overload signatures + 1 body-bearing implementation, same name. GitGalaxy'sfunction_datakeeps only the implementation, matching thestruct_func_startvs.function_countsplit already confirmed forpipeable. Also confirms this isn't specific to files with only bodyless overloads (likefp-ts/pipeable.ts) — it recurs in an ordinary implementation file too, wherever a real function has TS overload signatures declared above it. Raises confidence this is a systemic detector.py mechanism, not a corpus-specific quirk. Also found 2 same-namedconstructoroccurrences and 1cancel()dropped invscode/async.ts(lines 2526-2537,CancelableAsyncIterableProducerclass) that look like the same collapse mechanism triggered by multiple classes sharing the name `constructor" in one file, though not root-caused as precisely as the overload case above.Root-cause and file GitHub issues for TypeScript's real func_start re…
fix(typescript): guard against async-as-name and bless golden masters
chore: bless golden masters + tree-sitter baseline for #2277's fix
fix(typescript): recognize arrow/method-shorthand defs not at line st…
chore: re-bless golden masters against merged main (#2276+#2277+#2278)
Merge origin/main into fix/typescript-2279-bodyless-notype (round 2)
call resolver (ts/js): only a binding is bare-callable; signatures ar…