Skip to content

Commit aca4b46

Browse files
authored
fix(native): expand super-dispatch edges into CHA sibling overrides (#1544)
* fix(native): expand super-dispatch edges into CHA sibling overrides (#1544) runPostNativeCha was filtering out edges with technique='cha', which prevented it from expanding the super.method() → Parent.method edges inserted by runPostNativeThisDispatch (which also uses technique='cha'). Additionally, runPostNativeCha was running before runPostNativeThisDispatch, so the super-dispatch seed edges were not yet in the DB when the BFS expansion ran. Two changes fix parity with WASM: 1. Reorder so runPostNativeThisDispatch runs first, putting the technique='cha' seed edges in the DB before the expansion pass reads them. 2. Rename the CHA expansion output to technique='cha-expanded' and update both filter queries (native and WASM runChaPostPass) from != 'cha' to != 'cha-expanded'. This lets the expansion pass see 'cha'-tagged super-dispatch edges while still preventing infinite re-expansion of its own output edges. After this fix, native produces 6 CHA edges that WASM already emitted (e.g. PostMixin.m → B.m across jelly-micro fixtures where PostMixin and B both extend A). Closes #1544 * fix(cha): renumber CHA expansion post-pass to Phase 8.6 runPostNativeThisDispatch now runs before runPostNativeCha, making the previous dual "Phase 8.5" labels misleading. Renumber the CHA expansion pass (runPostNativeCha) to Phase 8.6 so the orchestrator numbering is monotonic and matches execution order.
1 parent 40b2d14 commit aca4b46

2 files changed

Lines changed: 30 additions & 22 deletions

File tree

src/domain/graph/builder/helpers.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ export const BUILTIN_RECEIVERS: Set<string> = new Set([
4848
'require',
4949
]);
5050

51-
/** Phase 8.5: confidence penalty applied to CHA-dispatch edges. */
51+
/** Phase 8.6: confidence penalty applied to CHA-dispatch edges. */
5252
export const CHA_DISPATCH_PENALTY = 0.1;
53-
/** Phase 8.5: fixed confidence for typed-receiver (interface/CHA) dispatch edges.
53+
/** Phase 8.6: fixed confidence for typed-receiver (interface/CHA) dispatch edges.
5454
* File proximity is not meaningful for virtual dispatch — all three engine paths
5555
* (WASM inline, WASM post-pass, native post-pass) must agree on this value. */
5656
export const CHA_TYPED_DISPATCH_CONFIDENCE = 0.8;
@@ -470,7 +470,7 @@ export function runChaPostPass(db: BetterSqlite3Database): number {
470470
JOIN nodes src ON e.source_id = src.id
471471
WHERE e.kind = 'calls' AND tgt.kind = 'method'
472472
AND INSTR(tgt.name, '.') > 0
473-
AND (e.technique IS NULL OR e.technique != 'super-dispatch')`,
473+
AND (e.technique IS NULL OR e.technique != 'cha-expanded')`,
474474
)
475475
.all() as Array<{ source_id: number; caller_name: string; method_name: string }>;
476476

@@ -533,7 +533,7 @@ export function runChaPostPass(db: BetterSqlite3Database): number {
533533
'calls',
534534
CHA_TYPED_DISPATCH_CONFIDENCE,
535535
0,
536-
'cha',
536+
'cha-expanded',
537537
]);
538538
}
539539
}

src/domain/graph/builder/stages/native-orchestrator.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ async function runPostNativeAnalysis(
390390
}
391391

