Parent: #459 Related: #889, #891
Problem
JavaScriptCore ends most of its runtime TypeErrors with the source text of the expression being evaluated. zig-js matches the leading clause on these families but stops there:
| source | zig-js | JavaScriptCore |
|---|---|---|
var o = {}; o.m.n() | undefined is not an object | undefined is not an object (evaluating 'o.m.n') |
var g = 1; new g() | 1 is not a constructor | 1 is not a constructor (evaluating 'new g()') |
var g = {}; new g.m() | undefined is not a constructor | undefined is not a constructor (evaluating 'new g.m()') |
A 41-case JSC differential over call and construction shapes matches 39/41; the
two misses are exactly the new form above. On the is not an object family
every leading clause already matches, so the suffix is all that is left.
Why it is now tractable
The blocker was recorded as "ast.Node has no spans". #889 showed that framing
was too pessimistic: the parser retains the whole source buffer for the life of
the parse and already slices it for Function.prototype.toString, so retaining
a node's own span is the established pattern rather than new machinery. #889 did
exactly this for ast.Node.call at no size cost — the union is sized by
class_expr (72 bytes) and the enlarged call payload is 56.
ast.Node.new_expr (24 bytes) and ast.Node.member (40) have the same headroom.
Required implementation
- Retain the construction's source span on
ast.Node.new_expr, and emit JSC's(evaluating '<source>')suffix from theis not a constructorthrow sites ininterpreter.zig(notAConstructorSubject's five callers). - Retain the member expression's span on
ast.Node.member, and emit the same suffix fromnotAnObjectMessage's callers. Note JSC prints the member expression there (o.m.n), not the enclosing call. - Both must reach the bytecode tier too. #889 added
bc.Chunk.call_sitesplusChunk.callSiteAtfor exactly this; the construction and member opcodes need the same treatment, or the tiers disagree on text under a corpus that never asserts it. - Gate it beside the #889 test in
src/context.zig, asserting identical text on the tree-walker and inside a generator body (which only the VM can run).