gitnexus 1.6.3-rc.5 → 1.6.3-rc.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_shared/index.d.ts +11 -1
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js +8 -0
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +72 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.js +79 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -0
- package/dist/_shared/scope-resolution/position-index.d.ts +50 -0
- package/dist/_shared/scope-resolution/position-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/position-index.js +134 -0
- package/dist/_shared/scope-resolution/position-index.js.map +1 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts +62 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js +120 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -0
- package/dist/_shared/scope-resolution/scope-id.d.ts +43 -0
- package/dist/_shared/scope-resolution/scope-id.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/scope-id.js +46 -0
- package/dist/_shared/scope-resolution/scope-id.js.map +1 -0
- package/dist/_shared/scope-resolution/scope-tree.d.ts +61 -0
- package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/scope-tree.js +185 -0
- package/dist/_shared/scope-resolution/scope-tree.js.map +1 -0
- package/dist/_shared/scope-resolution/types.d.ts +0 -6
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/core/search/phase-timer.d.ts +72 -0
- package/dist/core/search/phase-timer.js +106 -0
- package/dist/mcp/local/local-backend.js +48 -3
- package/package.json +1 -1
package/dist/_shared/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { getLanguageFromFilename, getSyntaxLanguageFromFilename } from './langua
|
|
|
6
6
|
export type { MroStrategy } from './mro-strategy.js';
|
|
7
7
|
export type { PipelinePhase, PipelineProgress } from './pipeline.js';
|
|
8
8
|
export type { SymbolDefinition } from './scope-resolution/symbol-definition.js';
|
|
9
|
-
export type { ScopeId, DefId, ScopeKind, Range, Capture, CaptureMatch, BindingRef, ImportEdge, TypeRef, Scope, ResolutionEvidence, Resolution, Reference, ReferenceIndex, LookupParams, RegistryContributor, ParsedImport, ParsedTypeBinding, WorkspaceIndex,
|
|
9
|
+
export type { ScopeId, DefId, ScopeKind, Range, Capture, CaptureMatch, BindingRef, ImportEdge, TypeRef, Scope, ResolutionEvidence, Resolution, Reference, ReferenceIndex, LookupParams, RegistryContributor, ParsedImport, ParsedTypeBinding, WorkspaceIndex, Callsite, } from './scope-resolution/types.js';
|
|
10
10
|
export { EvidenceWeights, typeBindingWeightAtDepth } from './scope-resolution/evidence-weights.js';
|
|
11
11
|
export { ORIGIN_PRIORITY } from './scope-resolution/origin-priority.js';
|
|
12
12
|
export type { OriginForTieBreak } from './scope-resolution/origin-priority.js';
|
|
@@ -18,6 +18,16 @@ export { buildModuleScopeIndex } from './scope-resolution/module-scope-index.js'
|
|
|
18
18
|
export type { ModuleScopeIndex, ModuleScopeEntry } from './scope-resolution/module-scope-index.js';
|
|
19
19
|
export { buildQualifiedNameIndex } from './scope-resolution/qualified-name-index.js';
|
|
20
20
|
export type { QualifiedNameIndex } from './scope-resolution/qualified-name-index.js';
|
|
21
|
+
export { resolveTypeRef } from './scope-resolution/resolve-type-ref.js';
|
|
22
|
+
export type { ResolveTypeRefContext, ScopeLookup } from './scope-resolution/resolve-type-ref.js';
|
|
23
|
+
export { buildMethodDispatchIndex } from './scope-resolution/method-dispatch-index.js';
|
|
24
|
+
export type { MethodDispatchIndex, MethodDispatchInput, } from './scope-resolution/method-dispatch-index.js';
|
|
25
|
+
export { makeScopeId, clearScopeIdInternPool } from './scope-resolution/scope-id.js';
|
|
26
|
+
export type { ScopeIdInput } from './scope-resolution/scope-id.js';
|
|
27
|
+
export { buildScopeTree, ScopeTreeInvariantError } from './scope-resolution/scope-tree.js';
|
|
28
|
+
export type { ScopeTree } from './scope-resolution/scope-tree.js';
|
|
29
|
+
export { buildPositionIndex } from './scope-resolution/position-index.js';
|
|
30
|
+
export type { PositionIndex } from './scope-resolution/position-index.js';
|
|
21
31
|
export { diffResolutions } from './scope-resolution/shadow/diff.js';
|
|
22
32
|
export type { ShadowAgreement, ShadowCallsite, ShadowDiff, } from './scope-resolution/shadow/diff.js';
|
|
23
33
|
export { aggregateDiffs } from './scope-resolution/shadow/aggregate.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,WAAW,EACX,cAAc,EACd,SAAS,EACT,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAGzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACjG,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAIrE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAChF,YAAY,EACV,OAAO,EACP,KAAK,EACL,SAAS,EACT,KAAK,EACL,OAAO,EACP,YAAY,EACZ,UAAU,EACV,UAAU,EACV,OAAO,EACP,KAAK,EACL,kBAAkB,EAClB,UAAU,EACV,SAAS,EACT,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,WAAW,EACX,cAAc,EACd,SAAS,EACT,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAGzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACjG,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAIrE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAChF,YAAY,EACV,OAAO,EACP,KAAK,EACL,SAAS,EACT,KAAK,EACL,OAAO,EACP,YAAY,EACZ,UAAU,EACV,UAAU,EACV,OAAO,EACP,KAAK,EACL,kBAAkB,EAClB,UAAU,EACV,SAAS,EACT,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,QAAQ,GACT,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AACnG,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAG/E,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,+CAA+C,CAAC;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAC;AAG5F,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,YAAY,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACjF,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACnG,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AACrF,YAAY,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;AAGrF,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,YAAY,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AAGjG,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AACvF,YAAY,EACV,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,6CAA6C,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACrF,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3F,YAAY,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,YAAY,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAG1E,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,YAAY,EACV,eAAe,EACf,cAAc,EACd,UAAU,GACX,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC"}
|
package/dist/_shared/index.js
CHANGED
|
@@ -12,6 +12,14 @@ export { LanguageClassifications, isProductionLanguage, } from './scope-resoluti
|
|
|
12
12
|
export { buildDefIndex } from './scope-resolution/def-index.js';
|
|
13
13
|
export { buildModuleScopeIndex } from './scope-resolution/module-scope-index.js';
|
|
14
14
|
export { buildQualifiedNameIndex } from './scope-resolution/qualified-name-index.js';
|
|
15
|
+
// Strict type-reference resolver (RFC §4.6; Ring 2 SHARED #916)
|
|
16
|
+
export { resolveTypeRef } from './scope-resolution/resolve-type-ref.js';
|
|
17
|
+
// Method-dispatch materialized view over HeritageMap (RFC §3.1; Ring 2 SHARED #914)
|
|
18
|
+
export { buildMethodDispatchIndex } from './scope-resolution/method-dispatch-index.js';
|
|
19
|
+
// Scope tree spine + position lookup (RFC §2.2 + §3.1; Ring 2 SHARED #912)
|
|
20
|
+
export { makeScopeId, clearScopeIdInternPool } from './scope-resolution/scope-id.js';
|
|
21
|
+
export { buildScopeTree, ScopeTreeInvariantError } from './scope-resolution/scope-tree.js';
|
|
22
|
+
export { buildPositionIndex } from './scope-resolution/position-index.js';
|
|
15
23
|
// Shadow-mode diff + aggregation (RFC §6.3; Ring 2 SHARED #918)
|
|
16
24
|
export { diffResolutions } from './scope-resolution/shadow/diff.js';
|
|
17
25
|
export { aggregateDiffs } from './scope-resolution/shadow/aggregate.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,mBAAmB;AACnB,OAAO,EACL,WAAW,EACX,cAAc,EACd,SAAS,EACT,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AAGpC,mBAAmB;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,mBAAmB;AACnB,OAAO,EACL,WAAW,EACX,cAAc,EACd,SAAS,EACT,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AAGpC,mBAAmB;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAgCjG,8DAA8D;AAC9D,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AACnG,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAGxE,yDAAyD;AACzD,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,+CAA+C,CAAC;AAGvD,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AAGrF,gEAAgE;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAGxE,oFAAoF;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AAMvF,2EAA2E;AAC3E,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAErF,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAE3F,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAG1E,gEAAgE;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAMpE,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MethodDispatchIndex` — materialized view of class hierarchies keyed by
|
|
3
|
+
* `DefId` (RFC §3.1; Ring 2 SHARED #914).
|
|
4
|
+
*
|
|
5
|
+
* Two O(1)-access maps used by `Registry.lookupMethod` and interface-
|
|
6
|
+
* dispatch callers:
|
|
7
|
+
*
|
|
8
|
+
* - `mroByOwnerDefId` : owner class → full MRO ancestor chain
|
|
9
|
+
* (excludes the owner itself, in per-language
|
|
10
|
+
* strategy order).
|
|
11
|
+
* - `implsByInterfaceDefId` : interface/trait → classes that implement it.
|
|
12
|
+
*
|
|
13
|
+
* **Not an MRO implementation.** The build function is a pure aggregator: it
|
|
14
|
+
* asks the caller (via `computeMro` and `implementsOf` callbacks) for the
|
|
15
|
+
* per-language answers and materializes the two-way index. MRO strategies
|
|
16
|
+
* live where they already do today (`model/resolve.ts § c3Linearize`,
|
|
17
|
+
* `languages/ruby.ts § selectDispatch`, etc.) — this index does not
|
|
18
|
+
* reimplement them.
|
|
19
|
+
*
|
|
20
|
+
* Why callbacks and not a shared strategy registry: the five strategies
|
|
21
|
+
* (Python C3, Ruby kind-aware, Java/Kotlin linear, Rust qualified-syntax,
|
|
22
|
+
* COBOL none) already exist in the CLI package and depend on the CLI's
|
|
23
|
+
* `HeritageMap` + `SemanticModel`. Pulling them into `gitnexus-shared` would
|
|
24
|
+
* require migrating both — out of scope for #914. Callbacks let the shared
|
|
25
|
+
* build stay pure while honoring existing strategies verbatim.
|
|
26
|
+
*
|
|
27
|
+
* Consumed by: #917 (`Registry.lookupMethod` MRO fast path, interface
|
|
28
|
+
* dispatch resolver).
|
|
29
|
+
*/
|
|
30
|
+
import type { DefId } from './types.js';
|
|
31
|
+
export interface MethodDispatchIndex {
|
|
32
|
+
/**
|
|
33
|
+
* Full MRO ancestor chain per owner class (excludes the owner itself).
|
|
34
|
+
* Order reflects the per-language strategy used by `computeMro`.
|
|
35
|
+
*/
|
|
36
|
+
readonly mroByOwnerDefId: ReadonlyMap<DefId, readonly DefId[]>;
|
|
37
|
+
/** Interfaces / traits → classes that implement them. */
|
|
38
|
+
readonly implsByInterfaceDefId: ReadonlyMap<DefId, readonly DefId[]>;
|
|
39
|
+
/** `mroByOwnerDefId.get`, with an empty frozen array on miss. */
|
|
40
|
+
mroFor(ownerDefId: DefId): readonly DefId[];
|
|
41
|
+
/** `implsByInterfaceDefId.get`, with an empty frozen array on miss. */
|
|
42
|
+
implementorsOf(interfaceDefId: DefId): readonly DefId[];
|
|
43
|
+
}
|
|
44
|
+
export interface MethodDispatchInput {
|
|
45
|
+
/**
|
|
46
|
+
* Owner defs to index (classes, structs, traits, interfaces — any kind
|
|
47
|
+
* that can appear on the owner side of a method-dispatch graph).
|
|
48
|
+
*/
|
|
49
|
+
readonly owners: readonly DefId[];
|
|
50
|
+
/**
|
|
51
|
+
* Return the full MRO ancestor chain for `ownerDefId`, **excluding the
|
|
52
|
+
* owner itself**, in the order dictated by the owner's language-specific
|
|
53
|
+
* MRO strategy.
|
|
54
|
+
*
|
|
55
|
+
* Contract:
|
|
56
|
+
* - Pure (no side effects).
|
|
57
|
+
* - Deterministic per input.
|
|
58
|
+
* - `undefined` not allowed — return `[]` when the owner has no parents.
|
|
59
|
+
*/
|
|
60
|
+
readonly computeMro: (ownerDefId: DefId) => readonly DefId[];
|
|
61
|
+
/**
|
|
62
|
+
* Return the set of interface/trait defs that `ownerDefId` implements.
|
|
63
|
+
* Transitive inclusion (e.g., `implements` on a parent class) is the
|
|
64
|
+
* caller's choice — the build function simply inverts whatever is
|
|
65
|
+
* returned.
|
|
66
|
+
*
|
|
67
|
+
* Repeated IDs in the output are deduplicated automatically.
|
|
68
|
+
*/
|
|
69
|
+
readonly implementsOf: (ownerDefId: DefId) => readonly DefId[];
|
|
70
|
+
}
|
|
71
|
+
export declare function buildMethodDispatchIndex(input: MethodDispatchInput): MethodDispatchIndex;
|
|
72
|
+
//# sourceMappingURL=method-dispatch-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"method-dispatch-index.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/method-dispatch-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,KAAK,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC;IAC/D,yDAAyD;IACzD,QAAQ,CAAC,qBAAqB,EAAE,WAAW,CAAC,KAAK,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC;IAErE,iEAAiE;IACjE,MAAM,CAAC,UAAU,EAAE,KAAK,GAAG,SAAS,KAAK,EAAE,CAAC;IAC5C,uEAAuE;IACvE,cAAc,CAAC,cAAc,EAAE,KAAK,GAAG,SAAS,KAAK,EAAE,CAAC;CACzD;AAED,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC;;;;;;;;;OASG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,UAAU,EAAE,KAAK,KAAK,SAAS,KAAK,EAAE,CAAC;IAC7D;;;;;;;OAOG;IACH,QAAQ,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,KAAK,KAAK,SAAS,KAAK,EAAE,CAAC;CAChE;AAID,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,mBAAmB,GAAG,mBAAmB,CAqCxF"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MethodDispatchIndex` — materialized view of class hierarchies keyed by
|
|
3
|
+
* `DefId` (RFC §3.1; Ring 2 SHARED #914).
|
|
4
|
+
*
|
|
5
|
+
* Two O(1)-access maps used by `Registry.lookupMethod` and interface-
|
|
6
|
+
* dispatch callers:
|
|
7
|
+
*
|
|
8
|
+
* - `mroByOwnerDefId` : owner class → full MRO ancestor chain
|
|
9
|
+
* (excludes the owner itself, in per-language
|
|
10
|
+
* strategy order).
|
|
11
|
+
* - `implsByInterfaceDefId` : interface/trait → classes that implement it.
|
|
12
|
+
*
|
|
13
|
+
* **Not an MRO implementation.** The build function is a pure aggregator: it
|
|
14
|
+
* asks the caller (via `computeMro` and `implementsOf` callbacks) for the
|
|
15
|
+
* per-language answers and materializes the two-way index. MRO strategies
|
|
16
|
+
* live where they already do today (`model/resolve.ts § c3Linearize`,
|
|
17
|
+
* `languages/ruby.ts § selectDispatch`, etc.) — this index does not
|
|
18
|
+
* reimplement them.
|
|
19
|
+
*
|
|
20
|
+
* Why callbacks and not a shared strategy registry: the five strategies
|
|
21
|
+
* (Python C3, Ruby kind-aware, Java/Kotlin linear, Rust qualified-syntax,
|
|
22
|
+
* COBOL none) already exist in the CLI package and depend on the CLI's
|
|
23
|
+
* `HeritageMap` + `SemanticModel`. Pulling them into `gitnexus-shared` would
|
|
24
|
+
* require migrating both — out of scope for #914. Callbacks let the shared
|
|
25
|
+
* build stay pure while honoring existing strategies verbatim.
|
|
26
|
+
*
|
|
27
|
+
* Consumed by: #917 (`Registry.lookupMethod` MRO fast path, interface
|
|
28
|
+
* dispatch resolver).
|
|
29
|
+
*/
|
|
30
|
+
// ─── Builder ────────────────────────────────────────────────────────────────
|
|
31
|
+
export function buildMethodDispatchIndex(input) {
|
|
32
|
+
const mroByOwnerDefId = new Map();
|
|
33
|
+
const implsBuilding = new Map();
|
|
34
|
+
const implsSeen = new Map();
|
|
35
|
+
for (const ownerId of input.owners) {
|
|
36
|
+
// First-write-wins on duplicate owner ids: a stable policy consistent
|
|
37
|
+
// with sibling indexes (#913 DefIndex / ModuleScopeIndex).
|
|
38
|
+
if (!mroByOwnerDefId.has(ownerId)) {
|
|
39
|
+
const chain = input.computeMro(ownerId);
|
|
40
|
+
mroByOwnerDefId.set(ownerId, Object.freeze(chain.slice()));
|
|
41
|
+
}
|
|
42
|
+
for (const ifaceId of input.implementsOf(ownerId)) {
|
|
43
|
+
let seen = implsSeen.get(ifaceId);
|
|
44
|
+
if (seen === undefined) {
|
|
45
|
+
seen = new Set();
|
|
46
|
+
implsSeen.set(ifaceId, seen);
|
|
47
|
+
}
|
|
48
|
+
if (seen.has(ownerId))
|
|
49
|
+
continue;
|
|
50
|
+
seen.add(ownerId);
|
|
51
|
+
let bucket = implsBuilding.get(ifaceId);
|
|
52
|
+
if (bucket === undefined) {
|
|
53
|
+
bucket = [];
|
|
54
|
+
implsBuilding.set(ifaceId, bucket);
|
|
55
|
+
}
|
|
56
|
+
bucket.push(ownerId);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const implsByInterfaceDefId = new Map();
|
|
60
|
+
for (const [ifaceId, owners] of implsBuilding) {
|
|
61
|
+
implsByInterfaceDefId.set(ifaceId, Object.freeze(owners.slice()));
|
|
62
|
+
}
|
|
63
|
+
return freezeIndex(mroByOwnerDefId, implsByInterfaceDefId);
|
|
64
|
+
}
|
|
65
|
+
// ─── Internal ───────────────────────────────────────────────────────────────
|
|
66
|
+
const EMPTY = Object.freeze([]);
|
|
67
|
+
function freezeIndex(mroByOwnerDefId, implsByInterfaceDefId) {
|
|
68
|
+
return {
|
|
69
|
+
mroByOwnerDefId,
|
|
70
|
+
implsByInterfaceDefId,
|
|
71
|
+
mroFor(ownerDefId) {
|
|
72
|
+
return mroByOwnerDefId.get(ownerDefId) ?? EMPTY;
|
|
73
|
+
},
|
|
74
|
+
implementorsOf(interfaceDefId) {
|
|
75
|
+
return implsByInterfaceDefId.get(interfaceDefId) ?? EMPTY;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=method-dispatch-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"method-dispatch-index.js","sourceRoot":"","sources":["../../src/scope-resolution/method-dispatch-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAiDH,+EAA+E;AAE/E,MAAM,UAAU,wBAAwB,CAAC,KAA0B;IACjE,MAAM,eAAe,GAAG,IAAI,GAAG,EAA2B,CAAC;IAC3D,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE/C,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACnC,sEAAsE;QACtE,2DAA2D;QAC3D,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACxC,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC7D,CAAC;QAED,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YAClD,IAAI,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAClC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,IAAI,GAAG,IAAI,GAAG,EAAS,CAAC;gBACxB,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC/B,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,SAAS;YAChC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAElB,IAAI,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACxC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,MAAM,GAAG,EAAE,CAAC;gBACZ,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACrC,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAA2B,CAAC;IACjE,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9C,qBAAqB,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,WAAW,CAAC,eAAe,EAAE,qBAAqB,CAAC,CAAC;AAC7D,CAAC;AAED,+EAA+E;AAE/E,MAAM,KAAK,GAAqB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAElD,SAAS,WAAW,CAClB,eAA6C,EAC7C,qBAAmD;IAEnD,OAAO;QACL,eAAe;QACf,qBAAqB;QACrB,MAAM,CAAC,UAAiB;YACtB,OAAO,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC;QAClD,CAAC;QACD,cAAc,CAAC,cAAqB;YAClC,OAAO,qBAAqB,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC;QAC5D,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `PositionIndex` — O(log N_file) scope-at-position lookup
|
|
3
|
+
* (RFC §3.1; Ring 2 SHARED #912).
|
|
4
|
+
*
|
|
5
|
+
* Per-file sorted array of `(range, scopeId)` entries, sorted by start
|
|
6
|
+
* position ASC (`startLine`, then `startCol`). `atPosition(filePath, line,
|
|
7
|
+
* col)` binary-searches for the last entry whose start ≤ (line, col), then
|
|
8
|
+
* scans backward through the sorted prefix and returns the first entry
|
|
9
|
+
* whose range contains the query position.
|
|
10
|
+
*
|
|
11
|
+
* **Why this works.** `ScopeTree`'s invariants (parent strictly contains
|
|
12
|
+
* child; siblings don't overlap) guarantee that the scopes containing a
|
|
13
|
+
* given point form an **ancestor chain**. When scanning backward through
|
|
14
|
+
* entries sorted by start position ASC, the first scope we find that
|
|
15
|
+
* contains the query is the innermost one — any deeper-starting scope
|
|
16
|
+
* that also contained the query would appear *later* in the sorted array,
|
|
17
|
+
* but we're only scanning entries with start ≤ query, so anything later
|
|
18
|
+
* necessarily starts after the query and can't contain it.
|
|
19
|
+
*
|
|
20
|
+
* Expected complexity: `O(log N_file + D)` where `D` is the lexical depth
|
|
21
|
+
* at the query position (typically ≤ 10). Worst-case degrades to `O(N_file)`
|
|
22
|
+
* only under pathological inputs (many scopes starting at the same line).
|
|
23
|
+
*
|
|
24
|
+
* **Line/column conventions.** Matches `Range` in `types.ts`: lines are
|
|
25
|
+
* 1-based, columns are 0-based. Ranges are **inclusive on both ends** —
|
|
26
|
+
* a scope whose `endLine:endCol` equals the query position still contains
|
|
27
|
+
* it. That matches how tree-sitter captures bodies (closing brace
|
|
28
|
+
* included) and how closed PR #902's `enclosingFunctions` behaved.
|
|
29
|
+
*/
|
|
30
|
+
import type { Scope, ScopeId } from './types.js';
|
|
31
|
+
export interface PositionIndex {
|
|
32
|
+
/** Total scope entries indexed across all files. */
|
|
33
|
+
readonly size: number;
|
|
34
|
+
/**
|
|
35
|
+
* Innermost scope containing `(line, col)` in `filePath`, or `undefined`
|
|
36
|
+
* when nothing contains it (position before file start, after file end,
|
|
37
|
+
* or filePath not indexed).
|
|
38
|
+
*/
|
|
39
|
+
atPosition(filePath: string, line: number, col: number): ScopeId | undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build a `PositionIndex` from a flat list of `Scope` records.
|
|
43
|
+
*
|
|
44
|
+
* Duplicate `id`s are tolerated and deduplicated — the caller's
|
|
45
|
+
* `ScopeTree.buildScopeTree` is the authoritative validator of scope
|
|
46
|
+
* identity, and the position index does not need to re-check that
|
|
47
|
+
* invariant.
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildPositionIndex(scopes: readonly Scope[]): PositionIndex;
|
|
50
|
+
//# sourceMappingURL=position-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"position-index.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/position-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAS,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CAC9E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,aAAa,CAqB1E"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `PositionIndex` — O(log N_file) scope-at-position lookup
|
|
3
|
+
* (RFC §3.1; Ring 2 SHARED #912).
|
|
4
|
+
*
|
|
5
|
+
* Per-file sorted array of `(range, scopeId)` entries, sorted by start
|
|
6
|
+
* position ASC (`startLine`, then `startCol`). `atPosition(filePath, line,
|
|
7
|
+
* col)` binary-searches for the last entry whose start ≤ (line, col), then
|
|
8
|
+
* scans backward through the sorted prefix and returns the first entry
|
|
9
|
+
* whose range contains the query position.
|
|
10
|
+
*
|
|
11
|
+
* **Why this works.** `ScopeTree`'s invariants (parent strictly contains
|
|
12
|
+
* child; siblings don't overlap) guarantee that the scopes containing a
|
|
13
|
+
* given point form an **ancestor chain**. When scanning backward through
|
|
14
|
+
* entries sorted by start position ASC, the first scope we find that
|
|
15
|
+
* contains the query is the innermost one — any deeper-starting scope
|
|
16
|
+
* that also contained the query would appear *later* in the sorted array,
|
|
17
|
+
* but we're only scanning entries with start ≤ query, so anything later
|
|
18
|
+
* necessarily starts after the query and can't contain it.
|
|
19
|
+
*
|
|
20
|
+
* Expected complexity: `O(log N_file + D)` where `D` is the lexical depth
|
|
21
|
+
* at the query position (typically ≤ 10). Worst-case degrades to `O(N_file)`
|
|
22
|
+
* only under pathological inputs (many scopes starting at the same line).
|
|
23
|
+
*
|
|
24
|
+
* **Line/column conventions.** Matches `Range` in `types.ts`: lines are
|
|
25
|
+
* 1-based, columns are 0-based. Ranges are **inclusive on both ends** —
|
|
26
|
+
* a scope whose `endLine:endCol` equals the query position still contains
|
|
27
|
+
* it. That matches how tree-sitter captures bodies (closing brace
|
|
28
|
+
* included) and how closed PR #902's `enclosingFunctions` behaved.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Build a `PositionIndex` from a flat list of `Scope` records.
|
|
32
|
+
*
|
|
33
|
+
* Duplicate `id`s are tolerated and deduplicated — the caller's
|
|
34
|
+
* `ScopeTree.buildScopeTree` is the authoritative validator of scope
|
|
35
|
+
* identity, and the position index does not need to re-check that
|
|
36
|
+
* invariant.
|
|
37
|
+
*/
|
|
38
|
+
export function buildPositionIndex(scopes) {
|
|
39
|
+
const entriesByFile = new Map();
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
for (const scope of scopes) {
|
|
42
|
+
if (seen.has(scope.id))
|
|
43
|
+
continue;
|
|
44
|
+
seen.add(scope.id);
|
|
45
|
+
let bucket = entriesByFile.get(scope.filePath);
|
|
46
|
+
if (bucket === undefined) {
|
|
47
|
+
bucket = [];
|
|
48
|
+
entriesByFile.set(scope.filePath, bucket);
|
|
49
|
+
}
|
|
50
|
+
bucket.push({ id: scope.id, range: scope.range });
|
|
51
|
+
}
|
|
52
|
+
for (const bucket of entriesByFile.values()) {
|
|
53
|
+
bucket.sort(compareEntry);
|
|
54
|
+
}
|
|
55
|
+
return freezeIndex(entriesByFile, seen.size);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Sort by start position ASC, breaking ties by end position DESC so that
|
|
59
|
+
* larger (outer) scopes appear before their smaller (inner) co-starting
|
|
60
|
+
* siblings in the array. Makes the backward-scan contract crisp: the
|
|
61
|
+
* first containing hit from the end of the scanned prefix is the
|
|
62
|
+
* innermost scope.
|
|
63
|
+
*/
|
|
64
|
+
function compareEntry(a, b) {
|
|
65
|
+
if (a.range.startLine !== b.range.startLine)
|
|
66
|
+
return a.range.startLine - b.range.startLine;
|
|
67
|
+
if (a.range.startCol !== b.range.startCol)
|
|
68
|
+
return a.range.startCol - b.range.startCol;
|
|
69
|
+
if (a.range.endLine !== b.range.endLine)
|
|
70
|
+
return b.range.endLine - a.range.endLine;
|
|
71
|
+
return b.range.endCol - a.range.endCol;
|
|
72
|
+
}
|
|
73
|
+
/** Whether `(line, col)` is at or after `range`'s start. */
|
|
74
|
+
function startIsAtOrBefore(range, line, col) {
|
|
75
|
+
if (range.startLine < line)
|
|
76
|
+
return true;
|
|
77
|
+
if (range.startLine > line)
|
|
78
|
+
return false;
|
|
79
|
+
return range.startCol <= col;
|
|
80
|
+
}
|
|
81
|
+
/** Whether `(line, col)` is at or before `range`'s end (inclusive). */
|
|
82
|
+
function endIsAtOrAfter(range, line, col) {
|
|
83
|
+
if (range.endLine > line)
|
|
84
|
+
return true;
|
|
85
|
+
if (range.endLine < line)
|
|
86
|
+
return false;
|
|
87
|
+
return range.endCol >= col;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Return the largest index `i` in `arr` where `arr[i].range` starts at or
|
|
91
|
+
* before `(line, col)`. Returns `-1` if no entry starts ≤ the query.
|
|
92
|
+
*
|
|
93
|
+
* Classic "upper bound - 1" binary search: find the first entry that
|
|
94
|
+
* starts *after* the query, then step back one.
|
|
95
|
+
*/
|
|
96
|
+
function findLastStartLteIndex(arr, line, col) {
|
|
97
|
+
let lo = 0;
|
|
98
|
+
let hi = arr.length;
|
|
99
|
+
while (lo < hi) {
|
|
100
|
+
const mid = (lo + hi) >>> 1;
|
|
101
|
+
if (startIsAtOrBefore(arr[mid].range, line, col)) {
|
|
102
|
+
lo = mid + 1;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
hi = mid;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return lo - 1;
|
|
109
|
+
}
|
|
110
|
+
function freezeIndex(entriesByFile, size) {
|
|
111
|
+
return {
|
|
112
|
+
get size() {
|
|
113
|
+
return size;
|
|
114
|
+
},
|
|
115
|
+
atPosition(filePath, line, col) {
|
|
116
|
+
const bucket = entriesByFile.get(filePath);
|
|
117
|
+
if (bucket === undefined || bucket.length === 0)
|
|
118
|
+
return undefined;
|
|
119
|
+
const endIdx = findLastStartLteIndex(bucket, line, col);
|
|
120
|
+
if (endIdx < 0)
|
|
121
|
+
return undefined;
|
|
122
|
+
// Scan backward; first containing hit is innermost (see file header).
|
|
123
|
+
for (let i = endIdx; i >= 0; i--) {
|
|
124
|
+
const entry = bucket[i];
|
|
125
|
+
if (endIsAtOrAfter(entry.range, line, col)) {
|
|
126
|
+
// `startIsAtOrBefore` is guaranteed true by the binary search.
|
|
127
|
+
return entry.id;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return undefined;
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=position-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"position-index.js","sourceRoot":"","sources":["../../src/scope-resolution/position-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `resolveTypeRef` — strict single-return resolver for `TypeRef`s
|
|
3
|
+
* (RFC §4.6; Ring 2 SHARED #916).
|
|
4
|
+
*
|
|
5
|
+
* Narrower contract than `Registry.lookup`: no name-only global fallback, no
|
|
6
|
+
* confidence ranking, no arity check. Used by `Registry.lookup` Step 2 (type-
|
|
7
|
+
* binding propagation) and by any caller that wants the single best type-
|
|
8
|
+
* target for an annotation without paying for the full evidence pipeline.
|
|
9
|
+
*
|
|
10
|
+
* **Algorithm (strict).** Walk the scope chain from `ref.declaredAtScope`:
|
|
11
|
+
*
|
|
12
|
+
* 1. At each scope, inspect `bindings.get(ref.rawName)`:
|
|
13
|
+
* - If one of the bindings is a **type-kind** def with a **strict origin**
|
|
14
|
+
* (`'local' | 'import' | 'namespace' | 'reexport'`), return it.
|
|
15
|
+
* - If any binding for this name exists at this scope but none qualifies
|
|
16
|
+
* (e.g., a local variable named `User` shadows an outer import of class
|
|
17
|
+
* `User`), return `null`. The nearer binding shadows; we do NOT fall
|
|
18
|
+
* through to the global qualified-name index.
|
|
19
|
+
* - Otherwise continue to the parent scope.
|
|
20
|
+
* 2. If the raw name is a dotted path (e.g., `'models.User'`) and the scope
|
|
21
|
+
* walk produced no match, consult `QualifiedNameIndex.byQualifiedName`.
|
|
22
|
+
* Only accept **exactly one** type-kind hit — anything ambiguous returns
|
|
23
|
+
* `null` rather than a guess.
|
|
24
|
+
* 3. Return `null`.
|
|
25
|
+
*
|
|
26
|
+
* **What `'strict' origins' means.** `'wildcard'` is intentionally excluded.
|
|
27
|
+
* A wildcard-expanded name (`from x import *`) is too loose to use as an
|
|
28
|
+
* anchor for type resolution — it gives no signal about whether the name was
|
|
29
|
+
* actually imported. `Registry.lookup` may accept wildcard bindings at its
|
|
30
|
+
* own discretion (with lower evidence weight); `resolveTypeRef` does not.
|
|
31
|
+
*
|
|
32
|
+
* **What 'type-kind' means.** The subset of `NodeLabel` that a type annotation
|
|
33
|
+
* may legitimately reference: class-like, interface-like, enum-like, and
|
|
34
|
+
* alias-like kinds. See `TYPE_KINDS` below.
|
|
35
|
+
*
|
|
36
|
+
* Pure function — safe to call repeatedly; no side effects.
|
|
37
|
+
*/
|
|
38
|
+
import type { SymbolDefinition } from './symbol-definition.js';
|
|
39
|
+
import type { Scope, ScopeId, TypeRef } from './types.js';
|
|
40
|
+
import type { DefIndex } from './def-index.js';
|
|
41
|
+
import type { QualifiedNameIndex } from './qualified-name-index.js';
|
|
42
|
+
/**
|
|
43
|
+
* Minimal scope-lookup contract required by `resolveTypeRef`. Implemented by
|
|
44
|
+
* the `ScopeTree` from #912; declared here so #916 can ship as a standalone
|
|
45
|
+
* piece without a hard dependency on the full scope-tree implementation. Any
|
|
46
|
+
* structure that hands back a `Scope` by `ScopeId` satisfies this contract.
|
|
47
|
+
*/
|
|
48
|
+
export interface ScopeLookup {
|
|
49
|
+
getScope(id: ScopeId): Scope | undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* All inputs `resolveTypeRef` needs from the semantic model. Bundled into a
|
|
53
|
+
* context object so the call site stays short and the interface is stable as
|
|
54
|
+
* additional indexes get threaded through in later rings.
|
|
55
|
+
*/
|
|
56
|
+
export interface ResolveTypeRefContext {
|
|
57
|
+
readonly scopes: ScopeLookup;
|
|
58
|
+
readonly defIndex: DefIndex;
|
|
59
|
+
readonly qualifiedNameIndex: QualifiedNameIndex;
|
|
60
|
+
}
|
|
61
|
+
export declare function resolveTypeRef(ref: TypeRef, ctx: ResolveTypeRefContext): SymbolDefinition | null;
|
|
62
|
+
//# sourceMappingURL=resolve-type-ref.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-type-ref.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/resolve-type-ref.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAc,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAIpE;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC;CAC1C;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;CACjD;AAsCD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,qBAAqB,GAAG,gBAAgB,GAAG,IAAI,CAgDhG"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `resolveTypeRef` — strict single-return resolver for `TypeRef`s
|
|
3
|
+
* (RFC §4.6; Ring 2 SHARED #916).
|
|
4
|
+
*
|
|
5
|
+
* Narrower contract than `Registry.lookup`: no name-only global fallback, no
|
|
6
|
+
* confidence ranking, no arity check. Used by `Registry.lookup` Step 2 (type-
|
|
7
|
+
* binding propagation) and by any caller that wants the single best type-
|
|
8
|
+
* target for an annotation without paying for the full evidence pipeline.
|
|
9
|
+
*
|
|
10
|
+
* **Algorithm (strict).** Walk the scope chain from `ref.declaredAtScope`:
|
|
11
|
+
*
|
|
12
|
+
* 1. At each scope, inspect `bindings.get(ref.rawName)`:
|
|
13
|
+
* - If one of the bindings is a **type-kind** def with a **strict origin**
|
|
14
|
+
* (`'local' | 'import' | 'namespace' | 'reexport'`), return it.
|
|
15
|
+
* - If any binding for this name exists at this scope but none qualifies
|
|
16
|
+
* (e.g., a local variable named `User` shadows an outer import of class
|
|
17
|
+
* `User`), return `null`. The nearer binding shadows; we do NOT fall
|
|
18
|
+
* through to the global qualified-name index.
|
|
19
|
+
* - Otherwise continue to the parent scope.
|
|
20
|
+
* 2. If the raw name is a dotted path (e.g., `'models.User'`) and the scope
|
|
21
|
+
* walk produced no match, consult `QualifiedNameIndex.byQualifiedName`.
|
|
22
|
+
* Only accept **exactly one** type-kind hit — anything ambiguous returns
|
|
23
|
+
* `null` rather than a guess.
|
|
24
|
+
* 3. Return `null`.
|
|
25
|
+
*
|
|
26
|
+
* **What `'strict' origins' means.** `'wildcard'` is intentionally excluded.
|
|
27
|
+
* A wildcard-expanded name (`from x import *`) is too loose to use as an
|
|
28
|
+
* anchor for type resolution — it gives no signal about whether the name was
|
|
29
|
+
* actually imported. `Registry.lookup` may accept wildcard bindings at its
|
|
30
|
+
* own discretion (with lower evidence weight); `resolveTypeRef` does not.
|
|
31
|
+
*
|
|
32
|
+
* **What 'type-kind' means.** The subset of `NodeLabel` that a type annotation
|
|
33
|
+
* may legitimately reference: class-like, interface-like, enum-like, and
|
|
34
|
+
* alias-like kinds. See `TYPE_KINDS` below.
|
|
35
|
+
*
|
|
36
|
+
* Pure function — safe to call repeatedly; no side effects.
|
|
37
|
+
*/
|
|
38
|
+
// ─── Strict policy constants ────────────────────────────────────────────────
|
|
39
|
+
/** `'wildcard'` is deliberately absent. See file header. */
|
|
40
|
+
const STRICT_ORIGINS = new Set([
|
|
41
|
+
'local',
|
|
42
|
+
'import',
|
|
43
|
+
'namespace',
|
|
44
|
+
'reexport',
|
|
45
|
+
]);
|
|
46
|
+
/**
|
|
47
|
+
* `NodeLabel` values that may appear on the RHS of a type annotation.
|
|
48
|
+
*
|
|
49
|
+
* Includes the usual class-like and interface-like kinds plus the alias-like
|
|
50
|
+
* ones (`TypeAlias`, `Typedef`). `Namespace` is excluded — it is a scope
|
|
51
|
+
* container, not a value type. `Function` / `Method` / `Variable` are
|
|
52
|
+
* excluded by design: a `rawName` bound to them at a strict origin is a
|
|
53
|
+
* *shadowing* binding, which the algorithm short-circuits to `null`.
|
|
54
|
+
*/
|
|
55
|
+
const TYPE_KINDS = new Set([
|
|
56
|
+
'Class',
|
|
57
|
+
'Interface',
|
|
58
|
+
'Enum',
|
|
59
|
+
'Struct',
|
|
60
|
+
'Union',
|
|
61
|
+
'Trait',
|
|
62
|
+
'TypeAlias',
|
|
63
|
+
'Typedef',
|
|
64
|
+
'Record',
|
|
65
|
+
'Delegate',
|
|
66
|
+
'Annotation',
|
|
67
|
+
'Template',
|
|
68
|
+
]);
|
|
69
|
+
// ─── Main entry point ──────────────────────────────────────────────────────
|
|
70
|
+
export function resolveTypeRef(ref, ctx) {
|
|
71
|
+
// Phase 1: scope-chain walk anchored at the declaration site.
|
|
72
|
+
let currentId = ref.declaredAtScope;
|
|
73
|
+
const visited = new Set();
|
|
74
|
+
while (currentId !== null) {
|
|
75
|
+
// Cycle guard — a well-formed scope tree never loops, but a bug in the
|
|
76
|
+
// construction path should fail fast here rather than hanging.
|
|
77
|
+
if (visited.has(currentId))
|
|
78
|
+
return null;
|
|
79
|
+
visited.add(currentId);
|
|
80
|
+
const scope = ctx.scopes.getScope(currentId);
|
|
81
|
+
if (scope === undefined)
|
|
82
|
+
return null; // broken chain = unresolvable
|
|
83
|
+
const bindings = scope.bindings.get(ref.rawName);
|
|
84
|
+
if (bindings !== undefined && bindings.length > 0) {
|
|
85
|
+
// At least one binding exists at this scope → it is the shadowing site.
|
|
86
|
+
// Either one of them qualifies, or the name is shadowed by a non-type.
|
|
87
|
+
for (const binding of bindings) {
|
|
88
|
+
if (!STRICT_ORIGINS.has(binding.origin))
|
|
89
|
+
continue;
|
|
90
|
+
if (TYPE_KINDS.has(binding.def.type)) {
|
|
91
|
+
return binding.def;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Shadowed by a non-type / non-strict-origin binding. Fail fast — no
|
|
95
|
+
// global fallback, no walk to the parent.
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
currentId = scope.parent;
|
|
99
|
+
}
|
|
100
|
+
// Phase 2: dotted fallback via `QualifiedNameIndex`. Only accept a unique
|
|
101
|
+
// type-kind hit; anything ambiguous returns null (strict: no guesses).
|
|
102
|
+
if (ref.rawName.includes('.')) {
|
|
103
|
+
const candidates = ctx.qualifiedNameIndex.get(ref.rawName);
|
|
104
|
+
let onlyTypeDef = null;
|
|
105
|
+
for (const defId of candidates) {
|
|
106
|
+
const def = ctx.defIndex.get(defId);
|
|
107
|
+
if (def === undefined)
|
|
108
|
+
continue;
|
|
109
|
+
if (!TYPE_KINDS.has(def.type))
|
|
110
|
+
continue;
|
|
111
|
+
if (onlyTypeDef !== null)
|
|
112
|
+
return null; // ambiguous
|
|
113
|
+
onlyTypeDef = def;
|
|
114
|
+
}
|
|
115
|
+
if (onlyTypeDef !== null)
|
|
116
|
+
return onlyTypeDef;
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=resolve-type-ref.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-type-ref.js","sourceRoot":"","sources":["../../src/scope-resolution/resolve-type-ref.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AA+BH,+EAA+E;AAE/E,4DAA4D;AAC5D,MAAM,cAAc,GAAsC,IAAI,GAAG,CAAuB;IACtF,OAAO;IACP,QAAQ;IACR,WAAW;IACX,UAAU;CACX,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,UAAU,GAA2B,IAAI,GAAG,CAAY;IAC5D,OAAO;IACP,WAAW;IACX,MAAM;IACN,QAAQ;IACR,OAAO;IACP,OAAO;IACP,WAAW;IACX,SAAS;IACT,QAAQ;IACR,UAAU;IACV,YAAY;IACZ,UAAU;CACX,CAAC,CAAC;AAEH,8EAA8E;AAE9E,MAAM,UAAU,cAAc,CAAC,GAAY,EAAE,GAA0B;IACrE,8DAA8D;IAC9D,IAAI,SAAS,GAAmB,GAAG,CAAC,eAAe,CAAC;IACpD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAW,CAAC;IAEnC,OAAO,SAAS,KAAK,IAAI,EAAE,CAAC;QAC1B,uEAAuE;QACvE,+DAA+D;QAC/D,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEvB,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,CAAC,8BAA8B;QAEpE,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACjD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,wEAAwE;YACxE,uEAAuE;YACvE,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;oBAAE,SAAS;gBAClD,IAAI,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrC,OAAO,OAAO,CAAC,GAAG,CAAC;gBACrB,CAAC;YACH,CAAC;YACD,qEAAqE;YACrE,0CAA0C;YAC1C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,0EAA0E;IAC1E,uEAAuE;IACvE,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3D,IAAI,WAAW,GAA4B,IAAI,CAAC;QAChD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACpC,IAAI,GAAG,KAAK,SAAS;gBAAE,SAAS;YAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS;YACxC,IAAI,WAAW,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC,CAAC,YAAY;YACnD,WAAW,GAAG,GAAG,CAAC;QACpB,CAAC;QACD,IAAI,WAAW,KAAK,IAAI;YAAE,OAAO,WAAW,CAAC;IAC/C,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|