diff --git a/docs/design/chained-call-resolution.md b/docs/design/chained-call-resolution.md index 4cf38eb..8485a02 100644 --- a/docs/design/chained-call-resolution.md +++ b/docs/design/chained-call-resolution.md @@ -1,12 +1,11 @@ # Design + status: chained static-factory / fluent call resolution -**Status:** SHIPPED for **11 languages** (C++, C, PHP, Java, Kotlin, C#, Swift, Rust, -Go, Scala, Dart, Objective-C) + a conformance pass. **TypeScript and Luau were evaluated -and intentionally skipped** (both gradually typed → the mechanism is +0 / regresses on -real code). **Pascal/Delphi** is blocked on a larger prerequisite (its method-call -extraction is broadly incomplete). See "Full README classification" below. Tracking -issue: **#750** (which began as "the statically-typed README languages" but that -enumeration was incomplete — it missed ObjC / Pascal / Luau). +**Status:** SHIPPED for **13 languages** (C++, C, PHP, Java, Kotlin, C#, Swift, Rust, +Go, Scala, Dart, Objective-C, Pascal/Delphi) + a conformance pass. **TypeScript and Luau +were evaluated and intentionally skipped** (both gradually typed → the mechanism is +0 / +regresses on real code). See "Full README classification" below. Tracking issue: +**#750** (which began as "the statically-typed README languages" but that enumeration was +incomplete — it missed ObjC / Pascal / Luau). **Motivation:** a call whose **receiver is itself a call** — a factory / singleton / builder that returns an object — should produce a `calls` edge to the chained method: @@ -75,10 +74,11 @@ walking `context.getSupertypes(...)`. | **Scala** | #761 | `.` | gatling **+14 / −59** | Precision win (−59 = stdlib `Option`/`Iterator` `.map`/`.flatMap` the baseline mis-tied to gatling's `Validation::*`). Companion factories + case-class `apply`. | | **Dart** | #762 | `.` | localsend hand-written **+17 / −10** | Precision win **+ constructors made first-class** (factory/named ctors `Foo.create()`/`Foo._()` are now indexed; unnamed `Foo()` stays `instantiates`). `dartCtorInfo` validates a ctor against the enclosing class name — handles a tree-sitter misparse where `@override (A,B) m()` makes `m()` look like a ctor. | | **Objective-C** | #786 | message send | SDWebImage **+35 / −75** | Precision win. Chained message send `[[Foo create] doIt]` over `message_expression`. getReturnType skips nullability qualifiers (`nonnull instancetype`). A class-message factory returns the receiver class by convention, so `[[X alloc] init]` / singleton chains resolve on `X` (validated). The −75 are wrong `init` mis-matches retargeted to the right class. | +| **Pascal/Delphi** | #791 | `.` (`exprDot`) | PascalCoin **+19 / −18** | Precision win. `TFoo.GetInstance().DoIt()` over Pascal's `exprCall`/`exprDot`. getReturnType from the `typeref` (incl. interface returns `IFoo`). Re-encoding gated on the Delphi `TFoo`/`IFoo` type convention so capitalized *variable* chains stay bare. A constructor (no `: TBar`) or typecast `TFoo(x)` resolves on the class. 15 of the −18 are correct class→interface retargets (`GetInstance(): IAsn1OctetString`). | | **TypeScript** | — | `.` | typeorm +0/−6 · nest **+0/−164** | **Evaluated, NOT shipped** — gradual typing; see below. | | **Luau** | — | `:` / `.` | Fusion +0/−0 · matter +0/−0 | **Evaluated, NOT shipped** — gradually typed; additive-safe (missing-edge gap, no regression) but real Luau rarely annotates factory returns, so +0 on both benchmarks. Works for `Foo.create(): Bar` then `:doIt()` (synthetic). | -`EXTRACTION_VERSION` is now **15** (C++→…→Dart→Objective-C). Re-index with `codegraph index -f` +`EXTRACTION_VERSION` is now **16** (C++→…→Objective-C→Pascal). Re-index with `codegraph index -f` to pick up the newer extractor on an existing graph. ## Why TypeScript was skipped @@ -108,20 +108,21 @@ declarations). Against the README's full supported-language list: | Bucket | Languages | |---|---| -| **Covered** (12) | C++, C, PHP, Java, Kotlin, C#, Swift, Rust, Go, Scala, Dart, Objective-C | +| **Covered** (13) | C++, C, PHP, Java, Kotlin, C#, Swift, Rust, Go, Scala, Dart, Objective-C, Pascal/Delphi | | **Evaluated, skipped** (2) | **TypeScript** — gradual typing → inference-typed factories can't be recovered; net recall regression. **Luau** — gradually typed; additive-safe but +0 on Fusion AND matter (real Luau rarely annotates factory returns). Both: the mechanism needs reliably-declared return types, which gradually-typed code too often omits. | -| **Blocked by a prerequisite** (1) | **Pascal/Delphi** — statically typed (so the mechanism *would* pay off), but its method-call extraction from procedure bodies is broadly incomplete: paren-less calls (`TFoo.GetInstance.DoIt`) parse as a bare `exprDot` (not in `callTypes`), and even paren'd calls (`f.Regular()`) produce no edge (no receiver-type tracking for Pascal locals). Building Pascal's call graph is a substantial standalone extractor effort; the chained-call port is a small part of it. Separate follow-up. | +| **Known limitation (not blocking)** | **Pascal/Delphi** is shipped (#791), but only the **paren'd** chain `TFoo.GetInstance().DoIt()` is covered — the **paren-less** form `TFoo.GetInstance.DoIt` parses as a bare `exprDot` (not in `callTypes`) and isn't extracted as a call at all. Emitting paren-less method calls is a separate extractor follow-up (and a broader Pascal-coverage win independent of chains). | | **Out of scope — no declared return types** (6) | JavaScript, Ruby, Lua, Svelte, Vue, Liquid (Liquid has no methods/chains at all) | | **Partial / separate** (1) | Python — only optional `-> T` hints; tracked as #578, not part of this mechanism | So #750's original framing ("the 9 statically-typed README languages") was incomplete — -it missed three more typed languages. Resolved: **Objective-C** shipped (#786, same -wrong-edge gap, mechanism ports directly); **Luau** evaluated and skipped (gradual -typing → +0 on real repos, additive-safe); **Pascal** is gated on unrelated extractor -work (its call graph is broadly incomplete). +it missed three more typed languages, all now resolved: **Objective-C** shipped (#786, +same wrong-edge gap, mechanism ports directly); **Pascal/Delphi** shipped (#791, a clean +port for the paren'd chain — an initial "blocked" read was wrong, caused by probing only +the paren-less form); **Luau** evaluated and skipped (gradual typing → +0 on real repos, +additive-safe). The through-line: this mechanism fits languages with **reliably-declared return types** -(the 12 shipped). Gradually-typed languages (TypeScript, Luau) omit them too often for +(the 13 shipped). Gradually-typed languages (TypeScript, Luau) omit them too often for it to pay off, and dynamically-typed languages have none. ---