Found during round-6 review of #2612 (issue-2088's implementation plan).
Problem
docs/plans/issue-2088.md's escape analysis (WU-2) now correctly excludes a bare (non-call) member/subscript read from the tracked-reference set — T's parent is member_expression in const f = T.k; exactly as it is in T.k(), but only the latter is a call, and collectInvokedPropertySites only records evidence for calls. So:
const T = { alpha: fnA };
const f = T.alpha;
f();
correctly marks T escaping (no correlated evidence can exist for alpha through this reference), falling back to T2. But T2 also cannot help here unless some unrelated .alpha(...) call happens to exist elsewhere in the build by coincidence — f() itself is never translated into "credit alpha as invoked" by any existing mechanism. Per round-6 review: "const f = T.k produces an fnRefBinding keyed T.k that nothing seeds" — the pre-existing, general local-function-alias tracking (fnRefBindings, which already handles whole-object aliases like const u = T) does not bridge a property-VALUE alias back to the object-literal value-ref mechanism.
Impact
Recall-only: f() is a real, correct invocation of fnA in actual program semantics, but codegraph has no channel that can currently prove it — with or without #2088. roles --role dead reports such a case dead both before and after #2088 — correctly conservative (no false claim of liveness), but incomplete (a real false negative for "is this dead").
Suggested fix shape (not binding — decide at execute/fix time)
Extend fnRefBindings (or add a sibling channel) to also key a variable_declarator whose value is directly T.k (a member/subscript expression, not just a bare identifier) as an alias of that property's value-ref, then let the existing alias-resolution machinery (already used for whole-object aliases) treat f() as equivalent to T.k() for evidence purposes — subject to f's own subsequent references being fully tracked too, recursively, the same way the whole-object alias branch already requires (round-4 fix to allReferencesTracked's rebinding branch).
Where
Found during round-6 review of #2612 (issue-2088's implementation plan).
Problem
docs/plans/issue-2088.md's escape analysis (WU-2) now correctly excludes a bare (non-call) member/subscript read from the tracked-reference set —T's parent ismember_expressioninconst f = T.k;exactly as it is inT.k(), but only the latter is a call, andcollectInvokedPropertySitesonly records evidence for calls. So:correctly marks
Tescaping (no correlated evidence can exist foralphathrough this reference), falling back to T2. But T2 also cannot help here unless some unrelated.alpha(...)call happens to exist elsewhere in the build by coincidence —f()itself is never translated into "creditalphaas invoked" by any existing mechanism. Per round-6 review: "const f = T.kproduces anfnRefBindingkeyedT.kthat nothing seeds" — the pre-existing, general local-function-alias tracking (fnRefBindings, which already handles whole-object aliases likeconst u = T) does not bridge a property-VALUE alias back to the object-literal value-ref mechanism.Impact
Recall-only:
f()is a real, correct invocation offnAin actual program semantics, but codegraph has no channel that can currently prove it — with or without #2088.roles --role deadreports such a case dead both before and after #2088 — correctly conservative (no false claim of liveness), but incomplete (a real false negative for "is this dead").Suggested fix shape (not binding — decide at execute/fix time)
Extend
fnRefBindings(or add a sibling channel) to also key avariable_declaratorwhosevalueis directlyT.k(a member/subscript expression, not just a bare identifier) as an alias of that property's value-ref, then let the existing alias-resolution machinery (already used for whole-object aliases) treatf()as equivalent toT.k()for evidence purposes — subject tof's own subsequent references being fully tracked too, recursively, the same way the whole-object alias branch already requires (round-4 fix toallReferencesTracked's rebinding branch).Where
docs/plans/issue-2088.md— WU-2'sisTrackedReferencePosition(member_expression/subscript_expressioncall-position narrowing); WU-10's escape-fallback case (h).