392392
/**
393-
* Phase 8.5: CHA expansion post-pass for the native orchestrator path.
393+
* Phase 8.6: CHA expansion post-pass for the native orchestrator path.
394394
*
395395
* The Rust build pipeline resolves typed receiver calls (e.g. `worker.doWork()`
396396
* where `worker: IWorker`) to the interface method declaration only. This
@@ -597,7 +597,7 @@ function runPostNativeCha(
597597
JOIN nodes src ON e.source_id = src.id
598598
WHERE e.kind = 'calls' AND tgt.kind = 'method'
599599
AND INSTR(tgt.name, '.') > 0
600-
AND (e.technique IS NULL OR e.technique != 'super-dispatch')
600+
AND (e.technique IS NULL OR e.technique != 'cha-expanded')
601601
AND src.file IN (${ph})`,
602602
)
603603
.all(...chunk) as Array<{
@@ -618,7 +618,7 @@ function runPostNativeCha(
618618
JOIN nodes src ON e.source_id = src.id
619619
WHERE e.kind = 'calls' AND tgt.kind = 'method'
620620
AND INSTR(tgt.name, '.') > 0
621-
AND (e.technique IS NULL OR e.technique != 'super-dispatch')
621+
AND (e.technique IS NULL OR e.technique != 'cha-expanded')
622622
`)
623623
.all() as Array<{
624624
source_id: number;
@@ -685,7 +685,7 @@ function runPostNativeCha(
685685
if (seen.has(key)) continue;
686686
seen.add(key);
687687
const conf = CHA_TYPED_DISPATCH_CONFIDENCE;
688-
newEdges.push([source_id, methodNode.id, 'calls', conf, 0, 'cha']);
688+
newEdges.push([source_id, methodNode.id, 'calls', conf, 0, 'cha-expanded']);
689689
newEdgeCount++;
690690
if (caller_file) affectedFiles.add(caller_file);
691691
if (methodNode.method_file) affectedFiles.add(methodNode.method_file);
@@ -1600,10 +1600,31 @@ export async function tryNativeOrchestrator(
16001600
}
16011601
const gapDetectMs = performance.now() - gapDetectStart;
16021602

1603-
// Phase 8.5: expand CHA call edges (interface dispatch → concrete implementations).
1603+
// Phase 8.5: this/super dispatch — hybrid WASM re-parse to resolve call sites
1604+
// whose raw receiver info the Rust pipeline does not persist to DB.
1605+
// Runs BEFORE the CHA expansion pass so that super.method() → Parent.method edges
1606+
// (technique='cha') are in the DB when runPostNativeCha expands them to sibling
1607+
// class overrides (e.g. PostMixin.m → B.m when PostMixin and B both extend A).
1608+
const {
1609+
elapsedMs: thisDispatchMs,
1610+
targetIds: thisDispatchTargetIds,
1611+
affectedFiles: thisDispatchAffectedFiles,
1612+
} = await runPostNativeThisDispatch(
1613+
ctx.db as unknown as BetterSqlite3Database,
1614+
ctx.rootDir,
1615+
result.changedFiles,
1616+
!!result.isFullBuild,
1617+
);
1618+
1619+
// Phase 8.6: expand CHA call edges (interface dispatch → concrete implementations).
16041620
// Returns the affected files so role re-classification below can be scoped to
16051621
// the nodes whose fan-in/out actually changed.
16061622
//
1623+
// Runs AFTER this/super dispatch so super.method() edges are already in the DB.
1624+
// The 'cha-expanded' technique tag on this pass's own output prevents re-expansion
1625+
// of those edges in subsequent incremental builds, while 'cha'-tagged edges from
1626+
// this/super dispatch remain eligible for expansion here.
1627+
//
16071628
// Function-as-object-property methods (`fn.method = function() {}`) are extracted
16081629
// natively by the Rust engine (#1432) and resolved in-build by its edge builder, so
16091630
// no WASM re-parse post-pass is needed for them. `Foo.prototype.bar = fn` likewise.
@@ -1615,19 +1636,6 @@ export async function tryNativeOrchestrator(
16151636
);
16161637
const chaMs = performance.now() - chaStart;
16171638

1618-
// Phase 8.5: this/super dispatch — hybrid WASM re-parse to resolve call sites
1619-
// whose raw receiver info the Rust pipeline does not persist to DB.
1620-
const {
1621-
elapsedMs: thisDispatchMs,
1622-
targetIds: thisDispatchTargetIds,
1623-
affectedFiles: thisDispatchAffectedFiles,
1624-
} = await runPostNativeThisDispatch(
1625-
ctx.db as unknown as BetterSqlite3Database,
1626-
ctx.rootDir,
1627-
result.changedFiles,
1628-
!!result.isFullBuild,
1629-
);
1630-
16311639
// Role re-classification after JS edge-writing post-passes.
16321640
// The Rust orchestrator classifies roles before these post-passes (CHA,
16331641
// this-dispatch) add edges, so roles for the edge endpoints are stale.

0 commit comments

Comments
 (0)