Context
Phase 8.3 implemented a field-based points-to analysis for the JS/TS fallback edge-building path (buildCallEdgesJS). The native Rust path (buildCallEdgesNative) does not benefit because the constraint solver lives entirely in JS/TS and is not forwarded to the Rust FFI.
Both engines must produce identical results (per CLAUDE.md). Currently the native engine produces fewer call edges than the WASM/JS path for code using function-reference aliases.
What needs to happen
-
Serialize fnRefBindings — add fn_ref_bindings to the NativeFileEntry FFI struct (already defined in build-edges.ts and passed to native.buildCallEdges). The FnRefBinding shape (lhs, rhs, rhs_receiver) is simple and maps cleanly to a Rust struct.
-
Implement the constraint solver in Rust — mirror buildPointsToMap / resolveViaPointsTo from src/domain/graph/resolver/points-to.ts in the native crate (crates/codegraph-core/src/). The algorithm is Andersen-style fixed-point propagation (≤ 50 iterations), already small enough to inline into the call-edge builder.
-
Apply pts fallback in native call-edge builder — when the Rust resolver finds no targets for a dynamic=true, receiver-less call, consult the pts map and retry.
-
Parity test — add a resolution parity test case that includes a const fn = handler; arr.map(fn) pattern and asserts both engines emit the same call edge to handler.
Related
Context
Phase 8.3 implemented a field-based points-to analysis for the JS/TS fallback edge-building path (
buildCallEdgesJS). The native Rust path (buildCallEdgesNative) does not benefit because the constraint solver lives entirely in JS/TS and is not forwarded to the Rust FFI.Both engines must produce identical results (per CLAUDE.md). Currently the native engine produces fewer call edges than the WASM/JS path for code using function-reference aliases.
What needs to happen
Serialize
fnRefBindings— addfn_ref_bindingsto theNativeFileEntryFFI struct (already defined inbuild-edges.tsand passed tonative.buildCallEdges). TheFnRefBindingshape (lhs,rhs,rhs_receiver) is simple and maps cleanly to a Rust struct.Implement the constraint solver in Rust — mirror
buildPointsToMap/resolveViaPointsTofromsrc/domain/graph/resolver/points-to.tsin the native crate (crates/codegraph-core/src/). The algorithm is Andersen-style fixed-point propagation (≤ 50 iterations), already small enough to inline into the call-edge builder.Apply pts fallback in native call-edge builder — when the Rust resolver finds no targets for a
dynamic=true, receiver-less call, consult the pts map and retry.Parity test — add a resolution parity test case that includes a
const fn = handler; arr.map(fn)pattern and asserts both engines emit the same call edge tohandler.Related