@scriptc/compiler 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ambient/scriptc-node-fallback.d.ts +63 -15
- package/ambient/scriptc.d.ts +2 -2
- package/dist/backend/cc.d.ts +2 -2
- package/dist/backend/emission/emit-async.js +1 -1
- package/dist/backend/emission/emit-exprs.js +131 -54
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-island.js +1 -1
- package/dist/backend/emission/emit-shapes.js +1 -1
- package/dist/backend/emission/emit-walkers.d.ts +14 -14
- package/dist/backend/emission/emit-walkers.js +44 -44
- package/dist/backend/emission/emit-walkers.js.map +1 -1
- package/dist/backend/emission/emitter.d.ts +3 -3
- package/dist/backend/emission/emitter.js +33 -9
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/emission/may-throw.js +1 -1
- package/dist/backend/llvm/dyn.d.ts +10 -10
- package/dist/backend/llvm/dyn.js +26 -26
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +156 -47
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/shapes.js +1 -1
- package/dist/backend/llvm/walkers.js +2 -2
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/coverage/surface-manifest.js +16 -2
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +21 -8
- package/dist/diagnostics/diagnostic.js +48 -14
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.js +5 -5
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.js +12 -12
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +63 -7
- package/dist/frontend/lowering/lower-builtins.js +327 -35
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +4 -4
- package/dist/frontend/lowering/lower-calls.js +104 -70
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +7 -0
- package/dist/frontend/lowering/lower-classes.js +82 -6
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +9 -5
- package/dist/frontend/lowering/lower-containers.js +88 -26
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-emitter.d.ts +70 -3
- package/dist/frontend/lowering/lower-emitter.js +438 -31
- package/dist/frontend/lowering/lower-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +87 -12
- package/dist/frontend/lowering/lower-exprs.js +630 -125
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +5 -5
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.js +12 -3
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +8 -5
- package/dist/frontend/lowering/lower-modules.js +157 -63
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +24 -0
- package/dist/frontend/lowering/lower-namespaces.js +158 -16
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +11 -11
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +1 -1
- package/dist/frontend/lowering/lower-stmts.js +271 -36
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +171 -20
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +27 -10
- package/dist/frontend/lowering/lowerer.js +156 -54
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +44 -0
- package/dist/frontend/lowering/surfaces.js +236 -5
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm.d.ts +12 -0
- package/dist/frontend/npm.js +30 -0
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/program.d.ts +25 -0
- package/dist/frontend/program.js +145 -136
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/shared.d.ts +1 -1
- package/dist/frontend/shared.js +8 -8
- package/dist/frontend/shared.js.map +1 -1
- package/dist/frontend/types.d.ts +2 -2
- package/dist/frontend/types.js +15 -15
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +169 -5
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +174 -106
- package/dist/ir/nodes.js +69 -24
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +55 -36
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/fence-eval.js +12 -2
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/int-infer.d.ts +119 -0
- package/dist/library/int-infer.js +1314 -0
- package/dist/library/int-infer.js.map +1 -0
- package/dist/library/int-infer.test.d.ts +1 -0
- package/dist/library/int-infer.test.js +279 -0
- package/dist/library/int-infer.test.js.map +1 -0
- package/dist/library/profile.d.ts +34 -5
- package/dist/library/profile.js +77 -13
- package/dist/library/profile.js.map +1 -1
- package/dist/library/sidecar-validate.js +1 -1
- package/dist/library/sidecar-validate.js.map +1 -1
- package/dist/library/sidecar.d.ts +24 -1
- package/dist/library/sidecar.js +163 -16
- package/dist/library/sidecar.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +210 -12
|
@@ -184,11 +184,11 @@ leading?: readonly IrExpr[]): IrExpr[];
|
|
|
184
184
|
* `type` has no undefined arm to wrap into. */
|
|
185
185
|
export declare function wrappedUndefined(L: Lowerer, type: IrType, loc: SrcLoc): IrExpr | null;
|
|
186
186
|
/** The synthesized argument for an omitted omittable param: the interned
|
|
187
|
-
* undefined arm of the param's `T | undefined` ABI union, or the
|
|
187
|
+
* undefined arm of the param's `T | undefined` ABI union, or the checked-dynamic tree
|
|
188
188
|
* undefined for a checked-dynamic param (`bar?: any`). */
|
|
189
189
|
/** The "absent argument" value for a param SLOT type, or null when the
|
|
190
190
|
* slot cannot hold one: the interned undefined arm for undefined-armed
|
|
191
|
-
* unions, the
|
|
191
|
+
* unions, the dyn undefined for checked-dynamic slots, the engine's own
|
|
192
192
|
* undefined for island slots. Shared by every call-completion loop
|
|
193
193
|
* (direct calls and calls through func-typed values). */
|
|
194
194
|
export declare function omittedArgFor(L: Lowerer, type: IrType, loc: SrcLoc): IrExpr | null;
|
|
@@ -382,7 +382,7 @@ export declare function lowerCall(L: Lowerer, expr: ts.CallExpression): IrExpr;
|
|
|
382
382
|
* - CHECKED-DYNAMIC (dyn spread sources — a JS rest binding, a dyn
|
|
383
383
|
* value): box the callee (dynFrom; a dyn callee is already boxed),
|
|
384
384
|
* convert every argument into dyn, and emit the spread-marked dynCall
|
|
385
|
-
* — the emitters build one fresh
|
|
385
|
+
* — the emitters build one fresh dyn argument array (spreads flatten
|
|
386
386
|
* left-to-right, non-iterables throw V8's TypeError) and apply through
|
|
387
387
|
* it; the boxed thunk delivers JS arity exactly. Result dyn, checked
|
|
388
388
|
* per use like every any-origin value.
|
|
@@ -404,7 +404,7 @@ export declare function lowerSpreadArgsCall(L: Lowerer, expr: ts.CallExpression,
|
|
|
404
404
|
* slots keep completeArgs' same-element spread packing. */
|
|
405
405
|
export declare function spreadNeedsRuntimeArity(shapes: readonly ParamShape[], argNodes: readonly ts.Expression[]): boolean;
|
|
406
406
|
/** The SHARED prototype names scr_dyn_invoke dispatches at runtime (the
|
|
407
|
-
* subset of
|
|
407
|
+
* subset of DYN_PROTO_METHOD_NAMES with a receiver-kind dispatch): the
|
|
408
408
|
* runtime runs the real method for the receiver's kind, throws Node's
|
|
409
409
|
* is-not-a-function where the kind's prototype lacks the name, and
|
|
410
410
|
* fences LOUDLY on real-but-unimplemented pairs. */
|
|
@@ -13,7 +13,7 @@ import { NARROW_FIRST, builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.
|
|
|
13
13
|
import { requiresDynamicDiag } from "../../diagnostics/diagnostic.js";
|
|
14
14
|
import { mixinFnShapeOf } from "./lower-mixins.js";
|
|
15
15
|
import { bufEncoding, dynStringReceiver, lowerArrayFromCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerRegexMethodCall, lowerStringMethodCall, lowerTupleReadMethodCall } from "./lower-containers.js";
|
|
16
|
-
import { lowerChildStreamMethodCall, lowerDirentMethodCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerWatcherMethodCall } from "./lower-builtins.js";
|
|
16
|
+
import { lowerChildStreamMethodCall, lowerCreateRequireCall, lowerDirentMethodCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerWatcherMethodCall } from "./lower-builtins.js";
|
|
17
17
|
import { droppableStatic, lowerPromiseAllTupleCall, lowerPromiseRejectCall, probeLower, templateRawTextOf } from "./lower-exprs.js";
|
|
18
18
|
import { httpClientFnBindingOf, isStreamUndefCallExpr, lowerHttpClientFnCall } from "./lower-server.js";
|
|
19
19
|
import { EMITTER_API_MEMBERS, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall } from "./lower-classes.js";
|
|
@@ -85,7 +85,7 @@ export function paramShape(L, param) {
|
|
|
85
85
|
const raw = L.irTypeOf(param.name);
|
|
86
86
|
// A DYNAMIC-TIER pattern source (`function f({} = a)` with
|
|
87
87
|
// `a: any` — jsval for island values, dyn for the checked-dynamic
|
|
88
|
-
//
|
|
88
|
+
// dyn): the slot holds its tier's undefined DIRECTLY, so the ABI
|
|
89
89
|
// is the slot itself — no synthesized union; the prologue tests
|
|
90
90
|
// undefined at runtime (declareParams).
|
|
91
91
|
if (raw.kind === "dyn" || raw.kind === "jsval") {
|
|
@@ -103,7 +103,7 @@ export function paramShape(L, param) {
|
|
|
103
103
|
}
|
|
104
104
|
if (param.dotDotDotToken) {
|
|
105
105
|
// A JS rest param with no static element type (`(...args)` — any[]):
|
|
106
|
-
// the VARIADIC dyn form. The lifted function takes one trailing
|
|
106
|
+
// the VARIADIC dyn form. The lifted function takes one trailing dyn
|
|
107
107
|
// ARRAY param the dyn call thunk fills with the call's surplus
|
|
108
108
|
// arguments; the binding is that array (dynRest — funcType marks
|
|
109
109
|
// `rest`, and the value only ever calls through the boxed thunk).
|
|
@@ -133,7 +133,7 @@ export function paramShape(L, param) {
|
|
|
133
133
|
const raw = L.irTypeOf(param.name);
|
|
134
134
|
// A DYNAMIC-TIER defaulted param (`function f(x = a)` with `a: any`
|
|
135
135
|
// — tsc types x any; jsval for island values, dyn for the checked-
|
|
136
|
-
// dynamic
|
|
136
|
+
// dynamic dyn): the slot holds its tier's undefined directly, so
|
|
137
137
|
// the ABI is the slot itself and the prologue's default test is the
|
|
138
138
|
// runtime undefined test (declareParams).
|
|
139
139
|
if (raw.kind === "dyn" || raw.kind === "jsval") {
|
|
@@ -169,7 +169,7 @@ export function paramShape(L, param) {
|
|
|
169
169
|
if (param.questionToken && !L.bareUndefinedArmedUnion(type) && type.kind !== "dyn" && type.kind !== "jsval") {
|
|
170
170
|
// `x?: unknown` where unknown came from an annotation: undefined is
|
|
171
171
|
// absorbed into the hole type, so no undefined ARM exists — but a
|
|
172
|
-
// checked-dynamic slot holds the
|
|
172
|
+
// checked-dynamic slot holds the dyn undefined directly (`bar?: any`
|
|
173
173
|
// — an omitted call passes it, undefinedArgFor), and an island slot
|
|
174
174
|
// the engine's own undefined likewise (`options?: [string?]` — an
|
|
175
175
|
// optional-tuple param, jsval-mapped), so dyn and jsval params stay
|
|
@@ -243,7 +243,7 @@ leading) {
|
|
|
243
243
|
// A missing argument for a CHECKED-DYNAMIC param (an implicit-any
|
|
244
244
|
// JS signature called short — `mustCall(fn)` with `expected`
|
|
245
245
|
// omitted): JS fills undefined, and the dyn slot holds exactly
|
|
246
|
-
// that — the undefined
|
|
246
|
+
// that — the undefined dyn value. tsc's arity families don't gate
|
|
247
247
|
// .js builds (SEMANTICS.md 116), so the completion lands here.
|
|
248
248
|
if (shape.type.kind === "dyn") {
|
|
249
249
|
return { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc };
|
|
@@ -271,7 +271,7 @@ leading) {
|
|
|
271
271
|
else if (restAt >= 0 && shapes[restAt].mode === "dynRest") {
|
|
272
272
|
// The VARIADIC dyn pack (a JS `...args` with no static element
|
|
273
273
|
// type, or the synthetic `arguments` slot): surplus arguments
|
|
274
|
-
// convert through the dyn boundary into one fresh
|
|
274
|
+
// convert through the dyn boundary into one fresh dyn array —
|
|
275
275
|
// exactly what the boxed call thunk builds for indirect calls.
|
|
276
276
|
const elems = sources.slice(restAt).map((a) => {
|
|
277
277
|
if (isIr(a))
|
|
@@ -384,11 +384,11 @@ export function wrappedUndefined(L, type, loc) {
|
|
|
384
384
|
return wrapped.kind === "unionWrap" ? wrapped : null;
|
|
385
385
|
}
|
|
386
386
|
/** The synthesized argument for an omitted omittable param: the interned
|
|
387
|
-
* undefined arm of the param's `T | undefined` ABI union, or the
|
|
387
|
+
* undefined arm of the param's `T | undefined` ABI union, or the checked-dynamic tree
|
|
388
388
|
* undefined for a checked-dynamic param (`bar?: any`). */
|
|
389
389
|
/** The "absent argument" value for a param SLOT type, or null when the
|
|
390
390
|
* slot cannot hold one: the interned undefined arm for undefined-armed
|
|
391
|
-
* unions, the
|
|
391
|
+
* unions, the dyn undefined for checked-dynamic slots, the engine's own
|
|
392
392
|
* undefined for island slots. Shared by every call-completion loop
|
|
393
393
|
* (direct calls and calls through func-typed values). */
|
|
394
394
|
export function omittedArgFor(L, type, loc) {
|
|
@@ -529,7 +529,7 @@ export function appendImplicitUndefinedReturn(L, body, bodyReturn, loc) {
|
|
|
529
529
|
// A DYN body that can complete without returning (a JS function whose
|
|
530
530
|
// guarded return may not run — mustSucceed's `if (typeof fn ===
|
|
531
531
|
// 'function') return fn.apply(...)`): JS completes with undefined —
|
|
532
|
-
// the undefined
|
|
532
|
+
// the undefined dyn value.
|
|
533
533
|
if (bodyReturn.kind === "dyn") {
|
|
534
534
|
body.push({
|
|
535
535
|
kind: "return",
|
|
@@ -584,7 +584,7 @@ export function declaredReturnType(L, decl, blame) {
|
|
|
584
584
|
// The RECORD twin (the tracing suite's traced closures — `function ()
|
|
585
585
|
// { return expectedResult; }` infers `{ foo: string }`): JS object
|
|
586
586
|
// literals are checked-dynamic VALUES, so a record-typed return would
|
|
587
|
-
// copy the
|
|
587
|
+
// copy the dyn value into a struct at the return and copy it back out
|
|
588
588
|
// at any dyn boundary — identity lost twice (found.result !==
|
|
589
589
|
// expectedResult where Node passes the object through). The inferred
|
|
590
590
|
// shape is inference, not a contract: the return stays checked-
|
|
@@ -1332,7 +1332,7 @@ function resolveInferredReturn(L, inst, infer, body, decl) {
|
|
|
1332
1332
|
distinct.push(e.stmt.value.type);
|
|
1333
1333
|
}
|
|
1334
1334
|
if (distinct.length === 0) {
|
|
1335
|
-
final = DYN; // no valued return: JS completes with undefined — the
|
|
1335
|
+
final = DYN; // no valued return: JS completes with undefined — the dyn undefined, today's slot
|
|
1336
1336
|
}
|
|
1337
1337
|
else if (distinct.length === 1) {
|
|
1338
1338
|
const t = distinct[0];
|
|
@@ -1459,7 +1459,7 @@ export function lowerGenericFnValue(L, ref, info) {
|
|
|
1459
1459
|
const inst = genericValueInstance(L, ref, info, bindings);
|
|
1460
1460
|
// The value's type is the completed ABI signature — exact-arity, the
|
|
1461
1461
|
// declared-function value rule (dynRest slots stay out of the param
|
|
1462
|
-
// list; the rest marker carries the trailing
|
|
1462
|
+
// list; the rest marker carries the trailing dyn-array ABI).
|
|
1463
1463
|
const funcType = {
|
|
1464
1464
|
kind: "func",
|
|
1465
1465
|
params: inst.params.filter((p) => p.mode !== "dynRest").map((p) => p.type),
|
|
@@ -2316,6 +2316,15 @@ export function lowerCall(L, expr) {
|
|
|
2316
2316
|
}
|
|
2317
2317
|
}
|
|
2318
2318
|
}
|
|
2319
|
+
// `require("spec")` through a createRequire binding (and the inline
|
|
2320
|
+
// `createRequire(import.meta.url)("spec")` spelling — a CallExpression
|
|
2321
|
+
// callee no other dispatch path serves): the static erasure —
|
|
2322
|
+
// builtins/json/npm per lowerCreateRequireCall's arms.
|
|
2323
|
+
{
|
|
2324
|
+
const crServed = lowerCreateRequireCall(L, expr, loc);
|
|
2325
|
+
if (crServed)
|
|
2326
|
+
return crServed;
|
|
2327
|
+
}
|
|
2319
2328
|
// `process.getuid?.()` — intercepted BEFORE the optional-chain
|
|
2320
2329
|
// machinery (the member always exists on a POSIX target, so the
|
|
2321
2330
|
// optional call IS the call; `process.getuid` itself has no value
|
|
@@ -2433,7 +2442,7 @@ export function lowerCall(L, expr) {
|
|
|
2433
2442
|
// non-format argument: strings VERBATIM, everything else through
|
|
2434
2443
|
// inspect at the rest-args depth 2 (formatWithOptions) — scalar
|
|
2435
2444
|
// kinds byte-exactly, boxed functions as [Function: name] /
|
|
2436
|
-
// [Function (anonymous)], composites through the dyn
|
|
2445
|
+
// [Function (anonymous)], composites through the dyn walk
|
|
2437
2446
|
// (insp.dyn). Never throws — Node's console.log never does.
|
|
2438
2447
|
if (lowered.type.kind === "dyn") {
|
|
2439
2448
|
return {
|
|
@@ -2542,10 +2551,10 @@ export function lowerCall(L, expr) {
|
|
|
2542
2551
|
}
|
|
2543
2552
|
return { kind: "libCall", fn: "timers.queueMicrotask", args: [adapted], type: VOID, loc };
|
|
2544
2553
|
}
|
|
2545
|
-
// structuredClone: the JSON-safe + bytes subset over the
|
|
2554
|
+
// structuredClone: the JSON-safe + bytes subset over the checked-dynamic tree, deep;
|
|
2546
2555
|
// %DOMException clones through WebIDL serialization (name/message,
|
|
2547
2556
|
// the code re-derives). Functions/handles throw the spec's catchable
|
|
2548
|
-
// DataCloneError; cycles fence (the
|
|
2557
|
+
// DataCloneError; cycles fence (the checked-dynamic tree cannot represent them — Node
|
|
2549
2558
|
// clones cycles, a documented divergence). Option validation throws
|
|
2550
2559
|
// Node's exact errors; the zero-argument call Node's
|
|
2551
2560
|
// ERR_MISSING_ARGS. Provenance-checked like setTimeout.
|
|
@@ -2571,7 +2580,7 @@ export function lowerCall(L, expr) {
|
|
|
2571
2580
|
const valueNode = expr.arguments[0];
|
|
2572
2581
|
// A NON-EMPTY transfer array of static values: nothing static is
|
|
2573
2582
|
// transferable, so the call is Node's DataCloneError — decided here
|
|
2574
|
-
// (the list's values need no
|
|
2583
|
+
// (the list's values need no dyn representation to fail). An EMPTY
|
|
2575
2584
|
// literal transfer list is a no-op member and drops.
|
|
2576
2585
|
{
|
|
2577
2586
|
let optNode = expr.arguments[1];
|
|
@@ -2602,8 +2611,8 @@ export function lowerCall(L, expr) {
|
|
|
2602
2611
|
const value = toDynArg(valueNode);
|
|
2603
2612
|
const cloned = { kind: "libCall", fn: "dyn.structuredClone", args: [value, optsArg], type: DYN, loc };
|
|
2604
2613
|
// The declared result is the value's own type (the generic's T):
|
|
2605
|
-
// validate the
|
|
2606
|
-
// dyn-typed and unmappable results stay
|
|
2614
|
+
// validate the dyn copy back into it when the type can be checked;
|
|
2615
|
+
// dyn-typed and unmappable results stay dyn values (JS files).
|
|
2607
2616
|
const resultT = L.mapTypeOf(L.typeOf(expr));
|
|
2608
2617
|
if (resultT !== null && resultT.kind !== "dyn" && resultT.kind !== "void" &&
|
|
2609
2618
|
canDynCheckTo(resultT, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
|
|
@@ -2709,7 +2718,7 @@ export function lowerCall(L, expr) {
|
|
|
2709
2718
|
if (ts.isPropertyAccessExpression(expr.expression) &&
|
|
2710
2719
|
L.isIslandExpr(expr.expression.expression)) {
|
|
2711
2720
|
const receiver = L.lowerExpr(expr.expression.expression);
|
|
2712
|
-
// A checker-`any` receiver whose VALUE lives in the
|
|
2721
|
+
// A checker-`any` receiver whose VALUE lives in the checked-dynamic tree (a
|
|
2713
2722
|
// checked-dynamic local behind the any-typed spelling — the JS
|
|
2714
2723
|
// WeakSet placeholder, rest-args arrays): the checked-dynamic
|
|
2715
2724
|
// method machinery owns it — receiver-kind dispatch, stored-member
|
|
@@ -2756,7 +2765,7 @@ export function lowerCall(L, expr) {
|
|
|
2756
2765
|
}
|
|
2757
2766
|
const callee = L.lowerExpr(expr.expression);
|
|
2758
2767
|
// A checker-`any` callee that LOWERED checked-dynamic (a dyn member
|
|
2759
|
-
// chain's stored function): the
|
|
2768
|
+
// chain's stored function): the checked-dynamic tree's own call — dynCall reads and
|
|
2760
2769
|
// calls the stored member with Node's is-not-a-function TypeError
|
|
2761
2770
|
// on refusal.
|
|
2762
2771
|
if (callee.type.kind === "dyn") {
|
|
@@ -3022,7 +3031,7 @@ export function lowerCall(L, expr) {
|
|
|
3022
3031
|
}
|
|
3023
3032
|
// STATIC atob/btoa (str.atob / str.btoa — scr_string.c; WHATWG
|
|
3024
3033
|
// forgiving-base64, Node is the oracle). The argument crosses as a
|
|
3025
|
-
//
|
|
3034
|
+
// dyn value: WebIDL ToString runs in the runtime over the dyn kind
|
|
3026
3035
|
// (Node's atob(null) decodes "null"), a malformed input throws the
|
|
3027
3036
|
// catchable DOMException InvalidCharacterError, and the
|
|
3028
3037
|
// zero-argument call throws Node's TypeError [ERR_MISSING_ARGS].
|
|
@@ -3515,7 +3524,7 @@ export function lowerCall(L, expr) {
|
|
|
3515
3524
|
if (callee.type.kind === "dyn") {
|
|
3516
3525
|
if (expr.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
3517
3526
|
// The runtime-arity lane: a dyn callee is already boxed — the
|
|
3518
|
-
// spread-marked dynCall applies through a fresh
|
|
3527
|
+
// spread-marked dynCall applies through a fresh dyn argument
|
|
3519
3528
|
// array (lowerSpreadArgsCall). Sources outside it keep the fence.
|
|
3520
3529
|
const spreadServed = lowerSpreadArgsCall(L, expr, callee, loc);
|
|
3521
3530
|
if (spreadServed)
|
|
@@ -3595,7 +3604,7 @@ export function lowerCall(L, expr) {
|
|
|
3595
3604
|
// skip — not a shape this surface models; fence.
|
|
3596
3605
|
for (let i = args.length; i < params.length; i++) {
|
|
3597
3606
|
// A missing argument completes with the slot's absent value — the
|
|
3598
|
-
// interned undefined arm, the
|
|
3607
|
+
// interned undefined arm, the dyn undefined for checked-dynamic
|
|
3599
3608
|
// slots (a JS-inferred wrapper like mustCall's, called short), or
|
|
3600
3609
|
// the engine undefined for island slots.
|
|
3601
3610
|
const absent = omittedArgFor(L, params[i], loc);
|
|
@@ -3615,7 +3624,7 @@ export function lowerCall(L, expr) {
|
|
|
3615
3624
|
* - CHECKED-DYNAMIC (dyn spread sources — a JS rest binding, a dyn
|
|
3616
3625
|
* value): box the callee (dynFrom; a dyn callee is already boxed),
|
|
3617
3626
|
* convert every argument into dyn, and emit the spread-marked dynCall
|
|
3618
|
-
* — the emitters build one fresh
|
|
3627
|
+
* — the emitters build one fresh dyn argument array (spreads flatten
|
|
3619
3628
|
* left-to-right, non-iterables throw V8's TypeError) and apply through
|
|
3620
3629
|
* it; the boxed thunk delivers JS arity exactly. Result dyn, checked
|
|
3621
3630
|
* per use like every any-origin value.
|
|
@@ -3703,7 +3712,7 @@ export function spreadNeedsRuntimeArity(shapes, argNodes) {
|
|
|
3703
3712
|
}
|
|
3704
3713
|
/** METHOD calls on dyn receivers (`pkg.name.replace(...)`, `rawName.split`,
|
|
3705
3714
|
* `ws.packages.filter(...)` — JSON.parse-derived values): validate the
|
|
3706
|
-
* receiver's
|
|
3715
|
+
* receiver's dyn kind, extract, and ride the STATIC method machinery — the
|
|
3707
3716
|
* dyn boundary's trust-but-verify stance extended to receivers. The
|
|
3708
3717
|
* receiver-kind mismatch throws V8's own catchable TypeErrors (nullish:
|
|
3709
3718
|
* "Cannot read properties of undefined (reading 'replace')"; other kinds:
|
|
@@ -3711,14 +3720,14 @@ export function spreadNeedsRuntimeArity(shapes, argNodes) {
|
|
|
3711
3720
|
* evaluate, where JS evaluates them first for the non-nullish case
|
|
3712
3721
|
* (SEMANTICS.md). String methods ride the string/regex intrinsic tables
|
|
3713
3722
|
* through a validated-string receiver; `.filter` runs the predicate over
|
|
3714
|
-
* the
|
|
3723
|
+
* the dyn array and validated-extracts the survivors into the element type
|
|
3715
3724
|
* the checker committed the result to. Null when the receiver isn't a dyn
|
|
3716
3725
|
* value or the method isn't claimable (the method-call fence stays). */
|
|
3717
3726
|
function lowerDynReceiverMethodCall(L, call, access) {
|
|
3718
3727
|
if (L.chainBlocked(call, access))
|
|
3719
3728
|
return null;
|
|
3720
3729
|
// Only checker-untyped receivers: `any`/`unknown`, or the `any[]` an
|
|
3721
|
-
// Array.isArray guard narrows them to (the value is STILL the
|
|
3730
|
+
// Array.isArray guard narrows them to (the value is STILL the checked-dynamic tree
|
|
3722
3731
|
// array — scalar narrowings bridge through maybeNarrow's dynCheck and
|
|
3723
3732
|
// take the ordinary typed paths, but there is no static home for an
|
|
3724
3733
|
// any-elemented array). Typed receivers keep their own lowerings.
|
|
@@ -3750,7 +3759,7 @@ function lowerDynReceiverMethodCall(L, call, access) {
|
|
|
3750
3759
|
return null;
|
|
3751
3760
|
// Typed-destination filter first (validated extraction into a real
|
|
3752
3761
|
// T[]); an untyped destination falls through to the runtime dispatch
|
|
3753
|
-
// below (the survivors stay
|
|
3762
|
+
// below (the survivors stay dyn values).
|
|
3754
3763
|
if (access.name.text === "filter") {
|
|
3755
3764
|
const extracted = lowerDynArrayFilterCall(L, call, access, recv);
|
|
3756
3765
|
if (extracted)
|
|
@@ -3758,10 +3767,10 @@ function lowerDynReceiverMethodCall(L, call, access) {
|
|
|
3758
3767
|
}
|
|
3759
3768
|
if (access.name.text === "flatMap")
|
|
3760
3769
|
return lowerDynArrayFlatMapCall(L, call, access, recv);
|
|
3761
|
-
// String methods claim only names NO other
|
|
3770
|
+
// String methods claim only names NO other dyn-representable kind's
|
|
3762
3771
|
// prototype declares (Array carries includes/indexOf/slice too): for
|
|
3763
3772
|
// these, "the receiver is a string, or the call throws V8's TypeError"
|
|
3764
|
-
// IS Node's semantics for every possible
|
|
3773
|
+
// IS Node's semantics for every possible dyn value. Shared names would
|
|
3765
3774
|
// need a receiver-kind dispatch — they keep the fence.
|
|
3766
3775
|
if (DYN_STRING_ONLY_METHODS.has(access.name.text)) {
|
|
3767
3776
|
const checked = () => dynStringReceiver(L, recv, access);
|
|
@@ -3795,7 +3804,7 @@ function lowerDynReceiverMethodCall(L, call, access) {
|
|
|
3795
3804
|
}
|
|
3796
3805
|
// SHARED prototype names with a runtime dispatch (scr_dyn_invoke):
|
|
3797
3806
|
// push/slice/join/forEach/map/apply/... dispatch on the receiver's
|
|
3798
|
-
// RUNTIME kind — the honest answer for names more than one
|
|
3807
|
+
// RUNTIME kind — the honest answer for names more than one dyn-
|
|
3799
3808
|
// representable prototype declares (test/common's mustCall internals:
|
|
3800
3809
|
// mustCallChecks.push(context), failed.forEach(fn), fn.apply(this,
|
|
3801
3810
|
// args)). Implemented (kind, name) pairs run JS-exact; real-but-
|
|
@@ -3817,18 +3826,18 @@ function lowerDynReceiverMethodCall(L, call, access) {
|
|
|
3817
3826
|
loc: locOf(call),
|
|
3818
3827
|
};
|
|
3819
3828
|
}
|
|
3820
|
-
// Names NO
|
|
3829
|
+
// Names NO dyn-representable prototype declares: the member can only
|
|
3821
3830
|
// be an OWN property, so "read the member, call it" IS Node's
|
|
3822
|
-
// semantics for every possible
|
|
3831
|
+
// semantics for every possible dyn value — `handlers.onDone(x)` on a
|
|
3823
3832
|
// checked-dynamic object calls the stored function (dynKeyGet answers
|
|
3824
3833
|
// the member or undefined; dynCall throws Node's exact catchable
|
|
3825
3834
|
// "handlers.onDone is not a function" on a non-function). Prototype
|
|
3826
3835
|
// names (map/join/hasOwnProperty/call/...) keep the fence: on a real
|
|
3827
|
-
//
|
|
3836
|
+
// dyn array/string/object Node would run the METHOD, which no stored
|
|
3828
3837
|
// member models. Order note: JS reads the callee before evaluating
|
|
3829
3838
|
// arguments — dynKeyGet's undefined-receiver TypeError fires first,
|
|
3830
3839
|
// exactly Node.
|
|
3831
|
-
if (
|
|
3840
|
+
if (DYN_PROTO_METHOD_NAMES.has(access.name.text))
|
|
3832
3841
|
return null;
|
|
3833
3842
|
// Optional forms (`obj.cb?.()`, `obj?.cb()`) belong to the chain
|
|
3834
3843
|
// machinery's short-circuit semantics — not modeled here yet.
|
|
@@ -3848,12 +3857,12 @@ function lowerDynReceiverMethodCall(L, call, access) {
|
|
|
3848
3857
|
const args = call.arguments.map((a) => L.lowerExprExpecting(a, DYN));
|
|
3849
3858
|
return { kind: "dynCall", callee: member, calleeName: access.getText(), args, type: DYN, loc };
|
|
3850
3859
|
}
|
|
3851
|
-
/** Prototype method names of the
|
|
3860
|
+
/** Prototype method names of the checked-dynamic tree-representable kinds (String, Array,
|
|
3852
3861
|
* Object, Function, Number prototypes): a dyn receiver call on one of
|
|
3853
3862
|
* these could be a REAL method on a real value, which a stored-member
|
|
3854
3863
|
* read would silently mis-answer — they keep the fence. Everything else
|
|
3855
|
-
* is own-property-or-throw for every
|
|
3856
|
-
const
|
|
3864
|
+
* is own-property-or-throw for every dyn value (the honest dynCall). */
|
|
3865
|
+
const DYN_PROTO_METHOD_NAMES = new Set([
|
|
3857
3866
|
// Object.prototype
|
|
3858
3867
|
"hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toLocaleString", "toString", "valueOf",
|
|
3859
3868
|
// Function.prototype
|
|
@@ -3868,7 +3877,7 @@ const DOM_PROTO_METHOD_NAMES = new Set([
|
|
|
3868
3877
|
"toExponential", "toFixed", "toPrecision",
|
|
3869
3878
|
]);
|
|
3870
3879
|
/** The SHARED prototype names scr_dyn_invoke dispatches at runtime (the
|
|
3871
|
-
* subset of
|
|
3880
|
+
* subset of DYN_PROTO_METHOD_NAMES with a receiver-kind dispatch): the
|
|
3872
3881
|
* runtime runs the real method for the receiver's kind, throws Node's
|
|
3873
3882
|
* is-not-a-function where the kind's prototype lacks the name, and
|
|
3874
3883
|
* fences LOUDLY on real-but-unimplemented pairs. */
|
|
@@ -3882,7 +3891,7 @@ export const DYN_DISPATCH_METHODS = new Set([
|
|
|
3882
3891
|
// the runtime kind so a boxed IncomingMessage/ServerResponse/Socket
|
|
3883
3892
|
// routes onto the same entry points the static lowerings use (modeled
|
|
3884
3893
|
// members) or the loud not-supported ladder (real-but-unmodeled ones).
|
|
3885
|
-
// On every other
|
|
3894
|
+
// On every other dyn kind they answer exactly what the stored-member
|
|
3886
3895
|
// path answered (OBJ own members call; the rest throw Node's
|
|
3887
3896
|
// is-not-a-function).
|
|
3888
3897
|
"on", "once", "addListener", "removeListener", "off", "removeAllListeners",
|
|
@@ -3897,11 +3906,11 @@ export const DYN_DISPATCH_METHODS = new Set([
|
|
|
3897
3906
|
// The netServer half of the handle surface (`let server; server =
|
|
3898
3907
|
// createServer(...)` — the handle lives in a dyn binding whose
|
|
3899
3908
|
// closures the checker cannot narrow): listen/close dispatch onto the
|
|
3900
|
-
// server ops; no other
|
|
3909
|
+
// server ops; no other dyn prototype declares either name, so the
|
|
3901
3910
|
// remainder keeps the stored-member answers.
|
|
3902
3911
|
"listen", "close",
|
|
3903
3912
|
// Promise.prototype (SCR_DYN_PROMISE receivers): the reaction trio
|
|
3904
|
-
// rides the fiber machinery (scr_dyn_promise_then); on every other
|
|
3913
|
+
// rides the fiber machinery (scr_dyn_promise_then); on every other dyn
|
|
3905
3914
|
// kind then/catch/finally answer the stored-member path (OBJ own
|
|
3906
3915
|
// members call, the rest throw Node's is-not-a-function).
|
|
3907
3916
|
"then", "catch", "finally",
|
|
@@ -3915,15 +3924,15 @@ export const DYN_DISPATCH_METHODS = new Set([
|
|
|
3915
3924
|
"additionalHeaders", "altsvc", "origin",
|
|
3916
3925
|
]);
|
|
3917
3926
|
/** STR_METHODS ∪ the regex-form names, MINUS everything Array (or any
|
|
3918
|
-
* other
|
|
3927
|
+
* other dyn kind's prototype) also declares. */
|
|
3919
3928
|
const DYN_STRING_ONLY_METHODS = new Set([
|
|
3920
3929
|
"charCodeAt", "charAt", "startsWith", "endsWith", "substring", "repeat",
|
|
3921
3930
|
"trim", "trimStart", "trimEnd", "split", "padStart", "padEnd",
|
|
3922
3931
|
"toLowerCase", "toUpperCase", "replace", "replaceAll", "match", "matchAll",
|
|
3923
3932
|
"search",
|
|
3924
3933
|
]);
|
|
3925
|
-
/** `Array.isArray(v)` — a real runtime test on `unknown` values (the
|
|
3926
|
-
* array kind:
|
|
3934
|
+
/** `Array.isArray(v)` — a real runtime test on `unknown` values (the checked-dynamic tree's
|
|
3935
|
+
* array kind: dyn arrays answer true, bytes/objects/scalars false — exactly
|
|
3927
3936
|
* JS, Uint8Array included), a compile-time constant on statically-typed
|
|
3928
3937
|
* ones (an `T[]` value IS an array, every other static kind is not; folded
|
|
3929
3938
|
* only over side-effect-free reads, the `in`-operator discipline; unions
|
|
@@ -4658,7 +4667,7 @@ export function lambdaSignature(L, node) {
|
|
|
4658
4667
|
// VARIADIC JS functions: a dynRest param (above), or a plain function
|
|
4659
4668
|
// whose body reads `arguments` (test/common's mustCall wrapper —
|
|
4660
4669
|
// `function() { ...; return fn.apply(this, arguments); }`). Both mark
|
|
4661
|
-
// the func type `rest`: the lifted body takes one trailing
|
|
4670
|
+
// the func type `rest`: the lifted body takes one trailing dyn-array
|
|
4662
4671
|
// param, filled by the boxed call thunk with the call's arguments
|
|
4663
4672
|
// from index params.length on. `arguments` is only claimed in
|
|
4664
4673
|
// ZERO-param functions (there it IS the surplus array); alongside
|
|
@@ -4678,7 +4687,7 @@ export function lambdaSignature(L, node) {
|
|
|
4678
4687
|
shapes,
|
|
4679
4688
|
funcType: {
|
|
4680
4689
|
kind: "func",
|
|
4681
|
-
// dynRest is EXCLUDED (the boxed thunk fills the trailing
|
|
4690
|
+
// dynRest is EXCLUDED (the boxed thunk fills the trailing dyn
|
|
4682
4691
|
// array — no spelled slot); islandRest is INCLUDED (the trailing
|
|
4683
4692
|
// jsval param IS the engine arguments array, the REST host-call
|
|
4684
4693
|
// adapter's one uniform shape).
|
|
@@ -4761,7 +4770,7 @@ export function lowerLambda(L, node) {
|
|
|
4761
4770
|
try {
|
|
4762
4771
|
const { params, prologue } = L.declareParams(node.parameters, shapes);
|
|
4763
4772
|
// The VARIADIC `arguments` form (rest-marked with no declared rest
|
|
4764
|
-
// param): a synthetic trailing
|
|
4773
|
+
// param): a synthetic trailing dyn-array param carries the call's
|
|
4765
4774
|
// arguments; `arguments` reads resolve to it (identifier lowering).
|
|
4766
4775
|
if (funcType.rest && !shapes.some((s) => s.mode === "dynRest" || s.mode === "islandRest")) {
|
|
4767
4776
|
const argsLocal = L.declareHiddenLocal("%arguments", DYN);
|
|
@@ -4866,7 +4875,7 @@ export function lowerLambda(L, node) {
|
|
|
4866
4875
|
const first = captured[0];
|
|
4867
4876
|
const pos = ts.getLineAndCharacterOfPosition(L.program.getSourceFile(first.loc.file) ?? node.getSourceFile(), first.loc.start);
|
|
4868
4877
|
const params = funcType.params.map((t, i) => ({ localId: `%pf${i}`, name: `%pf${i}`, type: t }));
|
|
4869
|
-
// A REST-MARKED value type hides one synthetic trailing
|
|
4878
|
+
// A REST-MARKED value type hides one synthetic trailing dyn-array
|
|
4870
4879
|
// param in the lifted function (the boxed call thunk fills it) —
|
|
4871
4880
|
// the fence lambda must spell that slot too or the validator's
|
|
4872
4881
|
// closure-signature check trips (SC9001). Island rest types SPELL
|
|
@@ -5093,7 +5102,7 @@ export function lowerPromiseMethodCall(L, call, access) {
|
|
|
5093
5102
|
// A TYPED handler on a DYN-settling promise (the tracePromise
|
|
5094
5103
|
// result's `.then((value) => ...)` — the checker's generic
|
|
5095
5104
|
// instantiation typed the parameter, but the settled value is a
|
|
5096
|
-
//
|
|
5105
|
+
// dyn value): box the handler and ride the dyn-handler desugar
|
|
5097
5106
|
// below — its call thunk validates the settled value into the
|
|
5098
5107
|
// declared parameter type (the per-arg dynCheck), Node's own
|
|
5099
5108
|
// runtime contract for a value that came off the wire untyped.
|
|
@@ -5105,10 +5114,10 @@ export function lowerPromiseMethodCall(L, call, access) {
|
|
|
5105
5114
|
}
|
|
5106
5115
|
// A CHECKED-DYNAMIC handler VALUE (`p.then(common.mustCall())` — the
|
|
5107
5116
|
// Node-suite wrapper is an untyped rest-args function): the same
|
|
5108
|
-
// async desugar with the handler called through the
|
|
5117
|
+
// async desugar with the handler called through the checked-dynamic tree — the
|
|
5109
5118
|
// settled value boxes (dyn passes through; void arrives as JS's
|
|
5110
5119
|
// explicit undefined argument), the result promise settles with the
|
|
5111
|
-
// handler's
|
|
5120
|
+
// handler's dyn result. A receiver rejection passes through the
|
|
5112
5121
|
// await like the typed path; the dyn call's own argument checking
|
|
5113
5122
|
// throws Node's TypeError for non-callables.
|
|
5114
5123
|
if (cb.type.kind === "dyn") {
|
|
@@ -5118,7 +5127,7 @@ export function lowerPromiseMethodCall(L, call, access) {
|
|
|
5118
5127
|
if (canConvertToDyn(v.type, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
|
|
5119
5128
|
return { kind: "dynFrom", value: v, type: DYN, loc };
|
|
5120
5129
|
}
|
|
5121
|
-
L.unsupported("SC1090", call.arguments[0], `then handlers receiving '${L.fmt(v.type)}' values through an untyped handler (the settled value cannot cross the
|
|
5130
|
+
L.unsupported("SC1090", call.arguments[0], `then handlers receiving '${L.fmt(v.type)}' values through an untyped handler (the settled value cannot cross the checked-dynamic tree boundary)`);
|
|
5122
5131
|
};
|
|
5123
5132
|
const resultT = { kind: "promise", inner: DYN };
|
|
5124
5133
|
const fnName = `%fn${L.lambdaCounter++}_then`;
|
|
@@ -5344,8 +5353,8 @@ export function lowerPromiseMethodCall(L, call, access) {
|
|
|
5344
5353
|
}
|
|
5345
5354
|
}
|
|
5346
5355
|
// .catch on a DYN-SETTLING promise (the tracePromise result's
|
|
5347
|
-
// `.catch((e) => ...)`): the rejection reason is a
|
|
5348
|
-
// handler runs through the
|
|
5356
|
+
// `.catch((e) => ...)`): the rejection reason is a dyn value, so the
|
|
5357
|
+
// handler runs through the checked-dynamic tree — a lifted async helper awaits the
|
|
5349
5358
|
// receiver, passes fulfillments through as dyn, and on rejection
|
|
5350
5359
|
// calls the boxed handler with caughtToDyn's identity-preserving
|
|
5351
5360
|
// snapshot (the dyn-then desugar's catch twin).
|
|
@@ -5531,7 +5540,7 @@ export function lowerPromiseMethodCall(L, call, access) {
|
|
|
5531
5540
|
else if (R.kind === "dyn") {
|
|
5532
5541
|
// A checked-dynamic result (the dyn-handler .then's promise-of-dyn
|
|
5533
5542
|
// chained into .catch): falling off the handler's end resolves
|
|
5534
|
-
// with the
|
|
5543
|
+
// with the dyn undefined.
|
|
5535
5544
|
catchBody.push({ kind: "return", value: dynUndefinedExpr(loc), loc });
|
|
5536
5545
|
}
|
|
5537
5546
|
else if (R.kind === "jsval") {
|
|
@@ -6263,7 +6272,7 @@ function lowerObjectStaticCall(L, call, access) {
|
|
|
6263
6272
|
// REAL prototype semantics: reads delegate LIVE, writes shadow,
|
|
6264
6273
|
// and inspect renders Node's exact shapes ("[Object: null
|
|
6265
6274
|
// prototype]" included). null and engine-held (jsval) prototypes
|
|
6266
|
-
// route; checked-dynamic (
|
|
6275
|
+
// route; checked-dynamic (dyn) prototypes keep the named fence —
|
|
6267
6276
|
// their marshal into the engine is a DEEP COPY, so a later
|
|
6268
6277
|
// prototype mutation would be invisible through the created
|
|
6269
6278
|
// object where Node delegates live.
|
|
@@ -6328,7 +6337,7 @@ function lowerObjectStaticCall(L, call, access) {
|
|
|
6328
6337
|
const tProbe = probeLower(L, call.arguments[0]);
|
|
6329
6338
|
const sProbe = probeLower(L, call.arguments[1]);
|
|
6330
6339
|
// CHECKED-DYNAMIC target and source (the JS file-scope
|
|
6331
|
-
// object-literal identity story): the runtime
|
|
6340
|
+
// object-literal identity story): the runtime dyn copy — own
|
|
6332
6341
|
// members of the source land on the target, which returns.
|
|
6333
6342
|
if (tProbe?.type.kind === "dyn") {
|
|
6334
6343
|
const loc = locOf(call);
|
|
@@ -6363,7 +6372,7 @@ function lowerObjectStaticCall(L, call, access) {
|
|
|
6363
6372
|
// `Object.assign(target, ...sources)` over a CHECKED-DYNAMIC target
|
|
6364
6373
|
// — the n-ary/spread form (`Object.assign({}, ...plugins.map(p =>
|
|
6365
6374
|
// p.options), coreOptions)`, support.js's option-table merge). The
|
|
6366
|
-
// sources pack into one fresh
|
|
6375
|
+
// sources pack into one fresh dyn array FIRST — plain sources
|
|
6367
6376
|
// retain in, spread sources flatten through the spread-call walk
|
|
6368
6377
|
// (V8's exact TypeError texts, the source spelling carried for the
|
|
6369
6378
|
// nullish form) — so every source evaluates and flattens before any
|
|
@@ -6375,7 +6384,7 @@ function lowerObjectStaticCall(L, call, access) {
|
|
|
6375
6384
|
// spread copies in at the boundary, the documented aliasing
|
|
6376
6385
|
// stance); anything else keeps the fence. Targets: dyn values, a
|
|
6377
6386
|
// FRESH object-literal target (`Object.assign({}, ...)` — no alias
|
|
6378
|
-
// exists, so building it as a
|
|
6387
|
+
// exists, so building it as a dyn object instead of a record is
|
|
6379
6388
|
// unobservable), or a nullish unit (Node's ToObject TypeError
|
|
6380
6389
|
// throws at the call, catchably); aliased record targets keep the
|
|
6381
6390
|
// fence — their identity could not survive the conversion.
|
|
@@ -6450,7 +6459,7 @@ function lowerObjectStaticCall(L, call, access) {
|
|
|
6450
6459
|
// Object.defineProperties over a CHECKED-DYNAMIC target (test/common's
|
|
6451
6460
|
// _mustCallInner copying name/length onto the mustCall wrapper): the
|
|
6452
6461
|
// runtime turns each descriptor's `value` into a plain own property on
|
|
6453
|
-
// the
|
|
6462
|
+
// the dyn node (OBJ members; FUNC nodes carry an own-property table) —
|
|
6454
6463
|
// flags accepted and ignored, accessors throw loudly (SEMANTICS.md).
|
|
6455
6464
|
// The result is the target, like JS. Typed targets keep the fence:
|
|
6456
6465
|
// static shapes have no property table to extend.
|
|
@@ -6513,7 +6522,7 @@ function lowerObjectStaticCall(L, call, access) {
|
|
|
6513
6522
|
const keyNode = call.arguments[1];
|
|
6514
6523
|
const probed = probeLower(L, recvNode);
|
|
6515
6524
|
// A CHECKED-DYNAMIC receiver (the JS file-scope object-literal
|
|
6516
|
-
// identity story): the runtime
|
|
6525
|
+
// identity story): the runtime dyn probe — OBJ member presence, ARR
|
|
6517
6526
|
// index bounds, Node's ToObject TypeError on nullish.
|
|
6518
6527
|
if (probed?.type.kind === "dyn") {
|
|
6519
6528
|
const loc = locOf(call);
|
|
@@ -6553,9 +6562,9 @@ function lowerObjectStaticCall(L, call, access) {
|
|
|
6553
6562
|
const argNode = call.arguments[0];
|
|
6554
6563
|
// A CHECKED-DYNAMIC argument — the checker may still spell a record
|
|
6555
6564
|
// type (the JS file-scope object-literal identity story stores the
|
|
6556
|
-
//
|
|
6557
|
-
// runtime walks the
|
|
6558
|
-
// JS's own-key order) and answers a
|
|
6565
|
+
// dyn object), so the LOWERED value's kind is the dispatch: the
|
|
6566
|
+
// runtime walks the dyn node's own keys (integer-like keys first,
|
|
6567
|
+
// JS's own-key order) and answers a dyn array.
|
|
6559
6568
|
{
|
|
6560
6569
|
const probed = probeLower(L, argNode);
|
|
6561
6570
|
const isDyn = probed?.type.kind === "dyn";
|
|
@@ -6777,7 +6786,7 @@ export function lowerFunction(L, decl) {
|
|
|
6777
6786
|
const { params, prologue } = L.declareParams(decl.parameters, sig.params);
|
|
6778
6787
|
// The synthetic `arguments` slot (a dynRest shape BEYOND the declared
|
|
6779
6788
|
// parameters — collectSignatureInner appended it): one trailing
|
|
6780
|
-
//
|
|
6789
|
+
// dyn-array param, resolved by `arguments` reads.
|
|
6781
6790
|
if (sig.params.length > decl.parameters.length && sig.params[sig.params.length - 1].mode === "dynRest") {
|
|
6782
6791
|
const argsLocal = L.declareHiddenLocal("%arguments", DYN);
|
|
6783
6792
|
params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
|
|
@@ -7128,8 +7137,13 @@ export function nullishValueUnitOf(L, sym) {
|
|
|
7128
7137
|
return cached;
|
|
7129
7138
|
L.nullishBindings.set(sym, null); // cycle guard: self-referential probes answer non-qualifying
|
|
7130
7139
|
const decl = L.checker.valueDeclarationOf(sym);
|
|
7140
|
+
// Statement-position declarators only: a for-loop head (`for (let x =
|
|
7141
|
+
// null as any; ...)`) declares a LOCAL with per-iteration semantics —
|
|
7142
|
+
// lowerVarDeclList's contract requires a lowered statement for it, so
|
|
7143
|
+
// the no-storage family never claims it.
|
|
7131
7144
|
if (!decl || !ts.isVariableDeclaration(decl) || !ts.isIdentifier(decl.name) ||
|
|
7132
|
-
decl.getSourceFile().isDeclarationFile || decl.initializer === undefined
|
|
7145
|
+
decl.getSourceFile().isDeclarationFile || decl.initializer === undefined ||
|
|
7146
|
+
!ts.isVariableStatement(decl.parent.parent)) {
|
|
7133
7147
|
return null;
|
|
7134
7148
|
}
|
|
7135
7149
|
const unit = nullishExprUnitOf(L, decl.initializer);
|
|
@@ -7204,8 +7218,21 @@ export function nullishGenericBindingUnitOf(L, sym) {
|
|
|
7204
7218
|
if (unit === null)
|
|
7205
7219
|
return null;
|
|
7206
7220
|
const mapped = L.mapTypeOf(L.checker.getTypeOfSymbol(sym));
|
|
7207
|
-
if (mapped !== null
|
|
7208
|
-
|
|
7221
|
+
if (mapped !== null) {
|
|
7222
|
+
// Only the EMPTY interned shape qualifies among record mappings —
|
|
7223
|
+
// the all-generic-signature interface (`I<A & B>`) whose struct has
|
|
7224
|
+
// no slot at all. A record with DATA fields (`const value: { inner:
|
|
7225
|
+
// number | string } = null as any`) keeps its real storage and
|
|
7226
|
+
// every ordinary lowering: its reads flow through positions (comma
|
|
7227
|
+
// chains, call arguments) the no-storage read paths never claim,
|
|
7228
|
+
// so claiming the binding would fence working programs.
|
|
7229
|
+
if (mapped.kind !== "record")
|
|
7230
|
+
return null;
|
|
7231
|
+
const shape = L.shapes.get(mapped.shapeId);
|
|
7232
|
+
if (!shape || shape.fields.length > 0 || shape.tuple !== undefined || shape.indexValue !== undefined) {
|
|
7233
|
+
return null;
|
|
7234
|
+
}
|
|
7235
|
+
}
|
|
7209
7236
|
return unit;
|
|
7210
7237
|
}
|
|
7211
7238
|
/** True when every write of `sym` in its declaring file is a plain `x =
|
|
@@ -7297,6 +7324,13 @@ export function deadUnmappableBinding(L, sym, decl) {
|
|
|
7297
7324
|
return true;
|
|
7298
7325
|
if (!ts.isIdentifier(decl.name))
|
|
7299
7326
|
return false;
|
|
7327
|
+
// Statement-position declarators only: a for-loop head (`for (let x;
|
|
7328
|
+
// false;) {}`) declares a LOCAL with per-iteration semantics —
|
|
7329
|
+
// lowerVarDeclList's contract requires a lowered statement for it, so
|
|
7330
|
+
// the no-storage family never claims it (catch bindings sit outside a
|
|
7331
|
+
// variable statement too and stay out the same way).
|
|
7332
|
+
if (!ts.isVariableStatement(decl.parent.parent))
|
|
7333
|
+
return false;
|
|
7300
7334
|
const sf = decl.getSourceFile();
|
|
7301
7335
|
if (sf.isDeclarationFile || isJsSourceFile(sf))
|
|
7302
7336
|
return false;
|