You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#2235 diagnosed (and this repo's own self-build was the original repro for) a typeMap-collision bug: two different functions in the same file declaring a same-named local/parameter collide under the flat, per-file, name-only typeMap bare key. #2235's fix adds a function-scoped key (${callerName}::${name}) that both engines now seed and consult before the bare fallback, plus fixes ReturnType<typeof fn>-style generic wrappers being extracted as if their own name were a real type. That fix is verified correct and complete for the general scoping-collision case (see the new tests in tests/parsers/javascript.test.ts, tests/integration/issue-2235-typemap-scoping-collision.test.ts, and the Rust unit tests in crates/codegraph-core/src/extractors/javascript.rs).
But: the specific real-world repro that motivated #2235 is still divergent after the fix
Rebuilding this repo's own src/ with both engines (node dist/cli.js build src --engine wasm|native --no-incremental) after #2235's fix lands:
native still resolves openReadonlyOrFail's local db to LockedDatabase (wrong — db is as unknown as BetterSqlite3Database at that line) instead of BetterSqlite3Database, and emits no calls edges to prepare/pragma at all — exactly the behavior #2235 originally reported.
openReadonlyOrFail's own local (const db = new Database(dbPath, { readonly: true }) as unknown as BetterSqlite3Database;, src/db/connection.ts:389) is an as-cast, not a type annotation or a bare new X() — neither engine's handleVarDeclaratorTypeMap/handle_var_declarator_type_map has a branch for as_expression values, so this line contributes nothing to the typeMap in either engine (confirmed by direct extraction dump — no openReadonlyOrFail::db scoped entry exists in either engine's typeMap). #2235's scoped key can only disambiguate a collision when the colliding function's OWN declaration is itself extractable; it can't help when the local declaration is un-extractable to begin with.
With no scoped entry, resolution for openReadonlyOrFail's db.pragma()/db.prepare() falls through to the bare "db" key (or, when that's also empty/wrong, a global proximity fallback at confidence 0.6). The bare key's value depends on which other function in the file wins it — and that's where the engines diverge:
src/db/connection.ts:178 — export function closeDb(db: LockedDatabase): void {} seeds bare "db" = "LockedDatabase" @ 0.9 (a genuine, correctly-scoped-but-irrelevant-here entry) in both engines.
src/db/connection.ts:607 / :673 — const db = openReadonlyOrFail(customDbPath, busyTimeoutMs); triggers the Phase 8.2 return-type-propagation branch (handleCallExprTypeMap / handle_var_declarator_type_map's call_expression branch), which looks up openReadonlyOrFail's own return type (): BetterSqlite3Database at :380, confidence 1.0) and propagates it onto that call site's own db local.
wasm ends up with "BetterSqlite3Database" winning the bare key (by whatever confidence/insertion-order the propagation branch produces there); native does not — the two engines are seeding the bare "db" key with genuinely different final values from this same propagation mechanism. This is an insertion-order/confidence discrepancy in the return-type-propagation branch itself, not a scoping problem — #2235's own scope note flagged auditing this as a separate, optional avenue distinct from the scoping fix it committed to.
Suggested follow-up
Instrument/compare both engines' raw type_map/return_type_map output for src/db/connection.ts end-to-end (not just the final DB edges) to find exactly where the propagated confidence or dedup/insertion order first diverges between handleCallExprTypeMap's resolveCallExprReturnType(valueN, typeMap, returnTypeMap, 0) (TS) and the equivalent inline block in handle_var_declarator_type_map (Rust, crates/codegraph-core/src/extractors/javascript.rs around the same_file_entry/propagated block).
Separately (lower priority, larger scope): consider whether as unknown as X / as X casts should seed a typeMap entry at all (currently silently dropped in both engines) — that would make openReadonlyOrFail's own scoped key correct at the source and stop depending on bare-key propagation luck entirely. This overlaps with typeMap collisions across same-named locals in different functions cause native/wasm divergence (residual gap after #1949) #2235's ReturnType<typeof fn> fix in spirit (both are about not letting an unresolvable/complex annotation-or-cast either poison or starve the typeMap) but is a distinct extraction gap on its own.
Context
#2235 diagnosed (and this repo's own self-build was the original repro for) a typeMap-collision bug: two different functions in the same file declaring a same-named local/parameter collide under the flat, per-file, name-only typeMap bare key. #2235's fix adds a function-scoped key (
${callerName}::${name}) that both engines now seed and consult before the bare fallback, plus fixesReturnType<typeof fn>-style generic wrappers being extracted as if their own name were a real type. That fix is verified correct and complete for the general scoping-collision case (see the new tests intests/parsers/javascript.test.ts,tests/integration/issue-2235-typemap-scoping-collision.test.ts, and the Rust unit tests incrates/codegraph-core/src/extractors/javascript.rs).But: the specific real-world repro that motivated #2235 is still divergent after the fix
Rebuilding this repo's own
src/with both engines (node dist/cli.js build src --engine wasm|native --no-incremental) after #2235's fix lands:native still resolves
openReadonlyOrFail's localdbtoLockedDatabase(wrong —dbisas unknown as BetterSqlite3Databaseat that line) instead ofBetterSqlite3Database, and emits nocallsedges toprepare/pragmaat all — exactly the behavior #2235 originally reported.Why #2235's fix doesn't reach this case
openReadonlyOrFail's own local (const db = new Database(dbPath, { readonly: true }) as unknown as BetterSqlite3Database;,src/db/connection.ts:389) is anas-cast, not a type annotation or a barenew X()— neither engine'shandleVarDeclaratorTypeMap/handle_var_declarator_type_maphas a branch foras_expressionvalues, so this line contributes nothing to the typeMap in either engine (confirmed by direct extraction dump — noopenReadonlyOrFail::dbscoped entry exists in either engine's typeMap). #2235's scoped key can only disambiguate a collision when the colliding function's OWN declaration is itself extractable; it can't help when the local declaration is un-extractable to begin with.With no scoped entry, resolution for
openReadonlyOrFail'sdb.pragma()/db.prepare()falls through to the bare"db"key (or, when that's also empty/wrong, a global proximity fallback at confidence 0.6). The bare key's value depends on which other function in the file wins it — and that's where the engines diverge:src/db/connection.ts:178—export function closeDb(db: LockedDatabase): void {}seeds bare"db"="LockedDatabase"@ 0.9 (a genuine, correctly-scoped-but-irrelevant-here entry) in both engines.src/db/connection.ts:607/:673—const db = openReadonlyOrFail(customDbPath, busyTimeoutMs);triggers the Phase 8.2 return-type-propagation branch (handleCallExprTypeMap/handle_var_declarator_type_map's call_expression branch), which looks upopenReadonlyOrFail's own return type (): BetterSqlite3Databaseat:380, confidence 1.0) and propagates it onto that call site's owndblocal.wasm ends up with
"BetterSqlite3Database"winning the bare key (by whatever confidence/insertion-order the propagation branch produces there); native does not — the two engines are seeding the bare"db"key with genuinely different final values from this same propagation mechanism. This is an insertion-order/confidence discrepancy in the return-type-propagation branch itself, not a scoping problem — #2235's own scope note flagged auditing this as a separate, optional avenue distinct from the scoping fix it committed to.Suggested follow-up
type_map/return_type_mapoutput forsrc/db/connection.tsend-to-end (not just the final DB edges) to find exactly where the propagated confidence or dedup/insertion order first diverges betweenhandleCallExprTypeMap'sresolveCallExprReturnType(valueN, typeMap, returnTypeMap, 0)(TS) and the equivalent inline block inhandle_var_declarator_type_map(Rust,crates/codegraph-core/src/extractors/javascript.rsaround thesame_file_entry/propagatedblock).as unknown as X/as Xcasts should seed a typeMap entry at all (currently silently dropped in both engines) — that would makeopenReadonlyOrFail's own scoped key correct at the source and stop depending on bare-key propagation luck entirely. This overlaps with typeMap collisions across same-named locals in different functions cause native/wasm divergence (residual gap after #1949) #2235'sReturnType<typeof fn>fix in spirit (both are about not letting an unresolvable/complex annotation-or-cast either poison or starve the typeMap) but is a distinct extraction gap on its own.