@scriptc/compiler 0.0.11 → 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 +12 -9
- 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 +97 -52
- 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 +8 -8
- 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 +97 -43
- 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/diagnostics/diagnostic.d.ts +1 -1
- package/dist/diagnostics/diagnostic.js +4 -3
- 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 +7 -7
- package/dist/frontend/lowering/lower-builtins.js +92 -31
- 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 +66 -66
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +31 -5
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +5 -5
- package/dist/frontend/lowering/lower-containers.js +19 -19
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-emitter.js +2 -2
- package/dist/frontend/lowering/lower-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +7 -7
- package/dist/frontend/lowering/lower-exprs.js +158 -112
- 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.js +16 -16
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +11 -1
- package/dist/frontend/lowering/lower-namespaces.js +41 -6
- 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 +191 -30
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +66 -22
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +10 -10
- package/dist/frontend/lowering/lowerer.js +51 -37
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.js +2 -2
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/program.js +1 -1
- package/dist/frontend/shared.js +7 -7
- 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.js +38 -7
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +110 -98
- package/dist/ir/nodes.js +48 -21
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +44 -34
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/int-infer.js +13 -0
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/profile.d.ts +8 -6
- 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 +1 -1
- package/dist/library/sidecar.js +20 -7
- package/dist/library/sidecar.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +4 -4
|
@@ -222,9 +222,9 @@ function lowerExprInner(L, expr) {
|
|
|
222
222
|
// A JS variable INITIALIZER whose BINDING registered as a
|
|
223
223
|
// checked-dynamic module global (the typedef-annotated
|
|
224
224
|
// doc-builder consts whose JSDoc types degraded — DYN slots):
|
|
225
|
-
// the island build could never land (no engine→
|
|
225
|
+
// the island build could never land (no engine→dyn crossing
|
|
226
226
|
// exists), so the literal takes its own world's path instead —
|
|
227
|
-
// the
|
|
227
|
+
// the dyn literal, or a static record the slot converts.
|
|
228
228
|
if (isJsSourceFile(expr.getSourceFile()) &&
|
|
229
229
|
ts.isVariableDeclaration(expr.parent) &&
|
|
230
230
|
expr.parent.initializer === expr &&
|
|
@@ -239,7 +239,7 @@ function lowerExprInner(L, expr) {
|
|
|
239
239
|
// reference degraded to checker-`any` — the tsgo multi-file
|
|
240
240
|
// value-as-type residue) is not an npm slot: when the literal's
|
|
241
241
|
// OWN type maps statically, it builds that way — the binding's
|
|
242
|
-
// checked-dynamic slot takes the
|
|
242
|
+
// checked-dynamic slot takes the dyn conversion. Genuinely
|
|
243
243
|
// island slots (npm .d.ts provenance, plain `any`) keep the
|
|
244
244
|
// native build.
|
|
245
245
|
if (ctxTs !== undefined && (ctxTs.flags & ts.TypeFlags.Any) === 0) {
|
|
@@ -274,13 +274,22 @@ function lowerExprInner(L, expr) {
|
|
|
274
274
|
const argsWith = [];
|
|
275
275
|
const getters = [];
|
|
276
276
|
let spread = null;
|
|
277
|
-
// A MEMBER a JS file cannot lower or marshal
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
//
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
|
|
277
|
+
// A MEMBER a JS file cannot lower or marshal: defer like a
|
|
278
|
+
// statement fence, shaped by what the member IS. A FUNCTION-shaped
|
|
279
|
+
// member (a generic function as a value, a signature with
|
|
280
|
+
// checked-dynamic parameters — the doc-builder public aggregate's
|
|
281
|
+
// degraded pieces) becomes a host closure that THROWS the captured
|
|
282
|
+
// diagnostic when invoked — building the aggregate compiles and
|
|
283
|
+
// only a CALL through the island stops the run. A DATA-shaped
|
|
284
|
+
// member must NOT become a callable (the retired fence box's
|
|
285
|
+
// silent wrong answers: typeof said "function", downstream errors
|
|
286
|
+
// blamed the wrong thing — the withPlugins `plugins:` slot), so it
|
|
287
|
+
// defines through the engine's getter machinery instead: READING
|
|
288
|
+
// the member throws the diagnostic — the honest granularity, since
|
|
289
|
+
// using the value is exactly what cannot be answered. `getterName`
|
|
290
|
+
// null keeps the closure shape (function-shaped members, and the
|
|
291
|
+
// conditional-spread arms where getters cannot combine).
|
|
292
|
+
const islandMemberFence = (diagsBefore, err, valueNode, getterName = null) => {
|
|
284
293
|
if (!(err instanceof PoisonError) ||
|
|
285
294
|
!isJsSourceFile(expr.getSourceFile()) ||
|
|
286
295
|
L.diagSink !== null ||
|
|
@@ -310,8 +319,33 @@ function lowerExprInner(L, expr) {
|
|
|
310
319
|
loc: locOf(valueNode),
|
|
311
320
|
});
|
|
312
321
|
const fence = { kind: "closure", fnName, captures: [], type: funcOf([], VOID), loc: locOf(valueNode) };
|
|
322
|
+
if (getterName !== null) {
|
|
323
|
+
getters.push({ name: getterName, fn: L.jsvalIn(fence, valueNode), loc: locOf(valueNode) });
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
313
326
|
return L.jsvalIn(fence, valueNode);
|
|
314
327
|
};
|
|
328
|
+
// The member's SHAPE decides the fence's granularity: syntactic
|
|
329
|
+
// functions and checker-callable values keep the call-time
|
|
330
|
+
// closure; everything else (call results, awaits, data reads —
|
|
331
|
+
// the withPlugins `plugins:` shape) fences at the READ.
|
|
332
|
+
const funcShapedMember = (p) => {
|
|
333
|
+
if (ts.isMethodDeclaration(p))
|
|
334
|
+
return true;
|
|
335
|
+
const src = ts.isPropertyAssignment(p)
|
|
336
|
+
? p.initializer
|
|
337
|
+
: ts.isShorthandPropertyAssignment(p)
|
|
338
|
+
? p.name
|
|
339
|
+
: null;
|
|
340
|
+
if (!src || !ts.isExpression(src))
|
|
341
|
+
return true; // unknown form: keep the closure shape
|
|
342
|
+
let inner = src;
|
|
343
|
+
while (ts.isParenthesizedExpression(inner))
|
|
344
|
+
inner = inner.expression;
|
|
345
|
+
if (ts.isArrowFunction(inner) || ts.isFunctionExpression(inner))
|
|
346
|
+
return true;
|
|
347
|
+
return L.checker.getCallSignatures(L.typeOf(src)).length > 0;
|
|
348
|
+
};
|
|
315
349
|
const pushProp = (name, value, valueNode, into) => {
|
|
316
350
|
const diagsBefore = L.diags.length;
|
|
317
351
|
let marshaled;
|
|
@@ -319,7 +353,15 @@ function lowerExprInner(L, expr) {
|
|
|
319
353
|
marshaled = L.jsvalIn(value, valueNode);
|
|
320
354
|
}
|
|
321
355
|
catch (err) {
|
|
322
|
-
|
|
356
|
+
// A value that LOWERED but cannot cross (a promise, a class
|
|
357
|
+
// instance): func-typed values keep the call-time closure;
|
|
358
|
+
// data-shaped values fence at the read (the getter), unless a
|
|
359
|
+
// conditional spread owns the literal (getters cannot combine).
|
|
360
|
+
const asGetter = value.type.kind !== "func" && spread === null;
|
|
361
|
+
const fence = islandMemberFence(diagsBefore, err, valueNode, asGetter ? name.text : null);
|
|
362
|
+
if (fence === null)
|
|
363
|
+
return; // registered as a fence getter — no data property
|
|
364
|
+
marshaled = fence;
|
|
323
365
|
}
|
|
324
366
|
for (const args of into) {
|
|
325
367
|
args.push({
|
|
@@ -403,7 +445,11 @@ function lowerExprInner(L, expr) {
|
|
|
403
445
|
: null;
|
|
404
446
|
}
|
|
405
447
|
catch (err) {
|
|
406
|
-
|
|
448
|
+
const nameText = name && (ts.isIdentifier(name) || ts.isStringLiteral(name)) ? name.text : null;
|
|
449
|
+
const asGetter = nameText !== null && spread === null && !funcShapedMember(prop);
|
|
450
|
+
value = islandMemberFence(valueDiagsBefore, err, prop, asGetter ? nameText : null);
|
|
451
|
+
if (value === null)
|
|
452
|
+
continue; // registered as a fence getter — no data property
|
|
407
453
|
}
|
|
408
454
|
if (value && name && (ts.isIdentifier(name) || ts.isStringLiteral(name))) {
|
|
409
455
|
pushProp(name, value, prop, [argsWithout, argsWith]);
|
|
@@ -494,7 +540,7 @@ function lowerExprInner(L, expr) {
|
|
|
494
540
|
}
|
|
495
541
|
// A checker-narrowed dyn read arrives as a VALIDATED extraction
|
|
496
542
|
// (maybeNarrow's dynCheck bridge). typeof needs no extraction — the
|
|
497
|
-
//
|
|
543
|
+
// dyn kind table answers the question directly, and answers it even
|
|
498
544
|
// where the flow type lied (the extraction would throw instead) —
|
|
499
545
|
// so unwrap back to the dyn value and take the dyn.typeof path.
|
|
500
546
|
if (operand.kind === "dynCheck" && operand.value.type.kind === "dyn") {
|
|
@@ -539,7 +585,7 @@ function lowerExprInner(L, expr) {
|
|
|
539
585
|
if (operand.type.kind === "dyn") {
|
|
540
586
|
// Bare typeof on a dyn value: the runtime's kind→string table
|
|
541
587
|
// (null answers "object", boxed closures "function" — JS-exact
|
|
542
|
-
// for every
|
|
588
|
+
// for every dyn kind; "bigint"/"symbol" have no producers).
|
|
543
589
|
return { kind: "libCall", fn: "dyn.typeof", args: [operand], type: STRING, loc };
|
|
544
590
|
}
|
|
545
591
|
L.unsupported("SC1090", expr, "typeof expressions on statically-typed values");
|
|
@@ -549,7 +595,7 @@ function lowerExprInner(L, expr) {
|
|
|
549
595
|
return { kind: "selfRef", type: L.ctx.selfType, loc };
|
|
550
596
|
}
|
|
551
597
|
// `arguments` in a variadic JS function (the rest-marked form): the
|
|
552
|
-
// synthetic trailing
|
|
598
|
+
// synthetic trailing dyn-array param — lambdaSignature marked the
|
|
553
599
|
// type and lowerLambda declared the local.
|
|
554
600
|
if (expr.text === "arguments" && L.ctx.argumentsLocal) {
|
|
555
601
|
return { kind: "varRef", localId: L.ctx.argumentsLocal.id, type: DYN, loc };
|
|
@@ -618,7 +664,7 @@ function lowerExprInner(L, expr) {
|
|
|
618
664
|
// optional/default/rest declarations pass the value fence first.
|
|
619
665
|
L.noteEdge(sig.name);
|
|
620
666
|
// dynRest slots stay out of the VALUE type's param list (fn.length
|
|
621
|
-
// semantics); the rest marker carries the trailing
|
|
667
|
+
// semantics); the rest marker carries the trailing dyn-array ABI.
|
|
622
668
|
const funcType = {
|
|
623
669
|
kind: "func",
|
|
624
670
|
params: sig.params.filter((p) => p.mode !== "dynRest").map((p) => p.type),
|
|
@@ -999,7 +1045,7 @@ function lowerExprInner(L, expr) {
|
|
|
999
1045
|
if (value.type.kind !== "promise") {
|
|
1000
1046
|
// A CHECKED-DYNAMIC operand (`await v` where v rode an untyped
|
|
1001
1047
|
// binding — a destructured helper's return, a dyn call result):
|
|
1002
|
-
// the runtime decides — a
|
|
1048
|
+
// the runtime decides — a dyn promise adopts (rejections
|
|
1003
1049
|
// re-throw), anything else takes JS's one-hop non-thenable await
|
|
1004
1050
|
// and answers itself. Thenable adoption stays unmodeled
|
|
1005
1051
|
// (SEMANTICS.md).
|
|
@@ -1157,9 +1203,9 @@ function lowerExprInner(L, expr) {
|
|
|
1157
1203
|
// bound handle).
|
|
1158
1204
|
if (L.isIslandExpr(expr.expression)) {
|
|
1159
1205
|
const receiver = L.lowerExpr(expr.expression);
|
|
1160
|
-
// The checker said 'any' but the VALUE lives in the
|
|
1206
|
+
// The checker said 'any' but the VALUE lives in the checked-dynamic tree (`this`
|
|
1161
1207
|
// in a plain JS function — dyn.this — or a checked-dynamic local
|
|
1162
|
-
// behind an any-typed spelling): the property read is the
|
|
1208
|
+
// behind an any-typed spelling): the property read is the checked-dynamic tree's
|
|
1163
1209
|
// own keyed read, dyn results and dyn chains exactly like every
|
|
1164
1210
|
// checked-dynamic member access (a nullish receiver throws V8's
|
|
1165
1211
|
// catchable TypeError, exactly Node). Never a jsOp over a dyn —
|
|
@@ -1443,14 +1489,14 @@ function lowerExprInner(L, expr) {
|
|
|
1443
1489
|
// .length` where the binding is an evolving any[] living as a
|
|
1444
1490
|
// checked-dynamic global): the stdlib member fence below would blame
|
|
1445
1491
|
// the unmappable checker type (`any[].length`), but the VALUE is a
|
|
1446
|
-
//
|
|
1492
|
+
// dyn node — lower the receiver first and read through the dyn keyed
|
|
1447
1493
|
// read (ARR answers length; everything else JS's own-property
|
|
1448
1494
|
// answer). Mapped receivers keep the fence-first order: their
|
|
1449
1495
|
// members' gaps are real surface gaps ([1,2].entries), not
|
|
1450
1496
|
// representation artifacts. `.length` on a receiver whose checker
|
|
1451
1497
|
// ARRAY type lowers to the checked-dynamic representation —
|
|
1452
1498
|
// `unknown[]`, the collapsed `(string | object)[]`, and the `any[]`
|
|
1453
|
-
// an Array.isArray guard narrows a collapsed union to — is the
|
|
1499
|
+
// an Array.isArray guard narrows a collapsed union to — is the checked-dynamic tree
|
|
1454
1500
|
// array's OWN length (a keyed read the ARR kind answers exactly),
|
|
1455
1501
|
// never an `Array.prototype` surface gap; both source languages.
|
|
1456
1502
|
// Prototype-method VALUE reads (`ps.map` unparenthesized) keep the
|
|
@@ -1460,7 +1506,7 @@ function lowerExprInner(L, expr) {
|
|
|
1460
1506
|
if ((isJsSourceFile(expr.getSourceFile()) &&
|
|
1461
1507
|
(L.mapTypeOf(L.typeOf(expr.expression)) === null ||
|
|
1462
1508
|
// A never-tainted receiver type maps (never rides as f64) but
|
|
1463
|
-
// its VALUE lowered checked-dynamic — same
|
|
1509
|
+
// its VALUE lowered checked-dynamic — same dyn read.
|
|
1464
1510
|
neverTaintedJsType(L, expr.expression, L.typeOf(expr.expression)))) ||
|
|
1465
1511
|
(expr.name.text === "length" &&
|
|
1466
1512
|
(L.checkerAnyArray(expr.expression) ||
|
|
@@ -1571,7 +1617,7 @@ function lowerExprInner(L, expr) {
|
|
|
1571
1617
|
// the property and the receiver's type instead of "property access".
|
|
1572
1618
|
const recvLowered = L.lowerExpr(expr.expression);
|
|
1573
1619
|
// A dyn receiver — JSON.parse's `any`, or `unknown` the checker
|
|
1574
|
-
// narrowed to `object` — reads through the
|
|
1620
|
+
// narrowed to `object` — reads through the dyn keyed read: member
|
|
1575
1621
|
// or undefined (JS's own-property answer), throwing JS's TypeError
|
|
1576
1622
|
// on undefined/null receivers unless an earlier `?.` guards the
|
|
1577
1623
|
// chain. Scalar-narrowed occurrences bridge via maybeNarrow's
|
|
@@ -1817,11 +1863,11 @@ export function lowerTernary(L, expr, expected) {
|
|
|
1817
1863
|
// === "string" ? pkg.name : null` — the lowering world types the
|
|
1818
1864
|
// unknown-receiver read `any`, which a static build cannot hold):
|
|
1819
1865
|
// dyn represents null and undefined directly, so the ternary stays
|
|
1820
|
-
// dyn — a unit arm converts to the
|
|
1866
|
+
// dyn — a unit arm converts to the dyn unit value (the dynFrom form
|
|
1821
1867
|
// the index-signature lowerings already use). A FRESH literal arm
|
|
1822
1868
|
// (`... ? pkg.scripts : {}` — the default-object idiom) converts the
|
|
1823
1869
|
// same way when it is JSON-safe: nothing else aliases a literal, so
|
|
1824
|
-
// the
|
|
1870
|
+
// the dyn copy is unobservable.
|
|
1825
1871
|
const dynish = (e) => e.type.kind === "dyn" ||
|
|
1826
1872
|
e.kind === "unitLit" ||
|
|
1827
1873
|
((e.kind === "recordLit" || e.kind === "arrayLit") && L.dynConvertible(e.type));
|
|
@@ -1907,13 +1953,13 @@ export function maybeNarrow(L, expr, node) {
|
|
|
1907
1953
|
(narrowed.kind === "f64" || narrowed.kind === "bool" || narrowed.kind === "string")) {
|
|
1908
1954
|
return { kind: "dynCheck", value: expr, type: narrowed, loc: expr.loc };
|
|
1909
1955
|
}
|
|
1910
|
-
// An `instanceof Uint8Array` narrow: the
|
|
1956
|
+
// An `instanceof Uint8Array` narrow: the checked-dynamic tree's bytes kind, extracted
|
|
1911
1957
|
// with the same validated copy the checked cast uses (a Buffer that
|
|
1912
1958
|
// crossed in rides the kind too — it IS a Uint8Array in Node).
|
|
1913
1959
|
if (narrowed?.kind === "bytes" && narrowed.elem === "u8") {
|
|
1914
1960
|
return { kind: "dynCheck", value: expr, type: narrowed, loc: expr.loc };
|
|
1915
1961
|
}
|
|
1916
|
-
// An `instanceof Error` narrow: the
|
|
1962
|
+
// An `instanceof Error` narrow: the checked-dynamic tree's error encoding rebuilds a
|
|
1917
1963
|
// fresh %Error (name/message/code from the marker object — a COPY,
|
|
1918
1964
|
// the unknown boundary's stance; SEMANTICS.md 67), validated like
|
|
1919
1965
|
// every dyn extraction.
|
|
@@ -2089,7 +2135,7 @@ export function lowerLooseNullCompare(L, expr, loc) {
|
|
|
2089
2135
|
return { kind: "boolLit", value: !negated, type: BOOL, loc };
|
|
2090
2136
|
}
|
|
2091
2137
|
if (other.type.kind === "dyn") {
|
|
2092
|
-
// `v != null` on unknown: one
|
|
2138
|
+
// `v != null` on unknown: one dyn kind test covers both units.
|
|
2093
2139
|
return {
|
|
2094
2140
|
kind: "dynTest",
|
|
2095
2141
|
test: "nullish",
|
|
@@ -2248,7 +2294,7 @@ export function lowerNullishCoalesce(L, expr, loc) {
|
|
|
2248
2294
|
// runtime kind (scr_dyn_is_nullish — UNDEF/NULL take the default;
|
|
2249
2295
|
// a wrapped island value routes to the engine's test, defensively:
|
|
2250
2296
|
// the wrap constructor scalar-normalizes engine null/undefined
|
|
2251
|
-
// away). Both sides live in the
|
|
2297
|
+
// away). Both sides live in the checked-dynamic tree — the right converts through
|
|
2252
2298
|
// the usual boundary and evaluates lazily in its branch; a default
|
|
2253
2299
|
// with no dyn representation keeps the fence.
|
|
2254
2300
|
const right = L.coerceToExpected(L.lowerExpr(expr.right), DYN);
|
|
@@ -2530,7 +2576,7 @@ export function lowerOptionalChain(L, expr) {
|
|
|
2530
2576
|
}
|
|
2531
2577
|
// NUMBER-typed indices (`entries?.[0]`): the property key is
|
|
2532
2578
|
// ToString(i), exactly JS — the canonical number text answers
|
|
2533
|
-
// array indices in the
|
|
2579
|
+
// array indices in the dyn helper, anything else (fractions,
|
|
2534
2580
|
// negatives, NaN) reads as an absent key.
|
|
2535
2581
|
if (key.type.kind === "f64") {
|
|
2536
2582
|
const skey = { kind: "toString", operand: key, type: STRING, loc: key.loc };
|
|
@@ -2538,12 +2584,12 @@ export function lowerOptionalChain(L, expr) {
|
|
|
2538
2584
|
}
|
|
2539
2585
|
}
|
|
2540
2586
|
// The METHOD-call step (`rawName?.match(re)` on a dyn value): a
|
|
2541
|
-
// nullish receiver short-circuits to the undefined
|
|
2587
|
+
// nullish receiver short-circuits to the undefined dyn singleton
|
|
2542
2588
|
// (dyn represents undefined directly); anything else runs the
|
|
2543
2589
|
// VALIDATED dynamic dispatch — the same one the truthy-guarded
|
|
2544
2590
|
// spelling (`v ? v.match(...) : null`) compiles to, Node-shaped
|
|
2545
2591
|
// TypeError on a kind mismatch included. The dispatch's static
|
|
2546
|
-
// result converts back into the
|
|
2592
|
+
// result converts back into the checked-dynamic tree (the chain's checker type is
|
|
2547
2593
|
// the error-any world's `any`, so dyn IS its representation).
|
|
2548
2594
|
if (ts.isCallExpression(expr) &&
|
|
2549
2595
|
ts.isPropertyAccessExpression(dotNode) &&
|
|
@@ -2714,7 +2760,7 @@ export function finishOptionalChain(L, expr, id, receiver, body, loc) {
|
|
|
2714
2760
|
}
|
|
2715
2761
|
// A dyn body (`pricing?.[key]` — an unknown-valued index-signature
|
|
2716
2762
|
// read) stays dyn: `unknown | undefined` IS unknown, and dyn represents
|
|
2717
|
-
// undefined directly (the unit path yields the undefined
|
|
2763
|
+
// undefined directly (the unit path yields the undefined dyn value).
|
|
2718
2764
|
if (body.type.kind === "dyn") {
|
|
2719
2765
|
return { kind: "optChain", id, receiver, body, type: DYN, loc };
|
|
2720
2766
|
}
|
|
@@ -2770,8 +2816,8 @@ export function ensureBool(L, e, node) {
|
|
|
2770
2816
|
return { kind: "toBool", operand: e, type: BOOL, loc: e.loc };
|
|
2771
2817
|
}
|
|
2772
2818
|
if (e.type.kind === "dyn") {
|
|
2773
|
-
// ToBoolean over the
|
|
2774
|
-
//
|
|
2819
|
+
// ToBoolean over the checked-dynamic tree (`if (pkg)` on a JSON.parse result): every
|
|
2820
|
+
// dyn kind has a JS-exact answer — the truthy dynTest reads the kind
|
|
2775
2821
|
// tag (plus the scalar payload for number/string).
|
|
2776
2822
|
return { kind: "dynTest", test: "truthy", value: e, type: BOOL, loc: e.loc };
|
|
2777
2823
|
}
|
|
@@ -2797,7 +2843,7 @@ export function ensureBool(L, e, node) {
|
|
|
2797
2843
|
L.badType(node, L.typeOf(node));
|
|
2798
2844
|
}
|
|
2799
2845
|
/** Truthiness needs a ToBoolean per arm: dyn/caught arms have none (a
|
|
2800
|
-
* dynamic ToBoolean over the
|
|
2846
|
+
* dynamic ToBoolean over the checked-dynamic tree / the snapshot box) — fence those
|
|
2801
2847
|
* unions; every other arm kind is answerable (units false, scalars and
|
|
2802
2848
|
* strings by value, refs true, jsval by the engine). */
|
|
2803
2849
|
export function requireTruthyUnion(L, unionId, node) {
|
|
@@ -2826,7 +2872,7 @@ export function lowerIntrinsicProperty(L, expr) {
|
|
|
2826
2872
|
return null;
|
|
2827
2873
|
// A never-tainted JS receiver type lowered checked-dynamic
|
|
2828
2874
|
// (neverTaintedJsType — `cmd.length` on `const cmd = ['pwd', []]`):
|
|
2829
|
-
// stand down so the
|
|
2875
|
+
// stand down so the dyn keyed read below the chain answers, instead
|
|
2830
2876
|
// of an array libCall over a dyn receiver hitting the boundary fence.
|
|
2831
2877
|
let kind = neverTaintedJsType(L, expr.expression, L.typeOf(expr.expression))
|
|
2832
2878
|
? undefined
|
|
@@ -3090,8 +3136,8 @@ export function lowerIntrinsicProperty(L, expr) {
|
|
|
3090
3136
|
return { kind: "jsExit", value: read, type: F64, loc: locOf(expr) };
|
|
3091
3137
|
}
|
|
3092
3138
|
// A CHECKED-DYNAMIC value behind an array-typed checker spelling
|
|
3093
|
-
// (`Object.keys(u).length` — the dyn walk answers a
|
|
3094
|
-
// tsc spells string[]): the runtime-world dispatch — a
|
|
3139
|
+
// (`Object.keys(u).length` — the dyn walk answers a dyn array while
|
|
3140
|
+
// tsc spells string[]): the runtime-world dispatch — a dyn keyed
|
|
3095
3141
|
// read validated into the declared number (a lying length throws
|
|
3096
3142
|
// the catchable TypeError, the dynCheck stance).
|
|
3097
3143
|
if (receiver.type.kind === "dyn") {
|
|
@@ -3134,7 +3180,7 @@ export function lowerArrayLiteral(L, expr, expected) {
|
|
|
3134
3180
|
// A JS literal whose OWN inferred type is never-tainted
|
|
3135
3181
|
// (neverTaintedJsType — the evolving `const gb = []`, the mixed
|
|
3136
3182
|
// command tuple `['pwd', []]`) carries no element information: route
|
|
3137
|
-
// it to the
|
|
3183
|
+
// it to the checked-dynamic tree fallback below rather than letting never's f64
|
|
3138
3184
|
// representation build a static number array (a later dyn push would
|
|
3139
3185
|
// throw "expected number at $, got string"; the tuple's union arm
|
|
3140
3186
|
// would re-tag as number[] and fence). A REAL slot still wins:
|
|
@@ -3264,14 +3310,14 @@ export function lowerArrayLiteral(L, expr, expected) {
|
|
|
3264
3310
|
if (!mapped || mapped.kind !== "array") {
|
|
3265
3311
|
// The JS declaration fallback, literal-side: an element type with no
|
|
3266
3312
|
// static home (a string | string[] mixed command tuple, an evolving
|
|
3267
|
-
// []) builds as a
|
|
3313
|
+
// []) builds as a dyn ARRAY — one dyn value whose elements each
|
|
3268
3314
|
// convert through the usual boundary (dynFrom's JSON-safe domain);
|
|
3269
3315
|
// an element that cannot convert fences per element. length/index
|
|
3270
|
-
// reads and dynamic consumers ride the keyed-
|
|
3316
|
+
// reads and dynamic consumers ride the keyed-dyn paths. TS literals
|
|
3271
3317
|
// take the same build when the slot ITSELF is checked-dynamic — an
|
|
3272
3318
|
// `unknown[]` annotation or a collapsed `(string | object)[]` maps
|
|
3273
3319
|
// to DYN wholesale now (mapType's dyn-element array rule), so the
|
|
3274
|
-
// literal IS the
|
|
3320
|
+
// literal IS the dyn array.
|
|
3275
3321
|
if (isJsSourceFile(expr.getSourceFile()) || mapped?.kind === "dyn") {
|
|
3276
3322
|
const elems = expr.elements.map((el) => {
|
|
3277
3323
|
if (ts.isSpreadElement(el)) {
|
|
@@ -3557,12 +3603,12 @@ function propNameText(L, name) {
|
|
|
3557
3603
|
return name.text;
|
|
3558
3604
|
}
|
|
3559
3605
|
/** The runtime-keyed JS object literal (a computed key that doesn't fold):
|
|
3560
|
-
* builds a
|
|
3606
|
+
* builds a dyn object member-by-member. Keys evaluate before their values,
|
|
3561
3607
|
* properties in source order — JS's object-literal evaluation exactly.
|
|
3562
3608
|
* Identifier/string keys are compile-time strings; numeric keys take
|
|
3563
3609
|
* their canonical number string (`{ 0x10: v }` stores "16" — JS's
|
|
3564
3610
|
* ToPropertyKey); computed keys evaluate and pass through ToString (the
|
|
3565
|
-
*
|
|
3611
|
+
* dyn's String() for dyn operands — `{ [field]: v }` where field is a
|
|
3566
3612
|
* checked-dynamic param). Values convert through the usual dyn boundary
|
|
3567
3613
|
* (dynFrom's domain, functions box); a value with no dyn representation
|
|
3568
3614
|
* fences per property. Spreads, accessors, and methods stay fenced —
|
|
@@ -3655,7 +3701,7 @@ export function lowerDynObjectLiteral(L, expr) {
|
|
|
3655
3701
|
L.unsupported("SC1101", valueExpr, `holding '${L.fmt(v.type)}' values in a runtime-keyed (computed-key) object literal`);
|
|
3656
3702
|
}
|
|
3657
3703
|
catch (err) {
|
|
3658
|
-
// A member value the
|
|
3704
|
+
// A member value the checked-dynamic tree cannot hold — a func whose signature
|
|
3659
3705
|
// cannot box, an island ('any') handle, a record carrying func
|
|
3660
3706
|
// fields (the export aggregate's typed utilities and npm-handle
|
|
3661
3707
|
// members): the same call-time fence deferral as an unlowerable
|
|
@@ -3725,7 +3771,7 @@ function fenceClosureProbe(L, node, slotType, attempt) {
|
|
|
3725
3771
|
return null;
|
|
3726
3772
|
}
|
|
3727
3773
|
// The trap's ABI: the field's func slot when one exists; otherwise (the
|
|
3728
|
-
//
|
|
3774
|
+
// dyn-object literal path — the value boxes into dyn) the all-dyn
|
|
3729
3775
|
// signature of the lambda's own arity, which canBoxFuncIntoDyn always
|
|
3730
3776
|
// admits.
|
|
3731
3777
|
const fieldType = slotType !== undefined && slotType.kind === "func"
|
|
@@ -3868,7 +3914,7 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
3868
3914
|
const loc = locOf(expr);
|
|
3869
3915
|
// The RUNTIME-KEYED literal (JS): a computed key that doesn't fold to a
|
|
3870
3916
|
// compile-time string means the literal's shape is not a compile-time
|
|
3871
|
-
// fact — no record shape can hold it. The whole literal builds as a
|
|
3917
|
+
// fact — no record shape can hold it. The whole literal builds as a dyn
|
|
3872
3918
|
// object instead (`{ [field]: criteria, actual: 0, ... }` —
|
|
3873
3919
|
// test/common's _mustCallInner context), where keys are runtime string
|
|
3874
3920
|
// values. TypeScript keeps the record world and its fence: this shape
|
|
@@ -4117,13 +4163,13 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4117
4163
|
const shapeId = L.shapes.intern(fields.map((f) => ({ name: f.name, type: f.value.type })));
|
|
4118
4164
|
return { kind: "recordLit", fields, type: { kind: "record", shapeId }, loc };
|
|
4119
4165
|
}
|
|
4120
|
-
// The JS declaration fallback, literal-side (the
|
|
4166
|
+
// The JS declaration fallback, literal-side (the checked-dynamic tree-array rule's
|
|
4121
4167
|
// object form): a literal whose shape has no static home — an
|
|
4122
4168
|
// unmappable contextual type over unmappable own fields (the
|
|
4123
4169
|
// PropertyDescriptorMap argument of Object.defineProperties, nested
|
|
4124
|
-
// descriptor records with `any` values) — builds as a
|
|
4170
|
+
// descriptor records with `any` values) — builds as a dyn OBJECT:
|
|
4125
4171
|
// each field converts through the usual dyn boundary, and dynamic
|
|
4126
|
-
// consumers ride the keyed-
|
|
4172
|
+
// consumers ride the keyed-dyn paths. TypeScript keeps the fence.
|
|
4127
4173
|
if ((!mapped || mapped.kind === "dyn") && isJsSourceFile(expr.getSourceFile())) {
|
|
4128
4174
|
return lowerDynObjectLiteral(L, expr);
|
|
4129
4175
|
}
|
|
@@ -4389,8 +4435,8 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4389
4435
|
const recArm = recArms[0];
|
|
4390
4436
|
const recTag = def.arms.indexOf(recArm);
|
|
4391
4437
|
// A checked-dynamic VALUE under the union-mapped checker type
|
|
4392
|
-
// (a JS
|
|
4393
|
-
// union tags a
|
|
4438
|
+
// (a JS dyn-holding binding): the present/absent desugar tests
|
|
4439
|
+
// union tags a dyn box does not carry — fence honestly instead
|
|
4394
4440
|
// of the validator's ICE.
|
|
4395
4441
|
const probedSrc = srcLowered ?? probeLower(L, srcNode);
|
|
4396
4442
|
if (probedSrc?.type.kind === "dyn") {
|
|
@@ -4572,11 +4618,11 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4572
4618
|
throw new PoisonError();
|
|
4573
4619
|
}
|
|
4574
4620
|
const obj = srcLowered ?? L.lowerExpr(srcNode);
|
|
4575
|
-
// A record-mapped CHECKER type whose VALUE lives in the
|
|
4621
|
+
// A record-mapped CHECKER type whose VALUE lives in the checked-dynamic tree (a
|
|
4576
4622
|
// JS file-scope object-literal global): read each field from
|
|
4577
|
-
// the
|
|
4623
|
+
// the checked-dynamic tree (dynKeyGet) and VALIDATE it into the source shape's
|
|
4578
4624
|
// field type (dynCheck) — the checked-dynamic member-read
|
|
4579
|
-
// discipline. A missing key answers the
|
|
4625
|
+
// discipline. A missing key answers the dyn undefined, exactly
|
|
4580
4626
|
// the undefined-armed optional's absent case; a mismatched
|
|
4581
4627
|
// runtime value throws the catchable TypeError, never a silent
|
|
4582
4628
|
// wrong copy. Runtime-ADDED keys drop — width subtyping in
|
|
@@ -4584,7 +4630,7 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4584
4630
|
let value;
|
|
4585
4631
|
if (obj.type.kind === "dyn") {
|
|
4586
4632
|
if (!canDynCheckTo(f.type, (id) => L.shapes.get(id), (id) => L.unions.get(id))) {
|
|
4587
|
-
L.unsupported("SC1100", prop, `object spread of a checked-dynamic source whose field '${f.name}' ('${L.fmt(f.type)}') cannot validate out of the
|
|
4633
|
+
L.unsupported("SC1100", prop, `object spread of a checked-dynamic source whose field '${f.name}' ('${L.fmt(f.type)}') cannot validate out of the checked-dynamic tree (copy the fields explicitly)`);
|
|
4588
4634
|
}
|
|
4589
4635
|
value = {
|
|
4590
4636
|
kind: "dynCheck",
|
|
@@ -4723,7 +4769,7 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4723
4769
|
// lowering: a union field with one array-family arm builds the
|
|
4724
4770
|
// literal AS that arm (lowerExprExpecting's IR-directed rule —
|
|
4725
4771
|
// the option-table `default: [{ value: [] }]` shape), where the
|
|
4726
|
-
// bare lowering would take the JS
|
|
4772
|
+
// bare lowering would take the JS dyn fallback and fence.
|
|
4727
4773
|
let init = prop.initializer;
|
|
4728
4774
|
while (ts.isParenthesizedExpression(init))
|
|
4729
4775
|
init = init.expression;
|
|
@@ -4768,7 +4814,7 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4768
4814
|
}
|
|
4769
4815
|
if (!fieldType) {
|
|
4770
4816
|
// Overflow entry: the value flows into the index signature's value
|
|
4771
|
-
// slot — dyn slots take a
|
|
4817
|
+
// slot — dyn slots take a dyn conversion (dynFrom), typed slots the
|
|
4772
4818
|
// ordinary coercion path. Later duplicates override (map semantics
|
|
4773
4819
|
// are last-write-wins already; a duplicate literal key is a tsc
|
|
4774
4820
|
// error anyway).
|
|
@@ -4810,7 +4856,7 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4810
4856
|
for (const f of shape.fields) {
|
|
4811
4857
|
if (provided.has(f.name))
|
|
4812
4858
|
continue;
|
|
4813
|
-
// 'unknown' fields complete with the
|
|
4859
|
+
// 'unknown' fields complete with the dyn undefined — the absent
|
|
4814
4860
|
// property reads as undefined in Node, and a dyn slot holds
|
|
4815
4861
|
// exactly that (the options-record call shape against
|
|
4816
4862
|
// `{ plugins: unknown, ... }` — a JS caller the checker admits).
|
|
@@ -5171,7 +5217,7 @@ export function lowerElementAccess(L, expr) {
|
|
|
5171
5217
|
// A never-tainted JS receiver type (neverTaintedJsType — `cmd[1]` on
|
|
5172
5218
|
// `const cmd = ['pwd', []]`, whose binding lowered checked-dynamic)
|
|
5173
5219
|
// dispatches as unmapped so the dyn-receiver branch below reads
|
|
5174
|
-
// through the
|
|
5220
|
+
// through the checked-dynamic tree instead of dynChecking into never's f64 residue.
|
|
5175
5221
|
const receiverIr = neverTaintedJsType(L, expr.expression, L.typeOf(expr.expression))
|
|
5176
5222
|
? null
|
|
5177
5223
|
: L.mapTypeOf(L.typeOf(expr.expression));
|
|
@@ -5179,7 +5225,7 @@ export function lowerElementAccess(L, expr) {
|
|
|
5179
5225
|
// Dispatch follows the RUNTIME world (383(d)): a checker-'any'
|
|
5180
5226
|
// receiver whose value LOWERED checked-dynamic (`bag.list[0]` where
|
|
5181
5227
|
// bag.list is a routed keyed read off a wrapped island value) takes
|
|
5182
|
-
// the
|
|
5228
|
+
// the dyn keyed read below — the routed JSVAL arm reads the real
|
|
5183
5229
|
// engine element; a jsval-lowered receiver keeps the island read.
|
|
5184
5230
|
const recv = L.lowerExpr(expr.expression);
|
|
5185
5231
|
if (recv.type.kind !== "dyn")
|
|
@@ -5258,7 +5304,7 @@ export function lowerElementAccess(L, expr) {
|
|
|
5258
5304
|
}
|
|
5259
5305
|
}
|
|
5260
5306
|
// `pkg["k"]` / `scripts[name]` / `scopeMatch[1]` on a dyn receiver (a
|
|
5261
|
-
// JSON.parse result): the
|
|
5307
|
+
// JSON.parse result): the dyn keyed read, exactly the dot form.
|
|
5262
5308
|
// NUMBER-typed indices convert through ToString first — JS property
|
|
5263
5309
|
// keys are strings, and the canonical number text answers array
|
|
5264
5310
|
// indices in the helper (fractions, negatives, and NaN read as
|
|
@@ -5368,7 +5414,7 @@ export function lowerElementAccess(L, expr) {
|
|
|
5368
5414
|
return islandElementRead(L, expr, arr);
|
|
5369
5415
|
// The checker sees an array but the VALUE lowered checked-dynamic (a
|
|
5370
5416
|
// jsdoc-typed default export from a .js module — signature 14): the
|
|
5371
|
-
// read rides the dynCheck boundary when the array shape is one the
|
|
5417
|
+
// read rides the dynCheck boundary when the array shape is one the checked-dynamic tree
|
|
5372
5418
|
// can validate, and fences by name when it is not — an arrayGet over a
|
|
5373
5419
|
// dyn receiver is never emitted (the validator ICE).
|
|
5374
5420
|
if (arr.type.kind === "dyn") {
|
|
@@ -5444,7 +5490,7 @@ function islandElementRead(L, expr, obj) {
|
|
|
5444
5490
|
* the index signature's value type (dyn for `unknown`), or its
|
|
5445
5491
|
* undefined-armed union under noUncheckedIndexedAccess. Every declared
|
|
5446
5492
|
* field must be able to SURFACE as that type (equal, an arm of it, or —
|
|
5447
|
-
* for dyn results — JSON-safe for the
|
|
5493
|
+
* for dyn results — JSON-safe for the dyn conversion); shapes mixing in
|
|
5448
5494
|
* fields outside that stay fenced. Declared-only shapes support reads
|
|
5449
5495
|
* whose key type proves membership (tsc's keyof check): all fields must
|
|
5450
5496
|
* share the result type, and a smuggled miss traps. */
|
|
@@ -5463,9 +5509,9 @@ export function lowerRecordKeyRead(L, expr, shapeId, shape) {
|
|
|
5463
5509
|
// The receiver lowers FIRST (both branches below read it, and JS
|
|
5464
5510
|
// evaluates the receiver before the key).
|
|
5465
5511
|
const obj = L.lowerExpr(expr.expression);
|
|
5466
|
-
// A record-mapped CHECKER type over a VALUE living in the
|
|
5512
|
+
// A record-mapped CHECKER type over a VALUE living in the checked-dynamic tree (a JS
|
|
5467
5513
|
// file-scope object-literal global): the checked-dynamic keyed read —
|
|
5468
|
-
// dynKeyGet against the runtime keys (a missing key answers the
|
|
5514
|
+
// dynKeyGet against the runtime keys (a missing key answers the checked-dynamic tree
|
|
5469
5515
|
// undefined, exactly JS); consumers validate (dynCheck) where a
|
|
5470
5516
|
// static type is required, the member-read discipline.
|
|
5471
5517
|
if (obj.type.kind === "dyn") {
|
|
@@ -5574,8 +5620,8 @@ export function recordKeyTypeLiteralText(L, node) {
|
|
|
5574
5620
|
}
|
|
5575
5621
|
/** Can every value a dynamic key can reach (declared fields + the
|
|
5576
5622
|
* overflow) surface as the read's result type? dyn results need
|
|
5577
|
-
*
|
|
5578
|
-
* the top — an optional field's undefined becomes the undefined
|
|
5623
|
+
* dyn-convertible fields (JSON-safe, with the undefined arm allowed at
|
|
5624
|
+
* the top — an optional field's undefined becomes the undefined dyn
|
|
5579
5625
|
* value, exactly what the missing-key path produces); typed results need
|
|
5580
5626
|
* each field to be the type itself or one of its arms, and the overflow
|
|
5581
5627
|
* value to be the type or wrappable into it. */
|
|
@@ -5643,7 +5689,7 @@ export function lowerElementWrite(L, expr) {
|
|
|
5643
5689
|
if (receiverIr?.kind === "jsval") {
|
|
5644
5690
|
const obj = L.lowerExpr(target.expression);
|
|
5645
5691
|
// Dispatch follows the RUNTIME world (383(d)): a checker-'any'
|
|
5646
|
-
// receiver whose value LOWERED checked-dynamic takes the
|
|
5692
|
+
// receiver whose value LOWERED checked-dynamic takes the dyn keyed
|
|
5647
5693
|
// write — the routed JSVAL arm lands it on the real engine object.
|
|
5648
5694
|
if (obj.type.kind === "dyn") {
|
|
5649
5695
|
const loc = locOf(expr);
|
|
@@ -5670,12 +5716,12 @@ export function lowerElementWrite(L, expr) {
|
|
|
5670
5716
|
return { kind: "exprStmt", expr: { kind: "jsOp", op: "setIdx", args: [obj, key, value], type: VOID, loc }, loc };
|
|
5671
5717
|
}
|
|
5672
5718
|
// A checked-dynamic receiver TYPE (`unknown[]` and the collapsed
|
|
5673
|
-
// `(string | object)[]` map to DYN wholesale now): the
|
|
5719
|
+
// `(string | object)[]` map to DYN wholesale now): the dyn keyed
|
|
5674
5720
|
// write — dyn.keySet. Number keys canonicalize through the JS-exact
|
|
5675
5721
|
// formatter; ARR receivers take canonical index keys as element
|
|
5676
5722
|
// set/extend (undefined-hole padding, JS's length growth exactly),
|
|
5677
5723
|
// OBJ receivers set the member, and the runtime throws Node's
|
|
5678
|
-
// TypeErrors on every other kind. Values convert into the
|
|
5724
|
+
// TypeErrors on every other kind. Values convert into the checked-dynamic tree;
|
|
5679
5725
|
// unconvertible ones fence per site (the dynFrom stance).
|
|
5680
5726
|
if (receiverIr?.kind === "dyn") {
|
|
5681
5727
|
const obj = L.lowerExpr(target.expression);
|
|
@@ -5689,7 +5735,7 @@ export function lowerElementWrite(L, expr) {
|
|
|
5689
5735
|
}
|
|
5690
5736
|
const value = L.coerceToExpected(L.lowerExpr(expr.right), DYN);
|
|
5691
5737
|
if (value.type.kind !== "dyn") {
|
|
5692
|
-
L.unsupported("SC1101", expr.right, `storing '${L.fmt(value.type)}' values in a checked-dynamic array (the value cannot convert into the
|
|
5738
|
+
L.unsupported("SC1101", expr.right, `storing '${L.fmt(value.type)}' values in a checked-dynamic array (the value cannot convert into the checked-dynamic tree)`);
|
|
5693
5739
|
}
|
|
5694
5740
|
return { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet", args: [obj, key, value], type: VOID, loc }, loc };
|
|
5695
5741
|
}
|
|
@@ -5729,11 +5775,11 @@ export function lowerElementWrite(L, expr) {
|
|
|
5729
5775
|
const loc = locOf(expr);
|
|
5730
5776
|
return { kind: "exprStmt", expr: { kind: "jsOp", op: "setIdx", args: [obj, key, value], type: VOID, loc }, loc };
|
|
5731
5777
|
}
|
|
5732
|
-
// A record-mapped CHECKER type over a VALUE living in the
|
|
5778
|
+
// A record-mapped CHECKER type over a VALUE living in the checked-dynamic tree (a
|
|
5733
5779
|
// JS file-scope object-literal global): the checked-dynamic keyed
|
|
5734
5780
|
// write — dyn.keySet (later writes win, insertion order; Node's
|
|
5735
5781
|
// TypeErrors on non-object receivers), the value converting into
|
|
5736
|
-
// the
|
|
5782
|
+
// the checked-dynamic tree. Literal and runtime keys alike: the checked-dynamic tree's key set is
|
|
5737
5783
|
// open, so no declared-field collision analysis applies.
|
|
5738
5784
|
if (obj.type.kind === "dyn") {
|
|
5739
5785
|
const loc = locOf(expr);
|
|
@@ -5748,7 +5794,7 @@ export function lowerElementWrite(L, expr) {
|
|
|
5748
5794
|
}
|
|
5749
5795
|
const value = L.coerceToExpected(L.lowerExpr(expr.right), DYN);
|
|
5750
5796
|
if (value.type.kind !== "dyn") {
|
|
5751
|
-
L.unsupported("SC1101", expr.right, `storing '${L.fmt(value.type)}' values in a checked-dynamic object (the value cannot convert into the
|
|
5797
|
+
L.unsupported("SC1101", expr.right, `storing '${L.fmt(value.type)}' values in a checked-dynamic object (the value cannot convert into the checked-dynamic tree)`);
|
|
5752
5798
|
}
|
|
5753
5799
|
return { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet", args: [obj, key, value], type: VOID, loc }, loc };
|
|
5754
5800
|
}
|
|
@@ -5836,7 +5882,7 @@ export function lowerElementWrite(L, expr) {
|
|
|
5836
5882
|
// A LITERAL key naming no declared field is a pure overflow insert
|
|
5837
5883
|
// — no collision to validate. Runtime keys must be able to collide
|
|
5838
5884
|
// with every declared field: dyn slots validate through the
|
|
5839
|
-
// dynCheck walker (fields must be
|
|
5885
|
+
// dynCheck walker (fields must be dyn-convertible — the same
|
|
5840
5886
|
// convertibility the read needs); typed slots write through
|
|
5841
5887
|
// directly, so every field must BE the index-value type.
|
|
5842
5888
|
const overflowOnly = litKey !== null;
|
|
@@ -5875,7 +5921,7 @@ export function lowerElementWrite(L, expr) {
|
|
|
5875
5921
|
// `result[key] = value`): dyn.keySet, exactly the record-mapped dyn
|
|
5876
5922
|
// arm above — later writes win in insertion order, number keys
|
|
5877
5923
|
// canonicalize through the JS-exact formatter (ToPropertyKey's string
|
|
5878
|
-
// side), index keys on
|
|
5924
|
+
// side), index keys on dyn arrays set/extend elements, and non-object
|
|
5879
5925
|
// receivers throw Node's TypeErrors at runtime. An UNMAPPED checker
|
|
5880
5926
|
// type (static `any` — mapTypeOf answers null without --dynamic)
|
|
5881
5927
|
// probes the receiver's own lowered world: a dyn value takes the same
|
|
@@ -5898,7 +5944,7 @@ export function lowerElementWrite(L, expr) {
|
|
|
5898
5944
|
}
|
|
5899
5945
|
const value = L.coerceToExpected(L.lowerExpr(expr.right), DYN);
|
|
5900
5946
|
if (value.type.kind !== "dyn") {
|
|
5901
|
-
L.unsupported("SC1101", expr.right, `storing '${L.fmt(value.type)}' values in a checked-dynamic object (the value cannot convert into the
|
|
5947
|
+
L.unsupported("SC1101", expr.right, `storing '${L.fmt(value.type)}' values in a checked-dynamic object (the value cannot convert into the checked-dynamic tree)`);
|
|
5902
5948
|
}
|
|
5903
5949
|
return { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet", args: [obj, key, value], type: VOID, loc }, loc };
|
|
5904
5950
|
}
|
|
@@ -5932,7 +5978,7 @@ export function ensureString(L, e, node) {
|
|
|
5932
5978
|
if (e.type.kind === "string")
|
|
5933
5979
|
return e;
|
|
5934
5980
|
if (e.type.kind === "dyn") {
|
|
5935
|
-
// String(u) / `${u}`: a runtime dispatch over the
|
|
5981
|
+
// String(u) / `${u}`: a runtime dispatch over the dyn kind — Node's
|
|
5936
5982
|
// String() exactly (undefined/null texts, JS number formatting,
|
|
5937
5983
|
// strings verbatim, arrays via join, objects as "[object Object]").
|
|
5938
5984
|
return { kind: "toString", operand: e, type: STRING, loc: e.loc };
|
|
@@ -6058,7 +6104,7 @@ export function lowerTemplate(L, expr) {
|
|
|
6058
6104
|
* documented divergence: a lying cast throws instead of corrupting
|
|
6059
6105
|
* memory);
|
|
6060
6106
|
* - dyn → anything else (closures, class instances, void) is rejected:
|
|
6061
|
-
* those types cannot be found inside a JSON
|
|
6107
|
+
* those types cannot be found inside a JSON dyn. */
|
|
6062
6108
|
/** `e as T` and the old-style assertion `<T>e` — one node shape (both
|
|
6063
6109
|
* carry `.type` and `.expression`), one lowering. */
|
|
6064
6110
|
export function lowerAsExpression(L, expr) {
|
|
@@ -6162,7 +6208,7 @@ export function lowerAsExpression(L, expr) {
|
|
|
6162
6208
|
return inner; // `as unknown`: erasure
|
|
6163
6209
|
if (target.kind === "void" || !L.jsonSafe(target)) {
|
|
6164
6210
|
// Bare undefined-armed targets pass when every OTHER arm is
|
|
6165
|
-
// JSON-safe: the
|
|
6211
|
+
// JSON-safe: the checked-dynamic tree holds a first-class undefined value now
|
|
6166
6212
|
// (index-signature overflow reads produce it for missing keys), and
|
|
6167
6213
|
// the undefined arm matches exactly it — `p[key] as string |
|
|
6168
6214
|
// undefined` is the missing-key idiom. Parsed JSON still never
|
|
@@ -6171,7 +6217,7 @@ export function lowerAsExpression(L, expr) {
|
|
|
6171
6217
|
if (target.kind === "union" && L.dynConvertible(target)) {
|
|
6172
6218
|
return { kind: "dynCheck", value: inner, type: target, loc: locOf(expr) };
|
|
6173
6219
|
}
|
|
6174
|
-
// Uint8Array targets: the
|
|
6220
|
+
// Uint8Array targets: the checked-dynamic tree carries a bytes kind now (converted
|
|
6175
6221
|
// stdin chunks) — the extraction validates the kind and copies out.
|
|
6176
6222
|
if (target.kind === "bytes" && target.elem === "u8") {
|
|
6177
6223
|
return { kind: "dynCheck", value: inner, type: target, loc: locOf(expr) };
|
|
@@ -6194,7 +6240,7 @@ export function lowerAsExpression(L, expr) {
|
|
|
6194
6240
|
// — the errno-probing idiom): there is nothing to validate (every
|
|
6195
6241
|
// field is unknown, exactly what the dyn value already answers) and
|
|
6196
6242
|
// nothing to build — the cast is pure typing, so it ERASES and the
|
|
6197
|
-
// reads ride the
|
|
6243
|
+
// reads ride the dyn keyed read.
|
|
6198
6244
|
if (target.kind === "record") {
|
|
6199
6245
|
const shape = L.shapes.get(target.shapeId);
|
|
6200
6246
|
if (shape &&
|
|
@@ -6355,7 +6401,7 @@ export function lowerBinary(L, expr) {
|
|
|
6355
6401
|
}
|
|
6356
6402
|
// `events.defaultMaxListeners = v` — the module-property write
|
|
6357
6403
|
// Node validates (validateNumber(n, 'defaultMaxListeners', 0)):
|
|
6358
|
-
// the value crosses into the
|
|
6404
|
+
// the value crosses into the checked-dynamic tree and the runtime ladder throws
|
|
6359
6405
|
// ERR_INVALID_ARG_TYPE / ERR_OUT_OF_RANGE with Node's exact slot
|
|
6360
6406
|
// name; valid numbers apply. The expression's value is the RHS
|
|
6361
6407
|
// (JS's assignment yield).
|
|
@@ -6528,8 +6574,8 @@ export function lowerBinary(L, expr) {
|
|
|
6528
6574
|
}
|
|
6529
6575
|
if (left.type.kind === "dyn" || right.type.kind === "dyn") {
|
|
6530
6576
|
// A checked-dynamic operand (`fn.name || '<anonymous>'` —
|
|
6531
|
-
// test/common's _mustCallInner): both sides live in the
|
|
6532
|
-
// the deciding test is ToBoolean over the
|
|
6577
|
+
// test/common's _mustCallInner): both sides live in the checked-dynamic tree and
|
|
6578
|
+
// the deciding test is ToBoolean over the dyn kind
|
|
6533
6579
|
// (scr_dyn_truthy) — JS value semantics exactly, result dyn. The
|
|
6534
6580
|
// non-dyn side converts through the usual boundary; a value with
|
|
6535
6581
|
// no dyn representation keeps the fence.
|
|
@@ -6665,7 +6711,7 @@ export function lowerBinary(L, expr) {
|
|
|
6665
6711
|
const right = L.lowerExpr(expr.right);
|
|
6666
6712
|
if (left.type.kind === "dyn" || right.type.kind === "dyn") {
|
|
6667
6713
|
// The narrowing unit comparisons ARE answerable on unknown: `v ===
|
|
6668
|
-
// undefined` / `v !== null` test the
|
|
6714
|
+
// undefined` / `v !== null` test the dyn node's kind directly, and
|
|
6669
6715
|
// tsc's control flow narrows the branches (reads then bridge through
|
|
6670
6716
|
// maybeNarrow's validated extraction).
|
|
6671
6717
|
if (op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
@@ -6685,14 +6731,14 @@ export function lowerBinary(L, expr) {
|
|
|
6685
6731
|
}
|
|
6686
6732
|
// dyn vs SCALAR strict equality (`value !== ""`, `u === 5` — the
|
|
6687
6733
|
// normalizePricing filter): a guarded kind test + payload compare,
|
|
6688
|
-
// JS-exact (strict equality never coerces; a non-matching
|
|
6734
|
+
// JS-exact (strict equality never coerces; a non-matching dyn kind
|
|
6689
6735
|
// answers false). dyn vs dyn keeps the fence below.
|
|
6690
6736
|
const dynSide = left.type.kind === "dyn" ? left : right;
|
|
6691
6737
|
const scalarSide = dynSide === left ? right : left;
|
|
6692
6738
|
if (dynSide.type.kind === "dyn" &&
|
|
6693
6739
|
(scalarSide.type.kind === "f64" || scalarSide.type.kind === "string" || scalarSide.type.kind === "bool" ||
|
|
6694
6740
|
// dyn vs dyn (`context.actual !== context.exact` —
|
|
6695
|
-
// test/common's exit accounting): the runtime's whole-
|
|
6741
|
+
// test/common's exit accounting): the runtime's whole-dyn
|
|
6696
6742
|
// strict equality — scalars by value, units by kind,
|
|
6697
6743
|
// reference kinds by node identity (scr_dyn_strict_eq).
|
|
6698
6744
|
scalarSide.type.kind === "dyn")) {
|
|
@@ -6747,7 +6793,7 @@ export function lowerBinary(L, expr) {
|
|
|
6747
6793
|
}
|
|
6748
6794
|
if (other.type.kind === "string") {
|
|
6749
6795
|
// String-context `+`: JS's answer is String(unknown) — the
|
|
6750
|
-
// JS-exact
|
|
6796
|
+
// JS-exact dyn walker (numbers format, arrays join, objects
|
|
6751
6797
|
// print [object Object], handles the same) — never a checked
|
|
6752
6798
|
// cast: `'status ' + res.statusCode` concatenates like Node.
|
|
6753
6799
|
const strOf = (e) => e.type.kind === "dyn" ? { kind: "toString", operand: e, type: STRING, loc: e.loc } : e;
|
|
@@ -6765,7 +6811,7 @@ export function lowerBinary(L, expr) {
|
|
|
6765
6811
|
L.anyOpFence(`the '${ts.tokenToString(op) ?? ts.SyntaxKind[op]}' operator`, expr);
|
|
6766
6812
|
}
|
|
6767
6813
|
// tsc allows ===/!== on unknown (arithmetic/comparisons it rejects
|
|
6768
|
-
// itself); a dynamic equality would need a
|
|
6814
|
+
// itself); a dynamic equality would need a dyn walk — validate first.
|
|
6769
6815
|
L.unsupported("SC1100", expr, "operators on 'unknown' values");
|
|
6770
6816
|
}
|
|
6771
6817
|
// Operators over 'any' execute in the island with JS-exact semantics
|
|
@@ -7303,7 +7349,7 @@ export function lowerUnionTypeofTest(L, expr, loc) {
|
|
|
7303
7349
|
return null;
|
|
7304
7350
|
}
|
|
7305
7351
|
/** `typeof v === "lit"` / `typeof v !== "lit"` where v is `unknown`-typed
|
|
7306
|
-
* (dyn): the runtime kind test over the
|
|
7352
|
+
* (dyn): the runtime kind test over the dyn node's tag. Only the kinds a
|
|
7307
7353
|
* later read can bridge narrow ("string"/"number"/"boolean") plus
|
|
7308
7354
|
* "undefined" (no payload to read); "object"/"function" tests keep the
|
|
7309
7355
|
* fence — an object-narrowed `unknown` read has no lowering anyway (a
|
|
@@ -7387,7 +7433,7 @@ export function lowerDynTypeofTest(L, expr, loc) {
|
|
|
7387
7433
|
loc,
|
|
7388
7434
|
};
|
|
7389
7435
|
}
|
|
7390
|
-
// `typeof v === "object"`: the
|
|
7436
|
+
// `typeof v === "object"`: the dyn answers exactly (object, array,
|
|
7391
7437
|
// bytes, and null kinds — JS's oldest wart preserved). tsc narrows
|
|
7392
7438
|
// the branch to `object | null`; reads past the narrow take the
|
|
7393
7439
|
// checked-cast path per site.
|
|
@@ -7401,7 +7447,7 @@ export function lowerDynTypeofTest(L, expr, loc) {
|
|
|
7401
7447
|
loc,
|
|
7402
7448
|
};
|
|
7403
7449
|
}
|
|
7404
|
-
// `typeof v === "function"`: a REAL runtime test since the
|
|
7450
|
+
// `typeof v === "function"`: a REAL runtime test since the checked-dynamic tree's
|
|
7405
7451
|
// function kind exists (boxed closures — the mustCall guard
|
|
7406
7452
|
// `if (typeof fn !== 'function') throw` answers honestly).
|
|
7407
7453
|
if (b.text === "function") {
|
|
@@ -7564,7 +7610,7 @@ export function probeLower(L, node) {
|
|
|
7564
7610
|
* over a hierarchy class, `typeof` over a primitive), the read bridges
|
|
7565
7611
|
* with a kind-unchecked `caughtNarrow` extraction (trust-the-checker,
|
|
7566
7612
|
* exactly like unionNarrow). Every OTHER read is the narrowness fence:
|
|
7567
|
-
* the binding's payload is a typed exception snapshot, not a dyn
|
|
7613
|
+
* the binding's payload is a typed exception snapshot, not a dyn, so
|
|
7568
7614
|
* un-narrowed uses have nothing sound to lower to. */
|
|
7569
7615
|
export function caughtRead(L, node, local, loc) {
|
|
7570
7616
|
const ref = { kind: "varRef", localId: local.id, type: CAUGHT, loc };
|
|
@@ -7580,10 +7626,10 @@ export function caughtRead(L, node, local, loc) {
|
|
|
7580
7626
|
}
|
|
7581
7627
|
}
|
|
7582
7628
|
// An UN-narrowed use — the occurrence still types `unknown` — converts
|
|
7583
|
-
// to a dyn
|
|
7629
|
+
// to a dyn value (`options.onError?.(error)` — the caught snapshot
|
|
7584
7630
|
// flowing into an unknown slot): the typed→unknown deep-copy stance
|
|
7585
7631
|
// extended to exception payloads. Error payloads keep their
|
|
7586
|
-
// observability (instanceof Error / .message / String() — the
|
|
7632
|
+
// observability (instanceof Error / .message / String() — the checked-dynamic tree's
|
|
7587
7633
|
// error encoding); other object payloads are type-erased at runtime and
|
|
7588
7634
|
// convert to the "[object Object]" approximation — SEMANTICS.md 67.
|
|
7589
7635
|
if (narrowed?.kind === "dyn") {
|
|
@@ -7689,14 +7735,14 @@ export function lowerInstanceOf(L, expr, loc) {
|
|
|
7689
7735
|
L.builtinStreamInfoOf(rhsMemberSymbol) ??
|
|
7690
7736
|
undefined;
|
|
7691
7737
|
if (!target) {
|
|
7692
|
-
// `u instanceof Uint8Array` on an `unknown` value: the
|
|
7738
|
+
// `u instanceof Uint8Array` on an `unknown` value: the checked-dynamic tree carries a
|
|
7693
7739
|
// bytes kind — one runtime tag test, and tsc's narrowing types the
|
|
7694
7740
|
// true branch (reads bridge through maybeNarrow's validated
|
|
7695
7741
|
// extraction, like the typeof tests). Node's Buffer IS a Uint8Array
|
|
7696
7742
|
// subclass and rides the same bytes kind, so both worlds answer true
|
|
7697
7743
|
// for Buffer payloads — Node-exact (the bytes kind's other
|
|
7698
7744
|
// divergences are SEMANTICS.md 45). Catch bindings stay out (their
|
|
7699
|
-
// payload is a typed snapshot, not a
|
|
7745
|
+
// payload is a typed snapshot, not a dyn).
|
|
7700
7746
|
if (ts.isIdentifier(expr.right) &&
|
|
7701
7747
|
L.isStdlibGlobal(expr.right, "Uint8Array") &&
|
|
7702
7748
|
!L.caughtLocalOf(expr.left)) {
|
|
@@ -7787,7 +7833,7 @@ export function lowerInstanceOf(L, expr, loc) {
|
|
|
7787
7833
|
};
|
|
7788
7834
|
}
|
|
7789
7835
|
const left = L.lowerExpr(expr.left);
|
|
7790
|
-
// `u instanceof Error` on an `unknown` value: the
|
|
7836
|
+
// `u instanceof Error` on an `unknown` value: the checked-dynamic tree's error encoding
|
|
7791
7837
|
// (the shape caughtToDyn builds for Error payloads — the reserved
|
|
7792
7838
|
// "%error" marker) answers the test, so a caught Error passed through
|
|
7793
7839
|
// an unknown slot narrows like Node (`error instanceof Error ?
|
|
@@ -7800,7 +7846,7 @@ export function lowerInstanceOf(L, expr, loc) {
|
|
|
7800
7846
|
return { kind: "dynTest", test: "error", value: left, type: BOOL, loc };
|
|
7801
7847
|
}
|
|
7802
7848
|
// `u instanceof TypeError` (and the other BUILTIN error classes) on a
|
|
7803
|
-
// dyn value: the from_error cache holds the
|
|
7849
|
+
// dyn value: the from_error cache holds the checked-dynamic tree↔error identity edge,
|
|
7804
7850
|
// so the runtime resolves the encoding back to its error and asks the
|
|
7805
7851
|
// vtable's stamped interval — exact for every error that crossed the
|
|
7806
7852
|
// boundary (a hand-built {%error} literal answers false: subclass
|
|
@@ -8093,7 +8139,7 @@ export function lowerInExpression(L, expr, loc) {
|
|
|
8093
8139
|
}
|
|
8094
8140
|
}
|
|
8095
8141
|
// A dyn receiver (`"portless" in pkg` after the `typeof pkg ===
|
|
8096
|
-
// "object"` guard): own-member presence on the
|
|
8142
|
+
// "object"` guard): own-member presence on the checked-dynamic tree — tsc admits `in`
|
|
8097
8143
|
// only on object-typed operands, so unit receivers are unreachable.
|
|
8098
8144
|
if (recv.type.kind === "dyn") {
|
|
8099
8145
|
return { kind: "dynHasKey", key, value: recv, type: BOOL, loc };
|
|
@@ -8831,8 +8877,8 @@ export function lowerUnionProperty(L, expr) {
|
|
|
8831
8877
|
// fallback's discipline.
|
|
8832
8878
|
// A checker-union receiver whose VALUE lowered checked-dynamic (a
|
|
8833
8879
|
// never-tainted JS chain — `cmd[1].length` on `const cmd = ['pwd',
|
|
8834
|
-
// []]`, where the element read stayed a
|
|
8835
|
-
//
|
|
8880
|
+
// []]`, where the element read stayed a dyn node): read through the
|
|
8881
|
+
// dyn keyed read like the unmappable-receiver path below the chain.
|
|
8836
8882
|
if (value.type.kind === "dyn") {
|
|
8837
8883
|
const key = { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) };
|
|
8838
8884
|
return { kind: "dynKeyGet", key, value, type: DYN, loc: locOf(expr) };
|
|
@@ -9219,9 +9265,9 @@ export function symbolFieldTarget(L, expr) {
|
|
|
9219
9265
|
* tsc-clean (the property types as the setter's param), but Node yields
|
|
9220
9266
|
* undefined, which these property types cannot represent. */
|
|
9221
9267
|
export function fieldGetExpr(L, target, loc, blame) {
|
|
9222
|
-
// A record-shaped CHECKER target whose receiver VALUE lives in the
|
|
9268
|
+
// A record-shaped CHECKER target whose receiver VALUE lives in the checked-dynamic tree
|
|
9223
9269
|
// (a JS file-scope object-literal global): the checked-dynamic keyed
|
|
9224
|
-
// read — dynKeyGet (a missing key answers the
|
|
9270
|
+
// read — dynKeyGet (a missing key answers the dyn undefined, exactly
|
|
9225
9271
|
// JS); consumers validate (dynCheck) where a static type is required.
|
|
9226
9272
|
if ((target.container === "record" || target.container === "recordOvf") &&
|
|
9227
9273
|
target.obj.type.kind === "dyn") {
|
|
@@ -9302,15 +9348,15 @@ export function fieldGetExpr(L, target, loc, blame) {
|
|
|
9302
9348
|
* call). A write to a getter-only property never gets here in a clean
|
|
9303
9349
|
* program (tsc's TS2540 is the fence); the rejection is the backstop. */
|
|
9304
9350
|
export function fieldSetStmt(L, target, value, loc, blame) {
|
|
9305
|
-
// A record-shaped CHECKER target whose receiver VALUE lives in the
|
|
9351
|
+
// A record-shaped CHECKER target whose receiver VALUE lives in the checked-dynamic tree:
|
|
9306
9352
|
// the checked-dynamic keyed write — dyn.keySet (later writes win,
|
|
9307
9353
|
// insertion order; Node's TypeErrors on non-object receivers), the
|
|
9308
|
-
// value converting into the
|
|
9354
|
+
// value converting into the checked-dynamic tree.
|
|
9309
9355
|
if ((target.container === "record" || target.container === "recordOvf") &&
|
|
9310
9356
|
target.obj.type.kind === "dyn") {
|
|
9311
9357
|
const v = L.coerceToExpected(value, DYN);
|
|
9312
9358
|
if (v.type.kind !== "dyn") {
|
|
9313
|
-
L.unsupported("SC1101", blame, `storing '${L.fmt(value.type)}' values in a checked-dynamic object (the value cannot convert into the
|
|
9359
|
+
L.unsupported("SC1101", blame, `storing '${L.fmt(value.type)}' values in a checked-dynamic object (the value cannot convert into the checked-dynamic tree)`);
|
|
9314
9360
|
}
|
|
9315
9361
|
return {
|
|
9316
9362
|
kind: "exprStmt",
|
|
@@ -9398,7 +9444,7 @@ export function lowerPromiseRejectCall(L, call, access) {
|
|
|
9398
9444
|
const type = ctxT ? L.mapTypeOf(ctxT) : null;
|
|
9399
9445
|
const reasonNode = call.arguments[0];
|
|
9400
9446
|
// A CHECKED-DYNAMIC reason (`Promise.reject(value)` where value rode
|
|
9401
|
-
// an untyped binding — the tracingChannel suite's shape): the
|
|
9447
|
+
// an untyped binding — the tracingChannel suite's shape): the checked-dynamic tree
|
|
9402
9448
|
// value IS the rejection payload (the thrown-dyn representation, so
|
|
9403
9449
|
// identity survives to catch/unhandledRejection observers), and the
|
|
9404
9450
|
// result is promise<dyn> when no context names a concrete one.
|
|
@@ -9541,7 +9587,7 @@ export function lowerFieldCompound(L, access, op, rhsNode, loc) {
|
|
|
9541
9587
|
const concat = {
|
|
9542
9588
|
kind: "strConcat",
|
|
9543
9589
|
// String-context read: JS's String(unknown) over the field —
|
|
9544
|
-
// the JS-exact
|
|
9590
|
+
// the JS-exact dyn walker, never a checked cast.
|
|
9545
9591
|
left: { kind: "toString", operand: read, type: STRING, loc },
|
|
9546
9592
|
right: rhs,
|
|
9547
9593
|
type: STRING,
|