From a0198c80c6740a5651a204dddcaf157e016e9c07 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 27 Oct 2026 17:18:53 -0500 Subject: [PATCH] Read virtual calls by their kind when the unwind ABI walks a body Without the node index, or for a function the index didn't record, eachNodeOfKinds passes every node of the body, statements too. The unwind ABI's virtual-call pass cast each node to an expression before testing its kind, and the native compiler checks that cast: with SCRIPTC_EMIT_FACTS_VERIFY=1, whose comparison walks every body, it stopped on the first statement. The kind test now narrows the node. --- packages/compiler/src/backend/llvm/unwind-abi.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/compiler/src/backend/llvm/unwind-abi.ts b/packages/compiler/src/backend/llvm/unwind-abi.ts index 1c75a6b82..fdd0a2f18 100644 --- a/packages/compiler/src/backend/llvm/unwind-abi.ts +++ b/packages/compiler/src/backend/llvm/unwind-abi.ts @@ -107,12 +107,13 @@ export function unwindAbiFunctions( const anyClass = new Set(); const virtualCalls = nodes?.scan(VIRTUAL_CALL_KINDS); for (const fn of mod.functions) + // Without the index (or for a function it didn't record) every node + // arrives, statements included: the kind test narrows, not a cast. eachNodeOfKinds(fn, virtualCalls, (node) => { - const e = node as IrExpr; - if (e.kind !== "virtualCall") return true; - if (e.targets !== undefined) for (const target of e.targets) blocked.add(target); - else if (classes.has(e.className)) blocked.add(`%${e.className}.${e.method}`); - else anyClass.add(e.method); + if (node.kind !== "virtualCall") return true; + if (node.targets !== undefined) for (const target of node.targets) blocked.add(target); + else if (classes.has(node.className)) blocked.add(`%${node.className}.${node.method}`); + else anyClass.add(node.method); return true; }); // A hierarchy's vtables hold the methods declared by more than one of its