gitnexus 1.6.13-rc.18 → 1.6.13-rc.19

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.
Files changed (30) hide show
  1. package/dist/_shared/index.d.ts +1 -0
  2. package/dist/_shared/index.d.ts.map +1 -1
  3. package/dist/_shared/index.js.map +1 -1
  4. package/dist/_shared/scope-resolution/call-result-assignment-site.d.ts +14 -0
  5. package/dist/_shared/scope-resolution/call-result-assignment-site.d.ts.map +1 -0
  6. package/dist/_shared/scope-resolution/call-result-assignment-site.js +2 -0
  7. package/dist/_shared/scope-resolution/call-result-assignment-site.js.map +1 -0
  8. package/dist/_shared/scope-resolution/parsed-file.d.ts +3 -0
  9. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
  10. package/dist/core/ingestion/languages/swift/captures.js +30 -2
  11. package/dist/core/ingestion/languages/swift/index.d.ts +1 -1
  12. package/dist/core/ingestion/languages/swift/index.js +1 -1
  13. package/dist/core/ingestion/languages/swift/interpret.d.ts +8 -0
  14. package/dist/core/ingestion/languages/swift/interpret.js +16 -1
  15. package/dist/core/ingestion/languages/swift/query.js +26 -0
  16. package/dist/core/ingestion/languages/swift/scope-resolver.d.ts +2 -1
  17. package/dist/core/ingestion/languages/swift/scope-resolver.js +90 -1
  18. package/dist/core/ingestion/scope-extractor.d.ts +7 -3
  19. package/dist/core/ingestion/scope-extractor.js +59 -13
  20. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +5 -0
  21. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +10 -5
  22. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +87 -14
  23. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +11 -0
  24. package/dist/core/ingestion/scope-resolution/pipeline/run.js +109 -7
  25. package/dist/core/ingestion/scope-resolution/workspace-index-types.d.ts +6 -1
  26. package/dist/core/ingestion/scope-resolution/workspace-index.d.ts +3 -1
  27. package/dist/core/ingestion/scope-resolution/workspace-index.js +27 -2
  28. package/dist/storage/parse-cache.js +3 -1
  29. package/dist/storage/parsedfile-store.js +25 -2
  30. package/package.json +1 -1
@@ -23,6 +23,7 @@ export type { QualifiedNameIndex } from './scope-resolution/qualified-name-index
23
23
  export { resolveTypeRef } from './scope-resolution/resolve-type-ref.js';
24
24
  export type { ResolveTypeRefContext } from './scope-resolution/resolve-type-ref.js';
25
25
  export type { ParsedFile } from './scope-resolution/parsed-file.js';
26
+ export type { CallResultAssignmentSite } from './scope-resolution/call-result-assignment-site.js';
26
27
  export type { ReferenceSite, ReferenceKind, CallForm, MixedChainStep, } from './scope-resolution/reference-site.js';
27
28
  export type { CallableFlowOperand, CallableFlowExpectedSignature, CallableFlowPassingMode, CallableFlowInvocationKind, CallableFlowSeedSite, CallableFlowCopySite, CallableFlowAliasSite, CallableFlowAddressSite, CallableFlowStoreSite, CallableFlowLoadSite, CallableFlowFormalSite, CallableFlowArgumentSite, CallableFlowInvokeSite, CallableFlowSite, } from './scope-resolution/callable-flow-site.js';
28
29
  export { buildMethodDispatchIndex } from './scope-resolution/method-dispatch-index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -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,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAGjC,sBAAsB;AACtB,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AA4C5E,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,yEAAyE;AACzE,2DAA2D;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AA4BxE,oFAAoF;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AAMvF,uEAAuE;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AAWpE,sEAAsE;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AAKvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAKrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAErF,OAAO,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,mDAAmD,CAAC;AAEpF,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAEpG,OAAO,EACL,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,0CAA0C,CAAC;AAUlD,2EAA2E;AAC3E,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAErF,OAAO,EACL,cAAc,EACd,cAAc,EACd,uBAAuB,GACxB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAG1E,8EAA8E;AAC9E,wEAAwE;AACxE,wEAAwE;AACxE,8DAA8D;AAC9D,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAEjG,OAAO,EACL,cAAc,EACd,4BAA4B,EAC5B,kBAAkB,EAClB,eAAe,EACf,sBAAsB,GACvB,MAAM,mCAAmC,CAAC;AAG3C,mDAAmD;AACnD,OAAO,EACL,+BAA+B,EAC/B,6BAA6B,EAC7B,4BAA4B,EAC5B,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,GACf,MAAM,sCAAsC,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,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAGjC,sBAAsB;AACtB,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AA4C5E,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,yEAAyE;AACzE,2DAA2D;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AA6BxE,oFAAoF;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AAMvF,uEAAuE;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AAWpE,sEAAsE;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AAKvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAKrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAErF,OAAO,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,mDAAmD,CAAC;AAEpF,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAEpG,OAAO,EACL,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,0CAA0C,CAAC;AAUlD,2EAA2E;AAC3E,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAErF,OAAO,EACL,cAAc,EACd,cAAc,EACd,uBAAuB,GACxB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAG1E,8EAA8E;AAC9E,wEAAwE;AACxE,wEAAwE;AACxE,8DAA8D;AAC9D,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAEjG,OAAO,EACL,cAAc,EACd,4BAA4B,EAC5B,kBAAkB,EAClB,eAAe,EACf,sBAAsB,GACvB,MAAM,mCAAmC,CAAC;AAG3C,mDAAmD;AACnD,OAAO,EACL,+BAA+B,EAC/B,6BAA6B,EAC7B,4BAA4B,EAC5B,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,GACf,MAAM,sCAAsC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Range, ScopeId } from './types.js';
2
+ /**
3
+ * Compact extraction-time identity for `lhs = callee()`.
4
+ *
5
+ * The call-site range uses the same call-expression anchor as reference
6
+ * resolution, allowing downstream passes to join this fact to the exact
7
+ * resolved callee id without relying on a possibly polluted type binding.
8
+ */
9
+ export interface CallResultAssignmentSite {
10
+ readonly callSite: Range;
11
+ readonly inScope: ScopeId;
12
+ readonly lhs: string;
13
+ }
14
+ //# sourceMappingURL=call-result-assignment-site.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call-result-assignment-site.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/call-result-assignment-site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=call-result-assignment-site.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call-result-assignment-site.js","sourceRoot":"","sources":["../../src/scope-resolution/call-result-assignment-site.ts"],"names":[],"mappings":""}
@@ -55,6 +55,7 @@ import type { ParsedImport } from './types.js';
55
55
  import type { SymbolDefinition } from './symbol-definition.js';
56
56
  import type { ReferenceSite } from './reference-site.js';
57
57
  import type { CallableFlowSite } from './callable-flow-site.js';
