Repository navigation
typescript: construct, namespace, inline-chain, ThisType and bound-method callees resolve (#1997, #1998, #1999, #2000, #2001) - #2002
Merged
Conversation
swapnilpaliwal-sd
requested review from
JaredHLZhang,
Whua689 and
suyashpaliwal26
as code owners
October 29, 2026 08:54
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
callee-resolution.dl: aCONSTRUCTOR_CALLcallee is also looked up throughexpr_shapeandconstructor_in_scope, as rule (3) does for a plain call. Skipped where the callee variable holds a class (callee_holds_class), whose own constructor already answers.expr-type.dl: a property read off a namespace gets the exported variable'svar_shape, the half the named import already reads. Skipped where the const holds a function literal, which rule (8) answers with its body.expr-type.dl: a shape-typed member read off a shape qualifier gets itsfield_shape. Thefield_typeclause for the same qualifier existed; the shape clause did not, so the chain stopped after one level.thisunderThisType<T>.expr-type.dl:thistype_argfinds the marker in an object literal's contextual reference through intersections, parentheses and aliases, substituting the alias's parameter with the reference's argument. The argument is then a written type, or the callee's type variable bound bycall_tvar_arg_binding(an explicit type argument).thisin the literal's methods and function-expression members takes that type; arrow members keep the enclosingthis.call/apply/bindon a method value.callee-resolution.dlrule (6b): the Function members attach to an access that names a method, found exactly as rules (4) and (6) find it; getters and setters are excluded. A variable initialised withrecv.m.bind(...)callsm.Three new relations, declared in
souffle/decls_all.dl:thistype_arg,thistype_carrier_kind,objlit_this_type, plus the helpercallee_holds_class.Why the goldens moved
const asValue: Transform = p.tag.bind(p); asValue("d")now also namesPipeline#tag, the method that runs, beside theTransformsignature the compiler names, which still agrees. The envelope's separatevalue_call drive -> Pipeline.tagline goes, because the edge now carries it.this.handle.bind(this),this.onHover.bind(this)andthis.later.call(this)go fromambiguous_unknownto the case's ownFunction#bind/Function#call. The case is notnoLib, so the compiler's answer is the real library'sCallableFunctionmember and the case oracle cannot record it: the three are extras exactly as the existingsetTimeoutextras are.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:
new C(), C an alias of a construct-signature literal, and the literal inlinenewns.score(x), const of a function type holding a factory's resulto.meta.audit.log.write(), two and four levels of inline typethis.render.bind/call/apply,v.render.call(v), the bound result calledTwo 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,
thisin 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: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:
!var_is_functionguard is the fix for that.new Ctor()withconst Ctor: new () => Dog = Dog(case 46).const write = sink.write.bind(sink); write()WRONG: the call reached only the bodiless function types insidebind'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
--oracle(106 of 106) against the parser in this repositorytypescript,engine,bug