This roadmap describes the evolution of GitNexus's type-resolution layer from a receiver-disambiguation aid into a production-grade static-analysis foundation.
- stay conservative — prefer missing a binding over introducing a misleading one
- prefer explainable inference over clever but brittle inference
- limit performance overhead during ingestion
- keep per-language extractors explicit rather than over-generic
- separate "better receiver resolution" from "compiler-grade typing"
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.
ReturnTypeLookupinterface threading return-type knowledge into TypeEnv- Iterable call-expression support across 7 languages (Go, TS, Python, Rust, Java, Kotlin, C#)
- PHP class-level
@varproperty typing for$this->propertyforeach (Strategy C) pendingCallResultsinfrastructure (Tier 2b loop +PendingAssignmentunion) — activated by Phase 9
Shipped in feat/phase8-field-property-type-resolution.
- SymbolTable
fieldByOwnerindex — O(1) field lookup byownerNodeId\0fieldName HAS_PROPERTYedge type +declaredTypeon Property symbols- Deep chain resolution up to 3 levels (
user.address.city.getName()) across 10 languages - Mixed field+method chains via unified
MixedChainStep[](svc.getUser().address.save()) - Type-preserving stdlib passthroughs (
unwrap,clone,expect, etc.) ACCESSESedge type — read/write field access tracking across 12 languages- C++
field_declarationcapture,field_expressionreceiver support - Rust unit struct instantiation, Ruby YARD
@returnforattr_accessor
Shipped in feat/phase9-call-result-binding (PR #379).
- Simple call-result binding:
const user = getUser(); user.save()across 11 languages - Unified fixpoint loop replacing sequential Tier 2b/2a — handles 4 binding kinds (
callResult,copy,fieldAccess,methodCallResult) at arbitrary depth - Field access binding:
const addr = user.addressresolves vialookupFieldByOwner+declaredType - Method-call-result binding:
const city = addr.getCity()resolves vialookupFuzzyCallablefiltered byownerId - Fixpoint iterates until stable (max 10 iterations), enabling chains like
getUser() → .address → .getCity() → city.save() - Reverse-order copy chains now resolve (
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.
- Post-fixpoint for-loop replay (ex-9B):
pendingForLoopscollection + replay after fixpoint resolves iterable types - Object destructuring via
fieldAccessitems (TS/JSobject_pattern, Ruststruct_pattern) — no newdestructurePendingAssignment variant needed - Extracted
resolveFixpointBindings()helper with exhaustive switch +classDefCachememoization
BuildTypeEnvOptionsinterface replacing positional params forbuildTypeEnv- Heritage pre-pass constructing
parentMapfrom tree-sitter query matches (not graph edges — heritage-processor runs in parallel) - MRO-aware
walkParentChain()(depth 5, cycle-safe BFS) forresolveFieldTypeandresolveMethodReturnType this/self/$this/Mereceiver substitution viasubstituteThisReceiverhook- Go
inc_statement/dec_statementwrite-access queries
- Null-check narrowing (
!= null,!== undefined,is not null) via position-indexedpatternOverrides - Supported for TS, Kotlin, C# — renamed
PATTERN_BRANCH_TYPES→NARROWING_BRANCH_TYPES - Bug fix: Kotlin narrowing required 3 fixes in
jvm.ts(AST node typeequality_expression, anonymousnullnode,nullable_typeparameter fallback)
- Type predicates (13A): Cross-function analysis for niche TS
x is Userfeature — deferred - Swift parity (11D): tree-sitter-swift Node 22 issues — all Swift work consolidated to Phase S
- Positional destructuring (12C): Python/Kotlin/C#/C++ tuple-position-to-field mapping — deferred
- Discriminated union narrowing (13C): Needs tagged union metadata not in SymbolTable — deferred
17 fixture directories, 23 describe blocks, 705 lines of test code covering all 11 languages:
- Grandparent MRO (depth-2 C→B→A): TS, JS, Kotlin, C#, C++, Java, PHP, Python, Ruby
- Object destructuring: TS, JS
- Struct destructuring: Rust
- Post-fixpoint for-loop replay: TS, JS
- Go inc/dec write access
- Null-check narrowing: TS, C#, Kotlin
Plan: docs/plans/2026-03-19-feat-polymorphism-overloading-type-resolution-plan.md
Four incremental phases:
- Parameter type metadata — extend
SymbolDefinitionwithparameterTypes: string[]extracted during parsing — DELIVERED - Overload disambiguation — filter overloaded methods by argument literal types at call sites — DELIVERED (Java, Kotlin, C#, C++, TypeScript)
- Constructor-visible virtual dispatch —
Base b = new Derived(); b.method()resolves toDerived#methodwhen constructor type is a known subclass — DELIVERED (Java, C#, TS, C++, Kotlin viadetectConstructorTypehook, C++ smart pointers viamake_shared/make_unique) - Optional parameter arity resolution — calls with omitted optional/default args now resolve via
requiredParameterCountrange check — DELIVERED (TS, Python, Kotlin, C#, C++, PHP, Ruby) - Covariant return type awareness — prefer child's return type over inherited definition
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.
- For-loop element binding (from Phase 10)
- Assignment chains: copy, callResult, fieldAccess, methodCallResult (from Phase 11D)
guard letnarrowing (from Phase 13B) — uses scopeEnv path, notpatternOverrides
Impact: Medium | Effort: Medium
Shipped in feat/phase14-cross-file-binding-propagation.
Three enrichment mechanisms:
- E1:
seedCrossFileReceiverTypes— pre-seedsreceiverTypeNamefor single-hop imported receivers (zero re-parse) - E2:
ExportedTypeMapseeded intoimportedBindingsfor re-resolution pass - E3:
buildImportedReturnTypes— cross-file return types for imported callables (local-first, SymbolTable takes precedence)
Architecture:
- Topological import ordering via Kahn's BFS (
topologicalLevelSort, returns{ levels, cycleCount }) - Cycle-safe: files in cycles grouped in final level, no cross-cycle propagation
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 14- Worker path:
buildExportedTypeMapFromGraphcollects Tier 0 (annotated) exports only - Sequential path:
collectExportedBindingscaptures full fixpoint-inferred exports
Per-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:
- Java:
import static X.Y.methodnow captured (static modifier detection). Ambiguous static imports (same method from multiple classes) fall through to Tier 2a for arity narrowing. - C#:
using static NS.Type;now captured (last segment as class binding). Non-aliasusing NS;remains unsupported (namespace import requires type inference).
Resolved limitations (this PR):
Worker path vs sequential path quality split— workers now return file-scope TypeEnv bindings; main thread merges fixpoint-inferred exports into ExportedTypeMap (filtered by graphisExported)— separatelookupRawReturnTypeno cross-file fallbackimportedRawReturnTypesmap stores raw declared types (e.g.,User[]) for for-loop element extraction viaextractElementTypeFromStringC++ header method declarations— tree-sitter query fix:field_identifieradded to declaration pattern alongsideidentifier, plus pointer/reference return type variants
Impact: 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.
- For-loop element binding → Phase S
- Assignment chains (copy, callResult, fieldAccess, methodCallResult) → Phase S
guard letnarrowing → Phase S
Virtual dispatch:— RESOLVED viaDog()usescall_expression(nonewkeyword)detectConstructorTypehook
Cross-file binding propagation → Phase 14— DELIVERED for all 13 languages via two mechanisms: (1) named import extraction (TS/JS/Python/Kotlin/Rust/PHP/Java/C#), (2) wildcard import synthesis from graph-exported symbols (Go/Ruby/C/C++/Swift). Remaining gap: C# non-aliasusing 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:
- Strong receiver-constrained call resolution across common language idioms
- Reliable handling of typed loops, constructors, and common patterns
- Return-type propagation for service/repository code
- Field/property knowledge for chained-member analysis
- Inheritance-aware lookups
- Conservative behavior under ambiguity
- Predictable performance during indexing
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.