Commit 6207c9e
fix(lint): resolve the durability gate's wrapper hop through the call site's lexical scope (#13784)
* fix(lint): resolve the durability gate's wrapper hop through the call site's lexical scope
`indexFunctionBodies` built one flat `Map<name, body>` in source order, so a
file that declared the same name more than once resolved EVERY call to that
name to the LAST declaration, wherever the call was written. That is not an
approximation with a direction: a collision where only some of the same-named
bodies read either invents a read seam or drops a real one, and nothing in the
output distinguishes either case from a correct resolution.
The index now records every declaration with the scope it is visible from, and
`get(name, from)` walks outward from the call site, innermost scope first.
Two deliberate departures from a strict lexical resolver, both measured:
- a name with exactly ONE body in the file resolves from anywhere. There is
nothing to choose, and this keeps every hop the census depends on -- notably
a wrapper reached on an identifier receiver, whose owning class is not on the
caller's ancestor chain.
- a name with SEVERAL bodies and no enclosing one is refused rather than
guessed. File order is not evidence, and declining is the under-counting
direction this family declares.
`contradictsWrapperResolution` is unchanged: it answers a different question
(collisions across receivers), both of its clauses pass correctly on the live
instance, and it stays load-bearing for a unique name reached on a compound
receiver.
The sibling `indexLogAliases` stays flat and last-wins, and its docblock now
says so with the measurement behind it: zero same-file collisions among the
names that index holds, across the whole scan surface.
Regression control: four fixtures in `selfTestReadSeams` pinning both error
directions (dropped seam, invented seam), the live three-body `lookup` shape,
and the non-narrowing rule that catches an over-fix.
Measured on this tree: `--list` and `--depth-cost` are byte-identical before
and after, at the shipped bound and at every probed depth up to 8.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
* docs(lint): retire the resolution-hazard note the lexical resolver closed
The header recorded the flat-index collision as an OPEN hazard, in the present
tense, pinned to line numbers that had already drifted by ~131 lines. It also
supplied the third of three reasons for leaving MAX_READ_WRAPPER_DEPTH alone
("the hazard grows with depth"), so closing the hazard silently would have left
a maintainer-reserved decision resting on an argument that no longer holds.
The note now says what was true, what closed it, and what survives of the depth
argument in its narrower form: a longer chain no longer needs every name in it
to be unique, only resolvable at its own call site -- but a name declared
exactly once is still answered by name alone from anywhere, so a longer chain
still crosses more of those. The other two reasons are untouched and the bound
is not moved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent eb717a1 commit 6207c9e
1 file changed
Lines changed: 309 additions & 26 deletions
0 commit comments