58
+ import type { CallResultAssignmentSite } from './call-result-assignment-site.js';
58
59
  export interface ParsedFile {
59
60
  readonly filePath: string;
60
61
  /** `Scope.id` of the file's root `Module` scope. */
@@ -79,6 +80,8 @@ export interface ParsedFile {
79
80
  * syntax remain source-compatible; consumers normalize absence to `[]`.
80
81
  */
81
82
  readonly callableFlowSites?: readonly CallableFlowSite[];
83
+ /** Exact call-expression → assigned local identity for return-type replay. */
84
+ readonly callResultAssignmentSites?: readonly CallResultAssignmentSite[];
82
85
  /**
83
86
  * Opaque, language-private serialization of capture-time side-channel
84
87
  * state that a provider's `emitScopeCaptures` populates into module-level
@@ -1 +1 @@
1
- {"version":3,"file":"parsed-file.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/parsed-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAC;IAChD;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAChD,QAAQ,CAAC,cAAc,EAAE,SAAS,aAAa,EAAE,CAAC;IAClD;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACzD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAEtC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC"}
1
+ {"version":3,"file":"parsed-file.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/parsed-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAEjF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAC;IAChD;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAChD,QAAQ,CAAC,cAAc,EAAE,SAAS,aAAa,EAAE,CAAC;IAClD;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACzD,8EAA8E;IAC9E,QAAQ,CAAC,yBAAyB,CAAC,EAAE,SAAS,wBAAwB,EAAE,CAAC;IACzE;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAEtC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC"}
@@ -37,6 +37,7 @@ import { swiftQualifiedBaseTail } from './base-type.js';
37
37
  import { computeSwiftArityMetadata } from './arity-metadata.js';
38
38
  import { findEnclosingTypeDeclaration, synthesizeSwiftReceiverBinding, } from './receiver-binding.js';
39
39
  import { synthesizeSwiftSignatureBindings } from './signature-bindings.js';
40
+ import { swiftMethodConfig } from '../../method-extractors/configs/swift.js';
40
41
  import { getSwiftParser, getSwiftScopeQuery } from './query.js';
41
42
  import { preprocessSwiftConditionalDirectives } from './conditional-directive-preprocess.js';
42
43
  import { recordCacheHit, recordCacheMiss } from './cache-stats.js';
@@ -174,6 +175,23 @@ export function emitSwiftScopeCaptures(sourceText, _filePath, cachedTree) {
174
175
  }
175
176
  continue;
176
177
  }
178
+ // The query deliberately recognizes the compact `lhs = call()` shape;
179
+ // enforce "untyped lhs" here because tree-sitter queries cannot express
180
+ // absence of Swift's sibling type_annotation robustly. A typed declaration
181
+ // remains authoritative and must never enter return-type replay.
182
+ if (grouped['@call-result-assignment.call'] !== undefined) {
183
+ const callNode = nodeIfType(nodeMap['@call-result-assignment.call'], 'call_expression');
184
+ let property = callNode?.parent;
185
+ while (property?.type === 'await_expression' || property?.type === 'try_expression') {
186
+ property = property.parent;
187
+ }
188
+ if (property?.type !== 'property_declaration' ||
189
+ property.namedChildren.some((child) => child.type === 'type_annotation')) {
190
+ continue;
191
+ }
192
+ out.push(grouped);
193
+ continue;
194
+ }
177
195
  // ── Field accesses: a `navigation_expression` (`obj.field`) is one of
178
196
  // three things. Drop it when it's a call's callee (`u.save` in
179
197
  // `u.save()` — the @reference.call.member query already covers that).
@@ -279,8 +297,13 @@ export function emitSwiftScopeCaptures(sourceText, _filePath, cachedTree) {
279
297
  const fnNodeForArity = nodeIfType(nodeMap['@scope.function'] ??
280
298
  nodeMap['@declaration.method'] ??
281
299
  nodeMap['@declaration.constructor'], ...FUNCTION_NODE_TYPES);
282
- if (fnNodeForArity !== null)
300
+ if (fnNodeForArity !== null) {
283
301
  attachArityMetadata(grouped, fnNodeForArity);
302
+ const returnType = swiftMethodConfig.extractReturnType?.(fnNodeForArity);
303
+ if (returnType !== undefined && returnType !== '') {
304
+ grouped['@declaration.return-type'] = syntheticCapture('@declaration.return-type', fnNodeForArity, returnType);
305
+ }
306
+ }
284
307
  // Structural receiver chain for a call whose receiver is itself an
285
308
  // expression, so resolution can type it by folding over structure
286
309
  // instead of re-parsing the receiver's source text. Self-gating: a
@@ -304,8 +327,13 @@ export function emitSwiftScopeCaptures(sourceText, _filePath, cachedTree) {
304
327
  const declTag = FUNCTION_DECL_TAGS.find((t) => grouped[t] !== undefined);
305
328
  if (declTag !== undefined) {
306
329
  const fnNode = nodeIfType(nodeMap[declTag], ...FUNCTION_NODE_TYPES);
307
- if (fnNode !== null)
330
+ if (fnNode !== null) {
308
331
  attachArityMetadata(grouped, fnNode);
332
+ const returnType = swiftMethodConfig.extractReturnType?.(fnNode);
333
+ if (returnType !== undefined && returnType !== '') {
334
+ grouped['@declaration.return-type'] = syntheticCapture('@declaration.return-type', fnNode, returnType);
335
+ }
336
+ }
309
337
  }
310
338
  // ── Constructor calls: Swift has no `new`, so `Foo()` is a free call
311
339
  // whose callee is a type. Re-tag an UpperCamelCase free-call callee as
@@ -26,7 +26,7 @@
26
26
  */
27
27
  export { emitSwiftScopeCaptures } from './captures.js';
28
28
  export { getSwiftCaptureCacheStats, resetSwiftCaptureCacheStats } from './cache-stats.js';
29
- export { interpretSwiftImport, interpretSwiftTypeBinding } from './interpret.js';
29
+ export { interpretSwiftImport, interpretSwiftTypeBinding, normalizeSwiftTypeName, stripSwiftTypePreservingDecoration, } from './interpret.js';
30
30
  export { swiftMergeBindings } from './merge-bindings.js';
31
31
  export { swiftArityCompatibility } from './arity.js';
32
32
  export { resolveSwiftImportTarget, type SwiftResolveContext } from './import-target.js';
@@ -26,7 +26,7 @@
26
26
  */
27
27
  export { emitSwiftScopeCaptures } from './captures.js';
28
28
  export { getSwiftCaptureCacheStats, resetSwiftCaptureCacheStats } from './cache-stats.js';
29
- export { interpretSwiftImport, interpretSwiftTypeBinding } from './interpret.js';
29
+ export { interpretSwiftImport, interpretSwiftTypeBinding, normalizeSwiftTypeName, stripSwiftTypePreservingDecoration, } from './interpret.js';
30
30
  export { swiftMergeBindings } from './merge-bindings.js';
31
31
  export { swiftArityCompatibility } from './arity.js';
32
32
  export { resolveSwiftImportTarget } from './import-target.js';
@@ -13,3 +13,11 @@
13
13
  import type { CaptureMatch, ParsedImport, ParsedTypeBinding } from '../../../../_shared/index.js';
14
14
  export declare function interpretSwiftImport(captures: CaptureMatch): ParsedImport | null;
15
15
  export declare function interpretSwiftTypeBinding(captures: CaptureMatch): ParsedTypeBinding | null;
16
+ export declare function normalizeSwiftTypeName(text: string): string;
17
+ /**
18
+ * Type-preserving decoration only — used by `stripTypePreservingDecoration`
19
+ * for class lookup and declared-return replay. `User?` / `User!` → `User`.
20
+ * Arrays, generics, and nested `Foo.Bar` are left intact so a binding used
21
+ * for member lookup does not follow the element type or the trailing ident.
22
+ */
23
+ export declare function stripSwiftTypePreservingDecoration(typeName: string): string | undefined;
@@ -40,7 +40,7 @@ export function interpretSwiftTypeBinding(captures) {
40
40
  // `[User]` → User (array sugar)
41
41
  // `Array<User>` / `Optional<User>` → User (single-arg generic)
42
42
  // `Foundation.URL` → URL (qualifier)
43
- const rawType = stripQualifier(stripGeneric(stripArraySugar(stripOptional(typeCap.text.trim()))));
43
+ const rawType = normalizeSwiftTypeName(typeCap.text);
44
44
  let source = 'parameter-annotation';
45
45
  if (captures['@type-binding.self'] !== undefined)
46
46
  source = 'self';
@@ -54,6 +54,21 @@ export function interpretSwiftTypeBinding(captures) {
54
54
  source = 'return-annotation';
55
55
  return { boundName: nameCap.text, rawTypeName: rawType, source };
56
56
  }
57
+ export function normalizeSwiftTypeName(text) {
58
+ return stripQualifier(stripGeneric(stripArraySugar(stripOptional(text.trim()))));
59
+ }
60
+ /**
61
+ * Type-preserving decoration only — used by `stripTypePreservingDecoration`
62
+ * for class lookup and declared-return replay. `User?` / `User!` → `User`.
63
+ * Arrays, generics, and nested `Foo.Bar` are left intact so a binding used
64
+ * for member lookup does not follow the element type or the trailing ident.
65
+ */
66
+ export function stripSwiftTypePreservingDecoration(typeName) {
67
+ const trimmed = typeName.trim();
68
+ if (trimmed.endsWith('?') || trimmed.endsWith('!'))
69
+ return trimmed.slice(0, -1).trim();
70
+ return undefined;
71
+ }
57
72
  /** `User?` / `User!` → `User`. */
58
73
  function stripOptional(text) {
59
74
  if (text.endsWith('?') || text.endsWith('!'))
@@ -186,6 +186,32 @@ const SWIFT_SCOPE_QUERY = `
186
186
  (call_expression
187
187
  (simple_identifier) @reference.name) @reference.call.free
188
188
 
189
+ ;; Exact identity for \`let lhs = callee()\`. The call-expression anchor is
190
+ ;; byte-identical to @reference.call.free / member for downstream position join.
191
+ (property_declaration
192
+ name: (pattern
193
+ bound_identifier: (simple_identifier) @call-result-assignment.lhs)
194
+ value: (call_expression) @call-result-assignment.call)
195
+
196
+ (property_declaration
197
+ name: (pattern
198
+ bound_identifier: (simple_identifier) @call-result-assignment.lhs)
199
+ value: (await_expression
200
+ (call_expression) @call-result-assignment.call))
201
+
202
+ (property_declaration
203
+ name: (pattern
204
+ bound_identifier: (simple_identifier) @call-result-assignment.lhs)
205
+ value: (try_expression
206
+ (call_expression) @call-result-assignment.call))
207
+
208
+ (property_declaration
209
+ name: (pattern
210
+ bound_identifier: (simple_identifier) @call-result-assignment.lhs)
211
+ value: (try_expression
212
+ (await_expression
213
+ (call_expression) @call-result-assignment.call)))
214
+
189
215
  ;; ── References — member / method calls: \`obj.method(...)\` ───────────
190
216
  ;; navigation_expression carries the receiver (target:) and the member
191
217
  ;; (suffix > navigation_suffix > simple_identifier). \`self\` is a
@@ -14,7 +14,8 @@
14
14
  * re-keys an `extension Foo { … }` to a `class_declaration`-style def
15
15
  * named `Foo`, so its members land on `Foo`'s scope and the shared
16
16
  * `populateClassOwnedMembers` stamps them with `Foo`'s ownerId — the
17
- * same mechanism C# uses for `partial class`. No separate hoist pass.
17
+ * same mechanism C# uses for `partial class`. Cross-file extensions
18
+ * that mint no type def are reconciled by `populateWorkspaceOwners`.
18
19
  * - **Labeled arguments** narrow by ARITY only (count-primary, labels
19
20
  * soft) — see `arity.ts`. Label-precise dispatch is deferred to the
20
21
  * type-binding layer.
@@ -14,7 +14,8 @@
14
14
  * re-keys an `extension Foo { … }` to a `class_declaration`-style def
15
15
  * named `Foo`, so its members land on `Foo`'s scope and the shared
16
16
  * `populateClassOwnedMembers` stamps them with `Foo`'s ownerId — the
17
- * same mechanism C# uses for `partial class`. No separate hoist pass.
17
+ * same mechanism C# uses for `partial class`. Cross-file extensions
18
+ * that mint no type def are reconciled by `populateWorkspaceOwners`.
18
19
  * - **Labeled arguments** narrow by ARITY only (count-primary, labels
19
20
  * soft) — see `arity.ts`. Label-precise dispatch is deferred to the
20
21
  * type-binding layer.
@@ -52,6 +53,8 @@ import { populateClassOwnedMembers, isClassLike } from '../../scope-resolution/s
52
53
  import { resolveDefGraphId } from '../../scope-resolution/graph-bridge/ids.js';
53
54
  import { swiftProvider } from '../swift.js';
54
55
  import { swiftArityCompatibility, swiftMergeBindings, interpretSwiftImport, resolveSwiftImportTarget, populateSwiftTargetSiblings, emitSwiftImplicitImportEdges, mirrorSwiftSiblingTypeBindings, } from './index.js';
56
+ import { stripSwiftTypePreservingDecoration } from './interpret.js';
57
+ import { coerceSwiftTargets, groupSwiftFilesBySpmTarget } from './target-grouping.js';
55
58
  import { swiftIsGlobalNameFallbackPlausible } from './name-fallback-visibility.js';
56
59
  const ZERO_RANGE = { startLine: 0, startCol: 0, endLine: 0, endCol: 0 };
57
60
  const swiftScopeResolver = {
@@ -77,11 +80,19 @@ const swiftScopeResolver = {
77
80
  // Adapter: swiftArityCompatibility uses (def, callsite); contract is (callsite, def).
78
81
  arityCompatibility: (callsite, def) => swiftArityCompatibility(def, callsite),
79
82
  buildMro: (graph, parsedFiles, nodeLookup) => buildSwiftMro(graph, parsedFiles, nodeLookup),
83
+ implicitThisWalksMro: true,
84
+ stripTypePreservingDecoration: stripSwiftTypePreservingDecoration,
80
85
  // Methods/properties/init are owned by their enclosing class/struct/
81
86
  // extension(→extended type)/protocol. Extension members hoist for free
82
87
  // because captures.ts re-keys the extension to a Class def named after
83
88
  // the extended type.
84
89
  populateOwners: (parsed) => populateClassOwnedMembers(parsed),
90
+ // An extension has its own Class scope but deliberately does not mint a
91
+ // second type def. Its members therefore leave the per-file owner walk with
92
+ // a qualified name (`ExtendedType.member`) but no ownerId. Reconcile those
93
+ // members after all files are available so extensions declared in sibling
94
+ // files work as well as extensions beside the original type.
95
+ populateWorkspaceOwners: populateSwiftExtensionOwners,
85
96
  // `super.method()` dispatches through the superclass chain.
86
97
  isSuperReceiver: (text) => text.trim() === 'super',
87
98
  // Whole-module same-target visibility without `import`.
@@ -172,6 +183,84 @@ function buildSwiftMro(graph, parsedFiles, nodeLookup) {
172
183
  }
173
184
  return mro;
174
185
  }
186
+ function populateSwiftExtensionOwners(parsedFiles, ctx) {
187
+ const filesByTarget = groupSwiftFilesBySpmTarget(parsedFiles, (parsed) => parsed.filePath, coerceSwiftTargets(ctx?.resolutionConfig));
188
+ for (const files of filesByTarget.values()) {
189
+ stampSwiftExtensionOwnersInTarget(files);
190
+ }
191
+ }
192
+ function stampSwiftExtensionOwnersInTarget(parsedFiles) {
193
+ const ownersByName = new Map();
194
+ for (const parsed of parsedFiles) {
195
+ for (const def of parsed.localDefs) {
196
+ if (!isClassLike(def.type) || def.qualifiedName === undefined)
197
+ continue;
198
+ const bucket = ownersByName.get(def.qualifiedName);
199
+ if (bucket === undefined)
200
+ ownersByName.set(def.qualifiedName, [def]);
201
+ else
202
+ bucket.push(def);
203
+ }
204
+ }
205
+ // Extension members are Function-owned defs whose parent Class minted no
206
+ // type def. Nested locals are Function-owned defs whose parent is another
207
+ // Function — leave those ownerless so they cannot enter implicit-self CALLS.
208
+ for (const parsed of parsedFiles) {
209
+ const byId = new Map(parsed.scopes.map((scope) => [scope.id, scope]));
210
+ for (const scope of parsed.scopes) {
211
+ if (scope.kind !== 'Function')
212
+ continue;
213
+ const parent = scope.parent === null ? undefined : byId.get(scope.parent);
214
+ if (parent?.kind !== 'Class')
215
+ continue;
216
+ // A type-decl Class owns the type that opened it (same start line).
217
+ // Nested types inside an `extension` are also class-like and live on
218
+ // that Class scope — they are not the extended type, so they must
219
+ // not suppress stamping `func added` onto `Foo`.
220
+ if (parent.ownedDefs.some((d) => isClassLike(d.type) && defDeclaresThisClassScope(parent, d)))
221
+ continue;
222
+ for (const def of scope.ownedDefs) {
223
+ if (def.ownerId !== undefined || def.qualifiedName === undefined)
224
+ continue;
225
+ const dot = def.qualifiedName.lastIndexOf('.');
226
+ if (dot <= 0)
227
+ continue;
228
+ const owner = uniqueOwnerForExtensionPrefix(ownersByName, def.qualifiedName.slice(0, dot));
229
+ if (owner !== undefined) {
230
+ def.ownerId = owner.nodeId;
231
+ }
232
+ }
233
+ }
234
+ }
235
+ }
236
+ function defDeclaresThisClassScope(parent, def) {
237
+ const line = /#(\d+):/.exec(def.nodeId);
238
+ if (line === null)
239
+ return true;
240
+ return Number(line[1]) === parent.range.startLine;
241
+ }
242
+ function uniqueOwnerForExtensionPrefix(ownersByName, prefix) {
243
+ const seen = new Set();
244
+ const matches = [];
245
+ const consider = (defs) => {
246
+ if (defs === undefined)
247
+ return;
248
+ for (const def of defs) {
249
+ if (seen.has(def.nodeId))
250
+ continue;
251
+ seen.add(def.nodeId);
252
+ matches.push(def);
253
+ }
254
+ };
255
+ consider(ownersByName.get(prefix));
256
+ if (!prefix.includes('.')) {
257
+ for (const [qn, defs] of ownersByName) {
258
+ if (qn !== prefix && qn.endsWith('.' + prefix))
259
+ consider(defs);
260
+ }
261
+ }
262
+ return matches.length === 1 ? matches[0] : undefined;
263
+ }
175
264
  function closeProtocols(seeds, directImpls) {
176
265
  const out = [];
177
266
  const seen = new Set();
@@ -4,7 +4,7 @@
4
4
  * (RFC §5.3 + §3.2 Phase 1; Ring 2 PKG #919).
5
5
  *
6
6
  * Exactly one entry point: `extract(matches, filePath, provider) → ParsedFile`.
7
- * Runs a five-pass pipeline over the matches. Each pass is internal; the
7
+ * Runs a seven-pass pipeline over the matches. Each pass is internal; the
8
8
  * public contract is the output `ParsedFile`.
9
9
  *
10
10
  * ## Design principles
@@ -22,7 +22,7 @@
22
22
  * don't overlap) are enforced by `buildScopeTree` from Ring 2 SHARED
23
23
  * (#912). Malformed inputs throw `ScopeTreeInvariantError`.
24
24
  *
25
- * ## The five passes
25
+ * ## The seven passes
26
26
  *
27
27
  * 1. **Build scope tree.** Walk `@scope.*` matches. For each, consult
28
28
  * `provider.resolveScopeKind` (default: suffix of the capture name).
@@ -60,6 +60,10 @@
60
60
  * one `ReferenceSite` per match. Classify call form via
61
61
  * `provider.classifyCallForm` (default: the capture's sub-tag if
62
62
  * present; else `'free'`).
63
+ * 6. **Collect callable-value-flow facts.** Independent of Pass 5 so
64
+ * existing reference-site extraction stays byte-identical.
65
+ * 7. **Preserve call-result assignment identity.** Untyped
66
+ * `let lhs = call()` facts used by exact-callee return-type replay.
63
67
  *
64
68
  * ## What gets attached where
65
69
  *
@@ -90,7 +94,7 @@ import type { LanguageProvider } from './language-provider.js';
90
94
  */
91
95
  export type ScopeExtractorHooks = Pick<LanguageProvider, 'resolveScopeKind' | 'scopeOwnsReceivers' | 'bindingScopeFor' | 'interpretImport' | 'importsExecuteWhereWritten' | 'interpretTypeBinding' | 'classifyCallForm'>;
92
96
  /**
93
- * Drive the five extraction passes and return a `ParsedFile`.
97
+ * Drive the seven extraction passes and return a `ParsedFile`.
94
98
  *
95
99
  * Throws `ScopeTreeInvariantError` (from #912) when the provider emits
96
100
  * captures that violate structural scope invariants (e.g., overlapping
@@ -4,7 +4,7 @@
4
4
  * (RFC §5.3 + §3.2 Phase 1; Ring 2 PKG #919).
5
5
  *
6
6
  * Exactly one entry point: `extract(matches, filePath, provider) → ParsedFile`.
7
- * Runs a five-pass pipeline over the matches. Each pass is internal; the
7
+ * Runs a seven-pass pipeline over the matches. Each pass is internal; the
8
8
  * public contract is the output `ParsedFile`.
9
9
  *
10
10
  * ## Design principles
@@ -22,7 +22,7 @@
22
22
  * don't overlap) are enforced by `buildScopeTree` from Ring 2 SHARED
23
23
  * (#912). Malformed inputs throw `ScopeTreeInvariantError`.
24
24
  *
25
- * ## The five passes
25
+ * ## The seven passes
26
26
  *
27
27
  * 1. **Build scope tree.** Walk `@scope.*` matches. For each, consult
28
28
  * `provider.resolveScopeKind` (default: suffix of the capture name).
@@ -60,6 +60,10 @@
60
60
  * one `ReferenceSite` per match. Classify call form via
61
61
  * `provider.classifyCallForm` (default: the capture's sub-tag if
62
62
  * present; else `'free'`).
63
+ * 6. **Collect callable-value-flow facts.** Independent of Pass 5 so
64
+ * existing reference-site extraction stays byte-identical.
65
+ * 7. **Preserve call-result assignment identity.** Untyped
66
+ * `let lhs = call()` facts used by exact-callee return-type replay.
63
67
  *
64
68
  * ## What gets attached where
65
69
  *
@@ -79,7 +83,7 @@ import { extractTemplateArguments, stripTrailingCallSuffix, typeApplicationArgum
79
83
  import { parseTypeParameterList } from './utils/type-parameters.js';
80
84
  // ─── Public entry point ─────────────────────────────────────────────────────
81
85
  /**
82
- * Drive the five extraction passes and return a `ParsedFile`.
86
+ * Drive the seven extraction passes and return a `ParsedFile`.
83
87
  *
84
88
  * Throws `ScopeTreeInvariantError` (from #912) when the provider emits
85
89
  * captures that violate structural scope invariants (e.g., overlapping
@@ -137,6 +141,9 @@ export function extract(matches, filePath, provider) {
137
141
  // extraction remains byte-identical.
138
142
  const callableFlowSites = [];
139
143
  pass6CollectCallableFlows(partitioned.callableFlow, positionIndex, filePath, callableFlowSites);
144
+ // ── Pass 7: preserve call-result assignment identity ───────────────
145
+ const callResultAssignmentSites = [];
146
+ pass7CollectCallResultAssignments(partitioned.callResultAssignment, positionIndex, filePath, callResultAssignmentSites);
140
147
  // Freeze Scope drafts into final shape and return.
141
148
  const frozenScopes = scopeDrafts.map(draftToScope);
142
149
  return Object.freeze({
@@ -149,6 +156,9 @@ export function extract(matches, filePath, provider) {
149
156
  ...(callableFlowSites.length > 0
150
157
  ? { callableFlowSites: Object.freeze(callableFlowSites.slice()) }
151
158
  : {}),
159
+ ...(callResultAssignmentSites.length > 0
160
+ ? { callResultAssignmentSites: Object.freeze(callResultAssignmentSites.slice()) }
161
+ : {}),
152
162
  });
153
163
  }
154
164
  /**
@@ -168,6 +178,7 @@ function partitionByTopic(matches) {
168
178
  const typeBinding = [];
169
179
  const reference = [];
170
180
  const callableFlow = [];
181
+ const callResultAssignment = [];
171
182
  for (const match of matches) {
172
183
  for (const topic of topicsOf(match)) {
173
184
  switch (topic) {
@@ -189,10 +200,21 @@ function partitionByTopic(matches) {
189
200
  case 'callable-flow':
190
201
  callableFlow.push(match);
191
202
  break;
203
+ case 'call-result-assignment':
204
+ callResultAssignment.push(match);
205
+ break;
192
206
  }
193
207
  }
194
208
  }
195
- return { scope, declaration, import_, typeBinding, reference, callableFlow };
209
+ return {
210
+ scope,
211
+ declaration,
212
+ import_,
213
+ typeBinding,
214
+ reference,
215
+ callableFlow,
216
+ callResultAssignment,
217
+ };
196
218
  }
197
219
  function topicsOf(match) {
198
220
  const topics = new Set();
@@ -209,6 +231,8 @@ function topicsOf(match) {
209
231
  topics.add('reference');
210
232
  else if (name.startsWith('@callable-flow.'))
211
233
  topics.add('callable-flow');
234
+ else if (name.startsWith('@call-result-assignment.'))
235
+ topics.add('call-result-assignment');
212
236
  }
213
237
  return topics;
214
238
  }
@@ -396,19 +420,28 @@ function pass2AttachDeclarations(matches, drafts, positionIndex, localDefs, file
396
420
  // fact is the failure mode this subsystem rejects everywhere else.
397
421
  //
398
422
  // Copying the field onto BOTH twins makes the outcome identical whichever
399
- // one wins. Deliberately narrow — only `typeParameters`, the one field with
400
- // an asymmetric twin today. Widening this to "merge all metadata" would
401
- // change what every existing duplicate resolves to, which is a different
402
- // change with a different blast radius and no evidence behind it yet.
423
+ // one wins. Deliberately narrow — only metadata whose asymmetric twins have
424
+ // executable regressions (`typeParameters` and `returnType`). Widening this
425
+ // to "merge all metadata" would change what every existing duplicate
426
+ // resolves to, which is a different change with a different blast radius
427
+ // and no evidence behind it yet.
403
428
  const first = firstDefByNodeId.get(def.nodeId);
404
429
  if (first === undefined) {
405
430
  firstDefByNodeId.set(def.nodeId, def);
406
431
  }
407
- else if (first.typeParameters === undefined && def.typeParameters !== undefined) {
408
- first.typeParameters = def.typeParameters;
409
- }
410
- else if (def.typeParameters === undefined && first.typeParameters !== undefined) {
411
- def.typeParameters = first.typeParameters;
432
+ else {
433
+ if (first.typeParameters === undefined && def.typeParameters !== undefined) {
434
+ first.typeParameters = def.typeParameters;
435
+ }
436
+ else if (def.typeParameters === undefined && first.typeParameters !== undefined) {
437
+ def.typeParameters = first.typeParameters;
438
+ }
439
+ if (first.returnType === undefined && def.returnType !== undefined) {
440
+ first.returnType = def.returnType;
441
+ }
442
+ else if (def.returnType === undefined && first.returnType !== undefined) {
443
+ def.returnType = first.returnType;
444
+ }
412
445
  }
413
446
  // Find the innermost scope that contains the declaration's anchor range.
414
447
  const innermostId = positionIndex.atPosition(filePath, anchor.range.startLine, anchor.range.startCol);
@@ -1343,6 +1376,19 @@ function pass6CollectCallableFlows(matches, positionIndex, filePath, out) {
1343
1376
  }
1344
1377
  }
1345
1378
  }
1379
+ // ─── Pass 7: collect call-result assignment identity ──────────────────────
1380
+ function pass7CollectCallResultAssignments(matches, positionIndex, filePath, out) {
1381
+ for (const match of matches) {
1382
+ const call = match['@call-result-assignment.call'];
1383
+ const lhs = match['@call-result-assignment.lhs'];
1384
+ if (call === undefined || lhs === undefined || !nonEmpty(lhs.text))
1385
+ continue;
1386
+ const inScope = positionIndex.atPosition(filePath, call.range.startLine, call.range.startCol);
1387
+ if (inScope === undefined)
1388
+ continue;
1389
+ out.push({ callSite: call.range, inScope, lhs: lhs.text });
1390
+ }
1391
+ }
1346
1392
  function callableFlowKind(match) {
1347
1393
  return CALLABLE_FLOW_KINDS.find((kind) => match[`@callable-flow.${kind}`] !== undefined);
1348
1394
  }
@@ -612,6 +612,7 @@ export interface ScopeResolver {
612
612
  */
613
613
  readonly populateWorkspaceOwners?: (parsedFiles: readonly ParsedFile[], ctx: {
614
614
  readonly fileContents: ReadonlyMap<string, string>;
615
+ readonly resolutionConfig?: unknown;
615
616
  }) => void;
616
617
  /**
617
618
  * Optional workspace-wide enrichment of extracted reference sites. Runs
@@ -862,6 +863,10 @@ export interface ScopeResolver {
862
863
  * regression).
863
864
  */
864
865
  readonly freeCallsRequireInstanceOwnership?: boolean;
866
+ /** Whether an unqualified call inside a type may dispatch to an inherited
867
+ * instance method. Languages such as Swift allow implicit-self lookup,
868
+ * while Python/JavaScript/PHP require an explicit receiver. */
869
+ readonly implicitThisWalksMro?: boolean;
865
870
  /**
866
871
  * When true, a constructor-form call `Type(...)` links to the Class def
867
872
  * itself rather than its explicit Constructor def. Default
@@ -82,6 +82,7 @@ export declare function emitFreeCallFallback(graph: KnowledgeGraph, scopes: Scop
82
82
  * contains the method's owner. See
83
83
  * `ScopeResolver.freeCallsRequireInstanceOwnership`. */
84
84
  readonly freeCallsRequireInstanceOwnership?: boolean;
85
+ readonly implicitThisWalksMro?: boolean;
85
86
  readonly recordResolutionOutcome?: ResolutionOutcomeRecorder;
86
87
  /** Call sites owned by a later precise pass (for example callable-value-flow). */
87
88
  readonly skipSites?: ReadonlySet<string>;
@@ -164,11 +165,14 @@ export declare function pickUniqueGlobalClass(name: string, index: ReadonlyMap<s
164
165
  * pick a method member by name with overload narrowing on arity +
165
166
  * argument types. Returns undefined if there's no enclosing class,
166
167
  * no matching method, OR narrowing leaves multiple compatible
167
- * candidates — in the multi-candidate case, picking
168
- * `candidates[0]` would emit a high-confidence CALLS edge whose
169
- * target depends on registration order rather than a defensible
170
- * resolution. Mirrors `pickUniqueGlobalCallable`'s uniqueness check
171
- * in the same file (Codex PR #1497 review, finding 2).
168
+ * candidates — except when those survivors are a protocol/interface
169
+ * requirement plus exactly one extension witness, in which case the
170
+ * witness (the default body) is returned. An inherited class, struct,
171
+ * or enum member still wins over a protocol-extension default.
172
+ * Picking `candidates[0]` would emit a high-confidence CALLS edge
173
+ * whose target depends on registration order rather than a
174
+ * defensible resolution. Mirrors `pickUniqueGlobalCallable`'s
175
+ * uniqueness check in the same file (Codex PR #1497 review, finding 2).
172
176
  *
173
177
  * Exported for unit testing — language-agnostic logic, exercised
174
178
  * via synthetic stubs in `pick-implicit-this-overload.test.ts`. The
@@ -183,4 +187,5 @@ export declare function pickImplicitThisOverload(site: {
183
187
  readonly conversionRankFn?: ConversionRankFn;
184
188
  readonly conversionOnlyArgTypePrefixes?: readonly string[];
185
189
  readonly constraintCompatibility?: ScopeResolver['constraintCompatibility'];
190
+ readonly implicitThisWalksMro?: boolean;
186
191
  }): SymbolDefinition | undefined;
@@ -171,6 +171,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
171
171
  conversionRankFn: options.conversionRankFn,
172
172
  conversionOnlyArgTypePrefixes: options.conversionOnlyArgTypePrefixes,
173
173
  constraintCompatibility: options.constraintCompatibility,
174
+ implicitThisWalksMro: options.implicitThisWalksMro,
174
175
  });
175
176
  fnDefFromImplicitThis = fnDef !== undefined;
176
177
  }
@@ -925,11 +926,14 @@ export function pickUniqueGlobalClass(name, index) {
925
926
  * pick a method member by name with overload narrowing on arity +
926
927
  * argument types. Returns undefined if there's no enclosing class,
927
928
  * no matching method, OR narrowing leaves multiple compatible
928
- * candidates — in the multi-candidate case, picking
929
- * `candidates[0]` would emit a high-confidence CALLS edge whose
930
- * target depends on registration order rather than a defensible
931
- * resolution. Mirrors `pickUniqueGlobalCallable`'s uniqueness check
932
- * in the same file (Codex PR #1497 review, finding 2).
929
+ * candidates — except when those survivors are a protocol/interface
930
+ * requirement plus exactly one extension witness, in which case the
931
+ * witness (the default body) is returned. An inherited class, struct,
932
+ * or enum member still wins over a protocol-extension default.
933
+ * Picking `candidates[0]` would emit a high-confidence CALLS edge
934
+ * whose target depends on registration order rather than a
935
+ * defensible resolution. Mirrors `pickUniqueGlobalCallable`'s
936
+ * uniqueness check in the same file (Codex PR #1497 review, finding 2).
933
937
  *
934
938
  * Exported for unit testing — language-agnostic logic, exercised
935
939
  * via synthetic stubs in `pick-implicit-this-overload.test.ts`. The
@@ -954,24 +958,93 @@ export function pickImplicitThisOverload(site, scopes, workspaceIndex, model, ho
954
958
  const classDefId = workspaceIndex.classScopeIdToDefId.get(classScopeId);
955
959
  if (classDefId === undefined)
956
960
  return undefined;
957
- const overloads = model.methods.lookupAllByOwner(classDefId, site.name);
961
+ // Bare calls in an instance method use the same implicit receiver as
962
+ // `self.member()`. Prefer declarations on the enclosing type; when the
963
+ // language opts into MRO implicit-this, walk inherited owners
964
+ // nearest-first and arity-narrow per owner. Compatible-but-ambiguous
965
+ // on a nearer ancestor fail-closes — do not fall through to a farther
966
+ // override. Falling through to the global name lookup makes inherited
967
+ // defaults depend on file order.
968
+ const own = model.methods.lookupAllByOwner(classDefId, site.name);
969
+ const ownPicked = pickUniqueImplicitThisCandidate(own, site, hookCtx, workspaceIndex);
970
+ if (ownPicked !== undefined)
971
+ return ownPicked;
972
+ if (own.length > 0) {
973
+ const ownCompatible = narrowOverloadCandidates(own, site.arity, site.argumentTypes, {
974
+ argumentTypeClasses: site.argumentTypeClasses,
975
+ conversionRankFn: hookCtx?.conversionRankFn,
976
+ conversionOnlyArgTypePrefixes: hookCtx?.conversionOnlyArgTypePrefixes,
977
+ constraintCompatibility: hookCtx?.constraintCompatibility,
978
+ });
979
+ if (ownCompatible.length > 0)
980
+ return undefined;
981
+ }
982
+ if (hookCtx?.implicitThisWalksMro !== true)
983
+ return undefined;
984
+ for (const ownerId of scopes.methodDispatch?.mroFor(classDefId) ?? []) {
985
+ const inherited = model.methods.lookupAllByOwner(ownerId, site.name);
986
+ const inheritedPicked = pickUniqueImplicitThisCandidate(inherited, site, hookCtx, workspaceIndex);
987
+ if (inheritedPicked !== undefined)
988
+ return inheritedPicked;
989
+ if (inherited.length > 0) {
990
+ const inheritedCompatible = narrowOverloadCandidates(inherited, site.arity, site.argumentTypes, {
991
+ argumentTypeClasses: site.argumentTypeClasses,
992
+ conversionRankFn: hookCtx?.conversionRankFn,
993
+ conversionOnlyArgTypePrefixes: hookCtx?.conversionOnlyArgTypePrefixes,
994
+ constraintCompatibility: hookCtx?.constraintCompatibility,
995
+ });
996
+ if (inheritedCompatible.length > 0)
997
+ return undefined;
998
+ }
999
+ }
1000
+ return undefined;
1001
+ }
1002
+ function pickUniqueImplicitThisCandidate(overloads, site, hookCtx, workspaceIndex) {
958
1003
  if (overloads.length === 0)
959
1004
  return undefined;
960
- if (overloads.length === 1)
961
- return overloads[0];
962
- // Narrow on arity + argument types. Require a UNIQUE survivor —
963
- // ambiguous narrowing (multiple compatible candidates with no
964
- // disambiguating signal) leaves the call unresolved rather than
965
- // routing to an arbitrary first overload by registration order.
966
1005
  const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes, {
967
1006
  argumentTypeClasses: site.argumentTypeClasses,
968
1007
  conversionRankFn: hookCtx?.conversionRankFn,
969
1008
  conversionOnlyArgTypePrefixes: hookCtx?.conversionOnlyArgTypePrefixes,
970
1009
  constraintCompatibility: hookCtx?.constraintCompatibility,
971
1010
  });
972
- if (candidates.length !== 1)
1011
+ if (candidates.length === 0)
973
1012
  return undefined;
974
- return candidates[0];
1013
+ if (candidates.length === 1)
1014
+ return candidates[0];
1015
+ const witnesses = preferExtensionWitnesses(candidates, workspaceIndex);
1016
+ return witnesses.length === 1 ? witnesses[0] : undefined;
1017
+ }
1018
+ function preferExtensionWitnesses(candidates, workspaceIndex) {
1019
+ const onOwnerType = [];
1020
+ const extensionWitnesses = [];
1021
+ for (const def of candidates) {
1022
+ const ownerId = def.ownerId;
1023
+ if (ownerId === undefined) {
1024
+ extensionWitnesses.push(def);
1025
+ continue;
1026
+ }
1027
+ const ownerScope = workspaceIndex.classScopeByDefId?.get(ownerId);
1028
+ const livesOnOwner = ownerScope?.ownedDefs.some((owned) => owned.nodeId === def.nodeId) === true;
1029
+ if (livesOnOwner)
1030
+ onOwnerType.push(def);
1031
+ else
1032
+ extensionWitnesses.push(def);
1033
+ }
1034
+ if (extensionWitnesses.length === 0 || onOwnerType.length === 0)
1035
+ return candidates;
1036
+ const concrete = onOwnerType.filter((def) => !isProtocolLikeOwner(def.ownerId, workspaceIndex));
1037
+ if (concrete.length > 0)
1038
+ return concrete;
1039
+ return extensionWitnesses;
1040
+ }
1041
+ function isProtocolLikeOwner(ownerId, workspaceIndex) {
1042
+ if (ownerId === undefined)
1043
+ return false;
1044
+ const ownerScope = workspaceIndex.classScopeByDefId?.get(ownerId);
1045
+ if (ownerScope === undefined)
1046
+ return false;
1047
+ return ownerScope.ownedDefs.some((owned) => owned.nodeId === ownerId && (owned.type === 'Protocol' || owned.type === 'Interface'));
975
1048
  }
976
1049
  /**
977
1050
  * True when `name` is bound somewhere along the TRUE lexical scope
@@ -25,14 +25,25 @@
25
25
  import type { ParsedFile } from '../../../../_shared/index.js';
26
26
  import type { KnowledgeGraph } from '../../../graph/types.js';
27
27
  import type { MutableSemanticModel } from '../../model/semantic-model.js';
28
+ import { finalizeScopeModel } from '../../finalize-orchestrator.js';
28
29
  import { type ResolveStats } from '../../resolve-references.js';
29
30
  import { buildGraphNodeLookup } from '../graph-bridge/node-lookup.js';
30
31
  import { type FunctionNodeIndex } from '../../taint/summary-harvest-driver.js';
31
32
  import type { FunctionSummary } from '../../taint/summary-model.js';
32
33
  import type { CallSummary } from '../../taint/call-summary-model.js';
33
34
  import { type PropertyNameIndex } from '../passes/unique-name-properties.js';
35
+ import { type CalleeIdAccumulator } from '../graph-bridge/callee-id-sink.js';
34
36
  import type { ScopeResolver, UndecidedSatisfaction } from '../contract/scope-resolver.js';
37
+ import { buildWorkspaceResolutionIndex } from '../workspace-index.js';
35
38
  import type { ResolutionOutcome, ResolutionOutcomeRecorder } from '../resolution-outcome.js';
39
+ /**
40
+ * Join extraction-time assignment identity to Phase-4's exact resolved callee.
41
+ * Ambiguous dispatch and missing return annotations deliberately produce no
42
+ * binding. Extraction emits these facts only for untyped declarations, so an
43
+ * existing entry here is necessarily inference/mirroring and may be corrected;
44
+ * explicit annotations never enter this join.
45
+ */
46
+ export declare function applyPreciseCallResultBindings(parsedFiles: readonly ParsedFile[], indexes: ReturnType<typeof finalizeScopeModel>, workspaceIndex: ReturnType<typeof buildWorkspaceResolutionIndex>, calleeIds: CalleeIdAccumulator, nodeLookup: ReturnType<typeof buildGraphNodeLookup>): number;
36
47
  export type ScopeResolutionSubPhase = 'extracting' | 'analyzing types' | 'resolving references' | 'linking symbols';
37
48
  interface RunScopeResolutionInput {
38
49
  readonly graph: KnowledgeGraph;
@@ -47,7 +47,7 @@ import { emitReferencesViaLookup } from '../graph-bridge/references-to-edges.js'
47
47
  import { buildPropertyNameIndex, emitUniqueNamePropertyAccesses, } from '../passes/unique-name-properties.js';
48
48
  import { emitReturnShapeMemberAccesses } from '../passes/return-shape-members.js';
49
49
  import { emitImportedValueReferences } from '../passes/imported-value-refs.js';
50
- import { createCalleeIdAccumulator, } from '../graph-bridge/callee-id-sink.js';
50
+ import { calleeIdPosKey, createCalleeIdAccumulator, } from '../graph-bridge/callee-id-sink.js';
51
51
  import { emitImportEdges } from '../graph-bridge/imports-to-edges.js';
52
52
  import { callableFlowSiteKey, collectDeferredIndirectCollection, emitCallableValueFlow, } from '../passes/callable-value-flow.js';
53
53
  import { findEnclosingClassDef, resolveInheritanceBaseInScope } from '../scope/walkers.js';
@@ -55,6 +55,56 @@ import { heritageTypeArgumentsKey, } from '../utils/generic-instantiation.js';
55
55
  import { buildWorkspaceResolutionIndex } from '../workspace-index.js';
56
56
  import { logHeapProbe } from '../../utils/heap-probe.js';
57
57
  import { parseTruthyEnv } from '../../utils/env.js';
58
+ /**
59
+ * Join extraction-time assignment identity to Phase-4's exact resolved callee.
60
+ * Ambiguous dispatch and missing return annotations deliberately produce no
61
+ * binding. Extraction emits these facts only for untyped declarations, so an
62
+ * existing entry here is necessarily inference/mirroring and may be corrected;
63
+ * explicit annotations never enter this join.
64
+ */
65
+ export function applyPreciseCallResultBindings(parsedFiles, indexes, workspaceIndex, calleeIds, nodeLookup) {
66
+ let updated = 0;
67
+ const returnTypeByGraphId = new Map();
68
+ for (const parsed of parsedFiles) {
69
+ for (const def of parsed.localDefs) {
70
+ const returnType = workspaceIndex.declaredReturnTypeByCallableId.get(def.nodeId);
71
+ if (returnType === undefined)
72
+ continue;
73
+ const graphId = resolveDefGraphId(def.filePath, def, nodeLookup);
74
+ if (graphId !== undefined)
75
+ returnTypeByGraphId.set(graphId, returnType);
76
+ }
77
+ }
78
+ for (const parsed of parsedFiles) {
79
+ const resolvedByPosition = calleeIds.get(parsed.filePath);
80
+ if (resolvedByPosition === undefined)
81
+ continue;
82
+ for (const assignment of parsed.callResultAssignmentSites ?? []) {
83
+ const targets = resolvedByPosition.get(calleeIdPosKey(assignment.callSite.startLine, assignment.callSite.startCol));
84
+ if (targets === undefined || targets.size !== 1)
85
+ continue;
86
+ const targetId = targets.values().next().value;
87
+ if (targetId === undefined)
88
+ continue;
89
+ const returnType = returnTypeByGraphId.get(targetId);
90
+ if (returnType === undefined)
91
+ continue;
92
+ const scope = indexes.scopeTree.getScope(assignment.inScope);
93
+ if (scope === undefined)
94
+ continue;
95
+ scope.typeBindings.set(assignment.lhs, {
96
+ rawName: returnType.rawName,
97
+ ...(returnType.declaredSpelling !== undefined
98
+ ? { declaredSpelling: returnType.declaredSpelling }
99
+ : {}),
100
+ declaredAtScope: assignment.inScope,
101
+ source: 'assignment-inferred',
102
+ });
103
+ updated++;
104
+ }
105
+ }
106
+ return updated;
107
+ }
58
108
  import { isValueDefinitionLabel } from '../../utils/ast-helpers.js';
59
109
  import { TransitionalScopeTree } from '../../../../storage/scope-index-store.js';
60
110
  import { forceGc } from '../../../../storage/parsedfile-store.js';
@@ -235,7 +285,6 @@ export function runScopeResolution(input, provider) {
235
285
  const undecidedSatisfaction = [];
236
286
  const recordResolutionOutcome = (outcome) => {
237
287
  resolutionOutcomes.push(outcome);
238
- input.recordResolutionOutcome?.(outcome);
239
288
  };
240
289
  const PROF = process.env.PROF_SCOPE_RESOLUTION === '1';
241
290
  const tStart = PROF ? process.hrtime.bigint() : 0n;
@@ -311,7 +360,10 @@ export function runScopeResolution(input, provider) {
311
360
  logger.warn(`[scope-resolution prof] pre-extracted hits: ${preExtractedHits}/${files.length}`);
312
361
  }
313
362
  logHeapProbe('sr-extract-end', `lang=${provider.language} parsedFiles=${parsedFiles.length} preExtractedHits=${preExtractedHits} skipped=${filesSkipped}`);
314
- provider.populateWorkspaceOwners?.(parsedFiles, { fileContents: getFileContents() });
363
+ provider.populateWorkspaceOwners?.(parsedFiles, {
364
+ fileContents: getFileContents(),
365
+ resolutionConfig: input.resolutionConfig,
366
+ });
315
367
  provider.populateWorkspaceReferences?.(parsedFiles, {
316
368
  fileContents: getFileContents(),
317
369
  treeCache,
@@ -481,7 +533,9 @@ export function runScopeResolution(input, provider) {
481
533
  // views that delegate to it (out-of-core scope index) — the index pins no Scope objects, so the
482
534
  // disk seal can reclaim them. Byte-identical: the view returns the same Scope
483
535
  // the resident tree holds (or a value-identical revived one in disk mode).
484
- const workspaceIndex = buildWorkspaceResolutionIndex(parsedFiles, indexes.scopeTree);
536
+ const workspaceIndex = buildWorkspaceResolutionIndex(parsedFiles, indexes.scopeTree, {
537
+ stripTypePreservingDecoration: provider.stripTypePreservingDecoration,
538
+ });
485
539
  logHeapProbe('sr-post-workspaceIndex', `lang=${provider.language}`);
486
540
  // Cross-file implicit-namespace visibility (C#). Must run before
487
541
  // propagateImportedReturnTypes so the latter pass sees siblings'
@@ -637,6 +691,12 @@ export function runScopeResolution(input, provider) {
637
691
  const deferredIndirectCollection = collectDeferredIndirectCollection(emitParsedFiles, indexes);
638
692
  const deferredIndirectSites = deferredIndirectCollection.sites;
639
693
  const callableArgumentSites = new Set();
694
+ const callResultAssignmentSites = new Set();
695
+ for (const parsed of emitParsedFiles) {
696
+ for (const site of parsed.callResultAssignmentSites ?? []) {
697
+ callResultAssignmentSites.add(callableFlowSiteKey(parsed.filePath, site.callSite));
698
+ }
699
+ }
640
700
  if (input.pdg !== true && deferredIndirectSites.size > 0) {
641
701
  for (const parsed of emitParsedFiles) {
642
702
  for (const site of parsed.callableFlowSites ?? []) {
@@ -650,10 +710,13 @@ export function runScopeResolution(input, provider) {
650
710
  // for PDG OR when indirect-call facts need direct targets for actual→formal
651
711
  // propagation. Populated below at every CALLS emit path before dedup; the CFG
652
712
  // join still consumes it only inside the `input.pdg` block.
653
- const calleeIdAccumulator = input.pdg === true || deferredIndirectSites.size > 0
713
+ const calleeIdAccumulator = input.pdg === true || deferredIndirectSites.size > 0 || callResultAssignmentSites.size > 0
654
714
  ? createCalleeIdAccumulator(input.pdg === true
655
715
  ? undefined
656
- : (filePath, line, col) => callableArgumentSites.has(`${filePath}:${line}:${col}`))
716
+ : (filePath, line, col) => {
717
+ const key = `${filePath}:${line}:${col}`;
718
+ return callableArgumentSites.has(key) || callResultAssignmentSites.has(key);
719
+ })
657
720
  : undefined;
658
721
  const receiverBound = callableFlowOnly
659
722
  ? {
@@ -673,7 +736,7 @@ export function runScopeResolution(input, provider) {
673
736
  // (#2912). Empty under `callableFlowOnly`, which emits no dispatch.
674
737
  heritageTypeArguments,
675
738
  });
676
- const receiverExtras = receiverBound.emitted;
739
+ let receiverExtras = receiverBound.emitted;
677
740
  if (receiverBound.dispatchFanoutSkipped > 0) {
678
741
  // Never drop dispatch coverage silently (#2829) — same contract as the
679
742
  // property-dispatch cap below. An interface member over the cap loses real
@@ -704,6 +767,7 @@ export function runScopeResolution(input, provider) {
704
767
  isFileLocalDef: provider.isFileLocalDef,
705
768
  isBuiltInName: provider.languageProvider.isBuiltInName,
706
769
  freeCallsRequireInstanceOwnership: provider.freeCallsRequireInstanceOwnership === true,
770
+ implicitThisWalksMro: provider.implicitThisWalksMro === true,
707
771
  isCallableVisibleFromCaller: provider.isCallableVisibleFromCaller,
708
772
  resolveAdlCandidates: provider.resolveAdlCandidates,
709
773
  resolveQualifiedFreeCall: provider.resolveQualifiedFreeCall,
@@ -714,6 +778,42 @@ export function runScopeResolution(input, provider) {
714
778
  calleeIdSink: calleeIdAccumulator,
715
779
  skipSites: deferredIndirectSites,
716
780
  });
781
+ const replayedCallResultBindings = callableFlowOnly || calleeIdAccumulator === undefined
782
+ ? 0
783
+ : applyPreciseCallResultBindings(emitParsedFiles, indexes, workspaceIndex, calleeIdAccumulator, postHeritageNodeLookup);
784
+ if (replayedCallResultBindings > 0) {
785
+ const handledBeforeReplay = new Set(handledSites);
786
+ const replayedReceiverBound = emitReceiverBoundCalls(graph, indexes, emitParsedFiles, postHeritageNodeLookup, handledSites, provider, workspaceIndex, readonlyModel, {
787
+ calleeIdSink: calleeIdAccumulator,
788
+ isBuiltInName: provider.languageProvider.isBuiltInName,
789
+ heritageTypeArguments,
790
+ });
791
+ receiverExtras += replayedReceiverBound.emitted;
792
+ if (replayedReceiverBound.dispatchFanoutSkipped > 0) {
793
+ logger.warn({
794
+ lang: provider.language,
795
+ dispatchFanoutSkipped: replayedReceiverBound.dispatchFanoutSkipped,
796
+ dispatchFanoutSkippedNames: replayedReceiverBound.dispatchFanoutSkippedNames,
797
+ fanoutCap: MAX_INTERFACE_DISPATCH_FANOUT,
798
+ replay: true,
799
+ }, 'interface-dispatch: members over the fan-out cap dropped implementors (their CALLS edges were not emitted)');
800
+ }
801
+ const resolvedOnReplay = new Set();
802
+ for (const key of handledSites) {
803
+ if (!handledBeforeReplay.has(key))
804
+ resolvedOnReplay.add(key);
805
+ }
806
+ if (resolvedOnReplay.size > 0) {
807
+ for (let i = resolutionOutcomes.length - 1; i >= 0; i--) {
808
+ const outcome = resolutionOutcomes[i];
809
+ if (outcome.kind === 'suppressed' &&
810
+ outcome.reason === 'receiver-unresolved' &&
811
+ resolvedOnReplay.has(callableFlowSiteKey(outcome.filePath, outcome.range))) {
812
+ resolutionOutcomes.splice(i, 1);
813
+ }
814
+ }
815
+ }
816
+ }
717
817
  const referenceSkipSites = new Set(handledSites);
718
818
  for (const key of deferredIndirectSites)
719
819
  referenceSkipSites.add(key);
@@ -1176,6 +1276,8 @@ export function runScopeResolution(input, provider) {
1176
1276
  ` (${parsedFiles.length} files)`);
1177
1277
  }
1178
1278
  logHeapProbe('sr-end', `lang=${provider.language} parsedFiles=${parsedFiles.length}`);
1279
+ for (const outcome of resolutionOutcomes)
1280
+ input.recordResolutionOutcome?.(outcome);
1179
1281
  return {
1180
1282
  filesProcessed: parsedFiles.length,
1181
1283
  filesSkipped,
@@ -12,7 +12,7 @@
12
12
  * See `./workspace-index.ts` for what belongs in this index versus what belongs
13
13
  * on `SemanticModel`, and for the builder itself.
14
14
  */
15
- import type { Scope, ScopeId, SymbolDefinition } from '../../../_shared/index.js';
15
+ import type { Scope, ScopeId, SymbolDefinition, TypeRef } from '../../../_shared/index.js';
16
16
  export interface WorkspaceResolutionIndex {
17
17
  /** Class def `nodeId` → that class's `Scope`. */
18
18
  readonly classScopeByDefId: ReadonlyMap<string, Scope>;
@@ -31,4 +31,9 @@ export interface WorkspaceResolutionIndex {
31
31
  * killer). "First module-local callable in `moduleScopeByFile` order" is the
32
32
  * exact semantics the old scan returned, so it is byte-identical. */
33
33
  readonly exportedCallableByName: ReadonlyMap<string, SymbolDefinition>;
34
+ /** Exact callable def `nodeId` → its declared return type binding.
35
+ * Built from definitions owned by each callable's Function scope, so methods
36
+ * declared in extension/partial scopes remain addressable even when those
37
+ * scopes deliberately own no separate class-like definition. */
38
+ readonly declaredReturnTypeByCallableId: ReadonlyMap<string, TypeRef>;
34
39
  }
@@ -52,4 +52,6 @@ export type { WorkspaceResolutionIndex } from './workspace-index-types.js';
52
52
  * reclaim them. Without it (unit tests), the legacy direct `Map<K, Scope>` form
53
53
  * is returned unchanged.
54
54
  */
55
- export declare function buildWorkspaceResolutionIndex(parsedFiles: readonly ParsedFile[], scopeTree?: ScopeTree): WorkspaceResolutionIndex;
55
+ export declare function buildWorkspaceResolutionIndex(parsedFiles: readonly ParsedFile[], scopeTree?: ScopeTree, options?: {
56
+ readonly stripTypePreservingDecoration?: (typeName: string) => string | undefined;
57
+ }): WorkspaceResolutionIndex;
@@ -97,11 +97,12 @@ class ScopeByKeyView {
97
97
  * reclaim them. Without it (unit tests), the legacy direct `Map<K, Scope>` form
98
98
  * is returned unchanged.
99
99
  */
100
- export function buildWorkspaceResolutionIndex(parsedFiles, scopeTree) {
100
+ export function buildWorkspaceResolutionIndex(parsedFiles, scopeTree, options) {
101
101
  const classScopeIdByDefId = new Map();
102
102
  const classScopeIdToDefId = new Map();
103
103
  const moduleScopeIdByFile = new Map();
104
104
  const exportedCallableByName = new Map();
105
+ const declaredReturnTypeByCallableId = new Map();
105
106
  // Back-compat (no scopeTree): keep the direct Scope-object maps.
106
107
  const classScopeByDefIdDirect = scopeTree === undefined ? new Map() : undefined;
107
108
  const moduleScopeByFileDirect = scopeTree === undefined ? new Map() : undefined;
@@ -128,6 +129,24 @@ export function buildWorkspaceResolutionIndex(parsedFiles, scopeTree) {
128
129
  }
129
130
  }
130
131
  for (const scope of parsed.scopes) {
132
+ if (scope.kind === 'Function' && scope.parent !== null) {
133
+ for (const def of scope.ownedDefs) {
134
+ if (def.type !== 'Function' && def.type !== 'Method' && def.type !== 'Constructor') {
135
+ continue;
136
+ }
137
+ if (def.returnType !== undefined) {
138
+ const stripped = options?.stripTypePreservingDecoration?.(def.returnType);
139
+ const rawName = stripped ?? def.returnType;
140
+ declaredReturnTypeByCallableId.set(def.nodeId, {
141
+ rawName,
142
+ ...(rawName !== def.returnType ? { declaredSpelling: def.returnType } : {}),
143
+ declaredAtScope: scope.id,
144
+ source: 'return-annotation',
145
+ });
146
+ continue;
147
+ }
148
+ }
149
+ }
131
150
  if (scope.kind !== 'Class')
132
151
  continue;
133
152
  const cd = scope.ownedDefs.find((d) => isClassLike(d.type));
@@ -144,5 +163,11 @@ export function buildWorkspaceResolutionIndex(parsedFiles, scopeTree) {
144
163
  const moduleScopeByFile = scopeTree === undefined
145
164
  ? moduleScopeByFileDirect
146
165
  : new ScopeByKeyView(moduleScopeIdByFile, scopeTree);
147
- return { classScopeByDefId, classScopeIdToDefId, moduleScopeByFile, exportedCallableByName };
166
+ return {
167
+ classScopeByDefId,
168
+ classScopeIdToDefId,
169
+ moduleScopeByFile,
170
+ exportedCallableByName,
171
+ declaredReturnTypeByCallableId,
172
+ };
148
173
  }
@@ -764,7 +764,9 @@ import { copyV8CacheIfPresent, tryLoadV8Cache, writeV8CacheFile } from './v8-sid
764
764
  // v101 (#3294 review): Rust bare-keyword glob imports retain crate/self/super
765
765
  // instead of an empty target path; restricted pub(...) imports are no longer
766
766
  // captured as unrestricted reexports. Re-extract both facts on warm indexes.
767
- const SCHEMA_BUMP = 101;
767
+ // v102: ParsedFile gained callResultAssignmentSites; old durable shards do
768
+ // not carry the exact assignment identity required by return-type replay.
769
+ const SCHEMA_BUMP = 102;
768
770
  const GITNEXUS_PKG_VERSION = (() => {
769
771
  try {
770
772
  // package.json sits at gitnexus/package.json — two levels up from
@@ -301,21 +301,27 @@ export const loadParsedFilesForPaths = async (storagePath, wantPaths) => {
301
301
  rejectedFiles++;
302
302
  continue;
303
303
  }
304
+ const assignments = sanitizeCallResultAssignmentSites(pf.callResultAssignmentSites);
305
+ if (assignments === undefined) {
306
+ rejectedFiles++;
307
+ continue;
308
+ }
304
309
  const chains = sanitizeReceiverChains(pf.referenceSites);
305
310
  if (chains === undefined) {
306
311
  rejectedFiles++;
307
312
  continue;
308
313
  }
309
- if (flow.dropped === 0 && chains.dropped === 0) {
314
+ if (flow.dropped === 0 && assignments.dropped === 0 && chains.dropped === 0) {
310
315
  out.set(pf.filePath, pf);
311
316
  }
312
317
  else {
313
- droppedSites += flow.dropped;
318
+ droppedSites += flow.dropped + assignments.dropped;
314
319
  droppedChains += chains.dropped;
315
320
  filesWithDroppedSites++;
316
321
  out.set(pf.filePath, {
317
322
  ...pf,
318
323
  ...(flow.dropped === 0 ? {} : { callableFlowSites: flow.sites }),
324
+ ...(assignments.dropped === 0 ? {} : { callResultAssignmentSites: assignments.sites }),
319
325
  ...(chains.dropped === 0 ? {} : { referenceSites: chains.sites }),
320
326
  });
321
327
  }
@@ -342,6 +348,17 @@ function sanitizeCallableFlowSites(value) {
342
348
  const sites = bounded.filter(isValidCallableFlowSite);
343
349
  return { sites, dropped: value.length - sites.length };
344
350
  }
351
+ function sanitizeCallResultAssignmentSites(value) {
352
+ if (value === undefined)
353
+ return { sites: undefined, dropped: 0 };
354
+ if (!Array.isArray(value))
355
+ return undefined;
356
+ const bounded = value.length > MAX_CALLABLE_FLOW_SITES_PER_FILE
357
+ ? value.slice(0, MAX_CALLABLE_FLOW_SITES_PER_FILE)
358
+ : value;
359
+ const sites = bounded.filter(isValidCallResultAssignmentSite);
360
+ return { sites, dropped: value.length - sites.length };
361
+ }
345
362
  /**
346
363
  * Untrusted-boundary handling for the compact `receiverChain` on a reference site.
347
364
  *
@@ -434,6 +451,12 @@ function isValidCallableFlowSite(value) {
434
451
  return false;
435
452
  }
436
453
  }
454
+ function isValidCallResultAssignmentSite(value) {
455
+ return (isRecord(value) &&
456
+ isValidRange(value.callSite) &&
457
+ isBoundedString(value.inScope) &&
458
+ isBoundedString(value.lhs));
459
+ }
437
460
  function isValidOperand(value) {
438
461
  if (!isRecord(value))
439
462
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.13-rc.18",
3
+ "version": "1.6.13-rc.19",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",