type-resolution-roadmap.md
This roadmap describes the evolution of GitNexus's type-resolution layer from a receiver-disambiguation aid into a production-grade static-analysis foundation.
The goal is not to build a compiler. The goal is to support high-value static analysis for call graphs, impact analysis, context gathering, and downstream graph features.
Shipped in feat/phase7-type-resolution.
ReturnTypeLookup interface threading return-type knowledge into TypeEnv@var property typing for $this->property foreach (Strategy C)pendingCallResults infrastructure (Tier 2b loop + PendingAssignment union) — activated by Phase 9Shipped in feat/phase8-field-property-type-resolution.
fieldByOwner index — O(1) field lookup by ownerNodeId\0fieldNameHAS_PROPERTY edge type + declaredType on Property symbolsuser.address.city.getName()) across 10 languagesMixedChainStep[] (svc.getUser().address.save())unwrap, clone, expect, etc.)ACCESSES edge type — read/write field access tracking across 12 languagesfield_declaration capture, field_expression receiver support@return for attr_accessorShipped in feat/phase9-call-result-binding (PR #379).
const user = getUser(); user.save() across 11 languagescallResult, copy, fieldAccess, methodCallResult) at arbitrary depthconst addr = user.address resolves via lookupFieldByOwner + declaredTypeconst city = addr.getCity() resolves via lookupFuzzyCallable filtered by ownerIdgetUser() → .address → .getCity() → city.save()const b = a; const a: User = x → both resolve)Shipped in feat/type-resolution-milestone-d (PR #387). Consolidated original Phases 10–13 into 3 balanced phases.
pendingForLoops collection + replay after fixpoint resolves iterable typesfieldAccess items (TS/JS object_pattern, Rust struct_pattern) — no new destructure PendingAssignment variant neededresolveFixpointBindings() helper with exhaustive switch + classDefCache memoizationBuildTypeEnvOptions interface replacing positional params for buildTypeEnvparentMap from tree-sitter query matches (not graph edges — heritage-processor runs in parallel)walkParentChain() (depth 5, cycle-safe BFS) for resolveFieldType and resolveMethodReturnTypethis/self/$this/Me receiver substitution via substituteThisReceiver hookinc_statement/dec_statement write-access queries!= null, !== undefined, is not null) via position-indexed patternOverridesPATTERN_BRANCH_TYPES → NARROWING_BRANCH_TYPESjvm.ts (AST node type equality_expression, anonymous null node, nullable_type parameter fallback)x is User feature — deferred17 fixture directories, 23 describe blocks, 705 lines of test code covering all 11 languages:
Plan: docs/plans/2026-03-19-feat-polymorphism-overloading-type-resolution-plan.md
Four incremental phases:
SymbolDefinition with parameterTypes: string[] extracted during parsing — DELIVEREDBase b = new Derived(); b.method() resolves to Derived#method when constructor type is a known subclass — DELIVERED (Java, C#, TS, C++, Kotlin via detectConstructorType hook, C++ smart pointers via make_shared/make_unique)requiredParameterCount range check — DELIVERED (TS, Python, Kotlin, C#, C++, PHP, Ruby)Languages benefiting: Java, Kotlin, C#, C++, TypeScript (overloading). All OOP languages (virtual dispatch).
Impact: High | Effort: High (P.1–P.4 delivered; P.5 covariant return types remains open)
Blocked on tree-sitter-swift Node 22 compatibility.
guard let narrowing (from Phase 13B) — uses scopeEnv path, not patternOverridesImpact: Medium | Effort: Medium
Shipped in feat/phase14-cross-file-binding-propagation.
Three enrichment mechanisms:
seedCrossFileReceiverTypes — pre-seeds receiverTypeName for single-hop imported receivers (zero re-parse)ExportedTypeMap seeded into importedBindings for re-resolution passbuildImportedReturnTypes — cross-file return types for imported callables (local-first, SymbolTable takes precedence)Architecture:
topologicalLevelSort, returns { levels, cycleCount })runCrossFileBindingPropagation() extracted as standalone pipeline phasesynthesizeWildcardImportBindings() expands whole-module imports (Go/Ruby/C/C++/Swift) into per-symbol namedImportMap entries from graph-exported symbols — runs before Phase 14buildExportedTypeMapFromGraph collects Tier 0 (annotated) exports onlycollectExportedBindings captures full fixpoint-inferred exportsPer-language Phase 14 coverage:
| Language | namedImportMap | ExportedTypeMap (E1/E2) | E3 (importedReturnTypes) | Benefit |
|---|---|---|---|---|
| TypeScript | Full (named imports) | File-scope vars | Full | High |
| JavaScript | Full (named imports) | File-scope vars | Full | High |
| Python | from-imports | File-scope vars | Full | High |
| Kotlin | Top-level fns | Top-level props | Full | High |
| Rust | use clauses | Limited | Full | High |
| Go | Synthesized¹ | Exported symbols | Full | Medium |
| Ruby | Synthesized¹ | Exported symbols | Full | Medium |
| C/C++ | Synthesized¹ | Exported symbols | Full | Medium |
| Swift | Synthesized¹ | Exported symbols | Full | Low (Phase S blocked) |
| PHP | use classes | Inert (class-scope) | Inert (no fn imports) | Marginal |
| Java | Classes + static methods | Inert (no file-scope) | Via SymbolTable | Medium |
| C# | Alias + using static | Inert (no file-scope) | Via SymbolTable | Medium |
¹ Whole-module import languages: namedImportMap entries synthesized from graph-exported symbols via synthesizeWildcardImportBindings() (capped at 1000 per file)
Named binding extraction details:
import static X.Y.method now captured (static modifier detection). Ambiguous static imports (same method from multiple classes) fall through to Tier 2a for arity narrowing.using static NS.Type; now captured (last segment as class binding). Non-alias using NS; remains unsupported (namespace import requires type inference).Resolved limitations (this PR):
isExported)lookupRawReturnType no cross-file fallbackimportedRawReturnTypes map stores raw declared types (e.g., User[]) for for-loop element extraction via extractElementTypeFromStringfield_identifier added to declaration pattern alongside identifier, plus pointer/reference return type variantsImpact: High | Effort: High — delivered
Milestone D (Phases A, B, C) ✅ ──┐
├──→ Phase 14 (cross-file) ✅
Phase P (polymorphism) ───────────┤
│
Phase S (Swift parity) ───────────┘
Phase P.1–P.4 are delivered. P.5 (covariant return types) remains open.
Phase P and Phase S are independent of each other and Phase 14.
Phase 14 is delivered. Remaining open: Phase P.5, Phase S.
guard let narrowing → Phase SDog() uses call_expression (no new keyword)detectConstructorType hookusing NS; (namespace import, requires type inference).Loop inference, ReturnTypeLookup, PHP Strategy C.
Field/property maps, deep chains, mixed chains, stdlib passthroughs.
Unified fixpoint loop, call-result binding, field access binding, method-call-result binding, arbitrary-depth chain propagation.
Consolidated Phases 10–13 into 3 balanced phases. Loop-fixpoint bridge, MRO-aware inheritance walking, this/self resolution, object/struct destructuring, null-check narrowing. Kotlin null-check bug fix. Full 11-language integration test coverage.
Export-type index, cross-file binding propagation. Full coverage for TS/JS/Python/Kotlin. Marginal for PHP. Inert for Java/C#/Go/Ruby/C/C++ (relies on Phase 9 SymbolTable).
Parameter type metadata, overload disambiguation, constructor-visible virtual dispatch (including Kotlin detectConstructorType and C++ smart pointer factories), optional parameter arity resolution, covariant return types (open).
For-loop binding, assignment chains, guard let narrowing. Blocked on tree-sitter-swift Node 22.
| # | Question | Status |
|---|---|---|
| 1 | Where should field-type metadata live? | ✅ Resolved: fieldByOwner index in SymbolTable |
| 2 | How should ambiguity be represented? | ✅ Resolved: keep undefined. Conservative approach proven through 9 phases. |
| 3 | How much receiver context for return types? | ✅ Resolved: Phase 9C resolveMethodReturnType filters by ownerId. |
| 4 | How much branch sensitivity? | ✅ Resolved: type predicates + null checks only. No control-flow graph. (Phase 13) |
| 5 | Field typing and chain typing — one phase or two? | ✅ Resolved: incremental delivery within phases (Phase 8/8A precedent). |
| 6 | Phase 9B vs Phase 10? | ✅ Resolved: Phase 10 supersedes 9B via post-fixpoint replay. |
For GitNexus, production-grade does not mean replacing a language compiler. The target:
That supports: better call graphs, more accurate impact analysis, stronger AI context assembly, more trustworthy graph traversal.
Complete: Phases 7, 8, 9, 9C, Milestone D (A, B, C) — explicit types, constructor inference, loop inference, field/property resolution, deep chains, mixed chains, stdlib passthroughs, comment-based types, unified fixpoint with 4 binding kinds, arbitrary-depth chain propagation, MRO-aware inheritance walking, this/self resolution, object/struct destructuring, null-check narrowing — across 11 languages with full integration test coverage.
Next: Phase 14 (cross-file binding propagation) — the architectural capstone. Phase S (Swift parity) is independent and unblocked once tree-sitter-swift Node 22 is resolved.