fix(resolution): constrain inheritance/import reference target kinds (#1536, #1537) - #1796
Merged
Merged
Conversation
An inheritance reference bound to whatever local symbol shared its name.
The name-matcher scores node kind as a bonus, never a filter, and awards
no bonus at all for inheritance refs, so `use std::error::Error;` +
`impl Error for MapperError {}` resolved to the local `MapperError::Error`
VARIANT — an implementation relationship absent from the source.
Two changes, both needed. Filtering by kind alone was measured and it
only RELOCATES the false edge: with enum members excluded, the same 7
refs moved onto an unrelated local `type Error` alias, which is a legal
supertype kind and therefore harder for a consumer to reject.
1. Eligibility before ranking. `matchByExactName` restricts its candidate
pool to kinds that can BE a supertype, so a legitimate trait outranks
a same-named variant instead of merely losing its edge. `resolveOne`
is wrapped by a gate that applies the same set to every other strategy
at one seam — filtering inside the name-matcher would have missed the
framework, import, chain and CFML paths.
2. Locality. A name imported from outside the repository has no in-repo
referent at all, so no candidate is correct. Only oracles that cannot
be wrong are consulted: Rust `use` paths rooted at a stdlib crate, and
`isExternalImport` for ES modules. Generalizing the Rust side to "the
module path doesn't resolve to a file" was tried and reverted — a
crate re-exporting a sibling's modules (`pub use pupil_core::ports;`)
has no directory to walk, and that version deleted 13 real trait
implementations.
Measured on a Rust/Tauri project (2,682 nodes): the 11 false inheritance
edges are gone, all 59 real trait relationships are preserved, and node
count is unchanged. On this repository as a control, the only edge
removed is a class recorded as extending a function. Synthesized-edge
counts are identical in both.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`import * as path from 'node:path'` is unresolvable — the module is external — so the name-matcher fell back to finding any node called `path`, and a common word like path/url/join/get matches a class property or interface method somewhere in almost any repo. Nothing in any supported language lets an import bind to a member that only exists inside a type; you import the type. Same shape as the inheritance gate that precedes it: eligibility applied to the candidate pool before ranking, plus the resolveOne gate as the backstop for every other strategy. On this repository as a control: 19 imports pointing at methods and 4 at properties are gone (all of them coincidences — `Walker::join`, `Telemetry::events`), 3 refs now find the module constant they actually name, node count unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`isExternalImport` had a TS/JS branch listing typescript/tsx/javascript/jsx/
arkts, so for Svelte, Vue and Astro it fell through every branch and returned
false — "not external" — for `import { Foo } from 'some-npm-pkg'`.
An SFC imports inside its `<script>` block (Astro: the `---` frontmatter) with
ordinary ES module syntax; `extractImportMappings` already routes all three
through the same `extractJSImports`. So the classifier disagreed with the
extractor about what those imports are.
Effect on the preceding commit: its locality check asks `isExternalImport`, so
it silently did nothing for SFCs. A class in a `.svelte`/`.vue`/`.astro` file
implementing a type imported from an npm package still bound to whatever local
class shared that name — verified against this branch before the fix, all three
languages.
The language set is now one constant used by both the classifier and the
locality check, so they cannot drift apart again. Relative and aliased
specifiers are unaffected: the branch returns "not external" for `./…`,
workspace members, tsconfig alias prefixes, `@/`, `~/` and `src/` exactly as it
does for `.ts`.
No edge changes on this repository as a control.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Sep 8, 2026
colbymchenry
added a commit
that referenced
this pull request
Sep 27, 2026
…e pair (#2055) The inheritance target-kind gate (#1796) rejected any extends/implements resolution whose target cannot be a supertype. VS Code declares every service twice under one name, `export const IFoo = createDecorator<IFoo>(…)` beside `export interface IFoo`, and the import resolver takes the first export of that name, which is the value. The gate then dropped the edge instead of taking the interface the same file declares. Found by the pre-release v1.6.0 vs main comparison: 864 `implements` edges lost on vscode (AccessibilityService -> IAccessibilityService and ~860 like it), plus the ~5.8k interface-dispatch call edges synthesized from them. The gate now moves a TypeScript constant/variable target to the one same-named supertype in its file; with no such sibling it still drops the edge. vscode: implements 4,139 -> 5,003 (v1.6.0: 5,436, 254 of them on non-type targets; now 0), node count unchanged. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1536. Fixes #1537.
An external supertype such as Rust's
std::error::Errorcould bind to a local enum variant or type alias namedError; an import such asnode:pathcould bind to an unrelated class property namedpath. Candidate ranking treated node kind as optional and did not establish whether an imported supertype existed in the repository.Lands and supersedes #1538 by @ctype-lab: cherry-picked
b55ad79f,f010a09e, and7f2035e1onto main at040ba388, retaining upstream authorship. Applies target-kind eligibility before name ranking and a gate across resolution strategies, checks external Rust/ES-module supertype bindings, and classifies Svelte/Vue/Astro script imports consistently. Conflict resolution preserves main's visibility, module isolation, lexical shadowing, PHP import-alias handling, and deferred-reference lifecycle. Existing changelog entries are preserved; the two fix notes are under Unreleased. Re-index after upgrading to clear existing false edges.Linux x64 verification, Node 22.19.0, real
node:sqlitedatabases (CODEGRAPH_KERNEL=0for identical WASM extraction in both worktrees):__tests__/reference-target-kind.test.tsinto an isolated main worktree at040ba388: 7 failed, 5 passed, including both issue repros and all three SFC variants.9ad9a113: 12 passed; valid in-repo traits, re-exported workspace traits, class/interface/type-alias supertypes, and relative SFC imports remain connected.npm run build: passed, including TypeScript, viewer build, and copied grammar/viewer asset checks.Reproduction command in each worktree with Node 22 on PATH:
Verification used this native Linux workspace; the full suite and agent A/B were not run.