fix(resolution): fuzzy reachability rejects a unique guess, never manufactures one
A function nested inside another function is only callable from inside its
container (#1230). matchByExactName already declined such candidates; the
fuzzy fallback did not, so a builtin method call (`res.text()`) whose only
same-named project symbol was some file's closure resolved onto that
closure at 0.5 (#1708).
and on vitejs/vite@8492422 that traded 12 correct removals for 59 wrong
additions: the repo has a dozen `resolve` definitions, most nested, so the
filter left exactly one reachable `resolve` method and the strategy
committed every `import { resolve } from 'node:path'` call in the
playground configs to it. Filtering a crowd down to one survivor is not
evidence the survivor was ever the target.
So the check sits on the ONE candidate matchFuzzy would commit to: a
unique candidate the call cannot reach is declined; a crowd stays a crowd.
Same tree, measured against this branch's own base b9ca4b7: 12 edges lost
(all fuzzy, all onto nested functions — the same 12 #1709 removes), 0
gained, fuzzy 13 -> 1, every other resolvedBy row at zero.
The two-file fixture is #1709's, credited in the previous commit; four
direct tests pin the shape: a lone unreachable closure declines, the same
closure resolves from inside its container, closure + method is ambiguous
and declines (the candidate-set filter fails exactly this one), a lone
reachable method resolves as before.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
3d9352c7ac
commit
2521b49a9a
@@ -2799,13 +2799,23 @@ export function matchFuzzy(
|
||||
// a lone one and manufacture a 0.5 guess out of an ambiguity fuzzy declines.
|
||||
// Also decline a bare JS/TS call whose only survivor is a method or a
|
||||
// cross-file name the file already binds locally (#1714).
|
||||
// A function nested inside another function is only callable from inside
|
||||
// its container (#1230), so a builtin method call (`res.text()`) whose only
|
||||
// same-named project symbol is some file's closure must decline (#1708).
|
||||
// The check sits on the ONE candidate this strategy would commit to, not on
|
||||
// the candidate set: filtering the unreachable ones out of a crowd would
|
||||
// leave a single survivor and hand it every call of that name — on vite,
|
||||
// `import { resolve } from 'node:path'` in a dozen playground configs onto
|
||||
// the one reachable `resolve` method (#1709). Reachability may reject a
|
||||
// unique guess; it must never manufacture one.
|
||||
if (
|
||||
finalCandidates.length === 1 &&
|
||||
isVisibleAcrossFiles(finalCandidates[0]!, ref, context) &&
|
||||
isCrossFileReachable(finalCandidates[0]!, ref, context) &&
|
||||
!(isBareJsCall(ref, context) &&
|
||||
(finalCandidates[0]!.kind === 'method' ||
|
||||
(finalCandidates[0]!.filePath !== ref.filePath && isLocallyBoundJsName(ref.referenceName, ref.filePath, context))))
|
||||
(finalCandidates[0]!.filePath !== ref.filePath && isLocallyBoundJsName(ref.referenceName, ref.filePath, context)))) &&
|
||||
isLexicallyReachable(finalCandidates[0]!, ref, context)
|
||||
) {
|
||||
const isCrossLanguage = finalCandidates[0]!.language !== ref.language;
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user