Found during round-6 review of #2612 (issue-2088's implementation plan).
Problem
docs/plans/issue-2088.md's escape-analysis design (WU-2) tracks a reference in for (const r of T) (the of variant only) as a safe position, because forOfBindings models it in the points-to solver. The in variant of the same for_in_statement node type enumerates KEYS, not values:
for (const k in T) T[k]();
Here, T[k]() uses a dynamic key (k, the loop variable) — the call has no statically-known property name, so:
- T1 (
collectInvokedPropertySites) never records a ${siteKey}|${name} pair for it — there is no static name to key on.
- T3 (
collectComputedDispatchTableEvidence) does not fire either: verified against src/extractors/javascript.ts:5523-5538, it only recognizes the const x = TABLE[expr]; x(...) DECLARATOR form (the value must be directly a variable_declarator's value), not a direct TABLE[expr]() call.
So a for...in dispatch idiom gets no invocation evidence for any of the table's properties from any tier. Round 6 closes this soundly by excluding the in variant from the escape check's tracked set — such a table now correctly falls back to escaping — but the underlying capability (crediting a direct, non-declarator computed call like T[k]()) remains unmodeled.
Impact
Recall-only, conservative direction: a genuinely-live handler table dispatched exclusively via for...in + a direct computed call, with no other invocation evidence anywhere in the build, is reported dead by codegraph roles --role dead. This is the same error direction #2088 already accepts for any shape the analysis doesn't recognize (escapes defaults true), not a new regression introduced by round 6's fix.
Suggested fix shape (not binding — decide at execute/fix time)
Extend collectComputedDispatchTableEvidence (#2260) to also recognize a computed access that is DIRECTLY the callee of a call_expression (TABLE[expr]()), not only the const x = TABLE[expr]; x(...) declarator form — mirroring the same call-position check round 6 added to the escape analysis's own member_expression/subscript_expression handling. That would give for (const k in T) T[k]() a T3 evidence path without needing site correlation at all.
Where
Found during round-6 review of #2612 (issue-2088's implementation plan).
Problem
docs/plans/issue-2088.md's escape-analysis design (WU-2) tracks a reference infor (const r of T)(theofvariant only) as a safe position, becauseforOfBindingsmodels it in the points-to solver. Theinvariant of the samefor_in_statementnode type enumerates KEYS, not values:Here,
T[k]()uses a dynamic key (k, the loop variable) — the call has no statically-known property name, so:collectInvokedPropertySites) never records a${siteKey}|${name}pair for it — there is no staticnameto key on.collectComputedDispatchTableEvidence) does not fire either: verified againstsrc/extractors/javascript.ts:5523-5538, it only recognizes theconst x = TABLE[expr]; x(...)DECLARATOR form (the value must be directly avariable_declarator'svalue), not a directTABLE[expr]()call.So a
for...indispatch idiom gets no invocation evidence for any of the table's properties from any tier. Round 6 closes this soundly by excluding theinvariant from the escape check's tracked set — such a table now correctly falls back to escaping — but the underlying capability (crediting a direct, non-declarator computed call likeT[k]()) remains unmodeled.Impact
Recall-only, conservative direction: a genuinely-live handler table dispatched exclusively via
for...in+ a direct computed call, with no other invocation evidence anywhere in the build, is reported dead bycodegraph roles --role dead. This is the same error direction #2088 already accepts for any shape the analysis doesn't recognize (escapes defaultstrue), not a new regression introduced by round 6's fix.Suggested fix shape (not binding — decide at execute/fix time)
Extend
collectComputedDispatchTableEvidence(#2260) to also recognize a computed access that is DIRECTLY the callee of acall_expression(TABLE[expr]()), not only theconst x = TABLE[expr]; x(...)declarator form — mirroring the same call-position check round 6 added to the escape analysis's ownmember_expression/subscript_expressionhandling. That would givefor (const k in T) T[k]()a T3 evidence path without needing site correlation at all.Where
docs/plans/issue-2088.md— WU-2'sTRACKED_REFERENCE_PARENTS/isTrackedReferencePosition(for_in_statementhandling).src/extractors/javascript.ts:5523-5538(collectComputedDispatchTableEvidence), issue Computed-property (bracket-access) dispatch-table lookups lack a real calls edge, unlike dot-property value-refs #2260.