Skip to content

typescript: construct, namespace, inline-chain, ThisType and bound-method callees resolve (#1997, #1998, #1999, #2000, #2001) - #2002

Merged
swapnilpaliwal-sd merged 2 commits into
0.2.3from
fix/ts-callee-shapes
Oct 29, 2026
Merged

swapnilpaliwal-sd merged 2 commits into
0.2.3from
fix/ts-callee-shapes

Conversation

@swapnilpaliwal-sd

@swapnilpaliwal-sd swapnilpaliwal-sd commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1997
Fixes #1998
Fixes #1999
Fixes #2000
Fixes #2001

What changed

Five callee shapes resolved to nothing though the compiler names their target. Each fix is the missing half of a lookup the engine already makes elsewhere.

Three new relations, declared in souffle/decls_all.dl: thistype_arg, thistype_carrier_kind, objlit_this_type, plus the helper callee_holds_class.

Why the goldens moved

  • 08-function-values-and-callbacks: const asValue: Transform = p.tag.bind(p); asValue("d") now also names Pipeline#tag, the method that runs, beside the Transform signature the compiler names, which still agrees. The envelope's separate value_call drive -> Pipeline.tag line goes, because the edge now carries it.
  • 80-method-passed-by-reference: this.handle.bind(this), this.onHover.bind(this) and this.later.call(this) go from ambiguous_unknown to the case's own Function#bind / Function#call. The case is not noLib, so the compiler's answer is the real library's CallableFunction member and the case oracle cannot record it: the three are extras exactly as the existing setTimeout extras are.
  • 83-closed-world-dispatch: new C() through a construct-signature alias was its one known-missing edge. It now resolves to the compiler's target, so the known-missing file is removed.

New cases, each with its controls:

case construct controls
91-construct-through-shape new C(), C an alias of a construct-signature literal, and the literal inline constructor type, interface with new
92-namespace-typed-const ns.score(x), const of a function type holding a factory's result named import, const holding an arrow, exported function
93-literal-member-chain o.meta.audit.log.write(), two and four levels of inline type one level, named types throughout
94-thistype-object-literal marker through a generic alias bound by an explicit type argument, through an annotation, inline no marker, arrow member in a class
95-bind-on-method-value this.render.bind/call/apply, v.render.call(v), the bound result called function-typed field, getter

Two known-missing edges, both kept on purpose and explained in their files: in 92 the const holding an arrow is answered with the arrow's body where the compiler names the annotation (unchanged from the bare-name read), and in 94 the no-marker control, this in an unmarked literal, is not typed before or after.

Evidence

Synthetic cases above. Measured with graph/test/typescript/corpus/run-corpus.sh --set all --baseline, node 22.23.2, same parser build on both sides:

set sites exact wrong missed
dev (immer, remeda, zustand) 1393 +10 0 -10
held-out (typeorm, nest, ts-pattern) 19514 +10 -1 -12

trpc and vue-core are NOT RUN on both sides (oracle refused on this machine's installs). Per site, no project has a site that got worse: every change is MISSED to EXACT or SOUND_SUPERSET, or WRONG to SOUND_SUPERSET.

Solve cost, full axiomcode index, CPU time (user + sys), both sides built the same way and run in ABBA order: ts-pattern 20.0 s and 18.3 s base, 20.3 s and 19.3 s fix (+3%); nest 180.4 s and 171.3 s base, 178.3 s and 165.0 s fix (-2%); typeorm 117.0 s and 118.0 s base, 122.2 s and 117.6 s fix (+2%). Within noise. Peak RSS and database size unchanged. An earlier +20% reading compared a parallel engine build against a serial one and is withdrawn.

What did not work first:

  • The namespace shape without its guard turned every namespace call to an annotated arrow const from an implementation answer into a two-way hedge with the annotation's bodiless signature. The !var_is_function guard is the fix for that.
  • The construct shape without its guard did the same to new Ctor() with const Ctor: new () => Dog = Dog (case 46).
  • Rule (6b) alone made the linking fixture's const write = sink.write.bind(sink); write() WRONG: the call reached only the bodiless function types inside bind's generic return. The bound-result clause puts the method in the set; the fixture is back to 0 wrong, recall 0.953 to 0.972.

Checklist

  • The TypeScript suite passes locally with --oracle (106 of 106) against the parser in this repository
  • Any golden that moved is explained above
  • Each fix validated on more than one shape, with controls in the same case
  • Labels set: typescript, engine, bug

@swapnilpaliwal-sd swapnilpaliwal-sd added bug Something isn't working typescript TypeScript engine Resolution / call-graph engine rules labels Oct 29, 2026
…thod callees resolve (#1997, #1998, #1999, #2000, #2001)

Five callee shapes resolved to nothing though the compiler names their
target:

- new C() where C is typed by a construct-signature literal or an alias
  of one: construction read expr_type only, the plain-call side already
  read expr_shape (#1997)
- ns.f() where f is an exported const of a function type whose value is
  not a function literal: the namespace read gave var_type, never
  var_shape (#1998)
- a.b.c.m() through nested inline object types: a shape-typed member
  read off a shape qualifier had no field_shape clause (#1999)
- this.m() in an object literal typed X & ThisType<T>: the marker is
  read through intersections and aliases, with the alias parameter and
  the call's explicit type argument substituted (#2000)
- this.m.bind/call/apply and the bound result's call: the Function
  members attach to a method read as a value (#2001)

Two guards keep sites that were right from hedging: the namespace shape
is not added where the const holds a function literal, and the
construct shape is not added where the callee variable holds a class.

Cases 91 to 95 pin each shape with its controls. Goldens moved in 08,
80 and 83 (see the pull request); 83's known-missing edge now resolves.
… keeps its own version)

0.2.2 is released; this PR ships in 0.2.3. package.json (version and the five @axiomcode/engine-* pins) and the four editor plugin and extension manifests move from 0.2.2 to 0.2.3. The parser is unchanged by this PR and stays at 0.2.1.
@swapnilpaliwal-sd
swapnilpaliwal-sd changed the base branch from dev to 0.2.3 October 29, 2026 16:42
@swapnilpaliwal-sd
swapnilpaliwal-sd merged commit f74b449 into 0.2.3 Oct 29, 2026
13 checks passed
@swapnilpaliwal-sd
swapnilpaliwal-sd deleted the fix/ts-callee-shapes branch October 29, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working engine Resolution / call-graph engine rules typescript TypeScript

Projects

None yet

1 participant