@scriptc/compiler 0.0.8 → 0.0.10
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 +13 -0
- package/dist/backend/cc.js +14 -0
- package/dist/backend/cc.js.map +1 -1
- package/dist/backend/emission/emit-exprs.js +244 -17
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-types.d.ts +3 -0
- package/dist/backend/emission/emit-types.js +12 -0
- package/dist/backend/emission/emit-types.js.map +1 -1
- package/dist/backend/emission/emit-walkers.d.ts +7 -5
- package/dist/backend/emission/emit-walkers.js +52 -12
- package/dist/backend/emission/emit-walkers.js.map +1 -1
- package/dist/backend/emission/emitter.d.ts +1 -1
- package/dist/backend/emission/emitter.js +30 -9
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +1 -0
- package/dist/backend/llvm/dyn.js +83 -1
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +357 -20
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +73 -14
- package/dist/diagnostics/diagnostic.js +112 -31
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/render.js +8 -0
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.js +11 -1
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.js +16 -0
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +24 -0
- package/dist/frontend/lowering/lower-builtins.js +256 -3
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +71 -11
- package/dist/frontend/lowering/lower-calls.js +942 -18
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +27 -1
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +21 -2
- package/dist/frontend/lowering/lower-containers.js +386 -53
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +92 -17
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-emitter.js +54 -0
- package/dist/frontend/lowering/lower-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +231 -17
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +33 -2
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +25 -11
- package/dist/frontend/lowering/lower-namespaces.js +50 -15
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +211 -4
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +1 -5
- package/dist/frontend/lowering/lower-stmts.js +660 -19
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +92 -5
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +102 -15
- package/dist/frontend/lowering/lowerer.js +378 -30
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.js +20 -3
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm-static-rewrite.d.ts +7 -2
- package/dist/frontend/npm-static-rewrite.js +566 -138
- package/dist/frontend/npm-static-rewrite.js.map +1 -1
- package/dist/frontend/npm-static.js +11 -2
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/program.js +5 -5
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/shared.d.ts +6 -1
- package/dist/frontend/shared.js +46 -1
- package/dist/frontend/shared.js.map +1 -1
- package/dist/frontend/types.d.ts +13 -0
- package/dist/frontend/types.js +88 -9
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.js +169 -32
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +230 -12
- package/dist/ir/nodes.js +85 -6
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +109 -9
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/fence-eval.d.ts +77 -0
- package/dist/library/fence-eval.js +385 -0
- package/dist/library/fence-eval.js.map +1 -0
- package/dist/library/profile.d.ts +11 -1
- package/dist/library/profile.js +102 -18
- package/dist/library/profile.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +10 -3
|
@@ -10,15 +10,16 @@ import { BOOL, CAUGHT, DYN, DYN_HANDLE_KINDS, F64, JSVAL, NULL_T, REF_TRUTHY_KIN
|
|
|
10
10
|
import { cjsClassExprWholeExportOf, cjsExportAssignmentOf, cjsExportDiscardReason, isCjsExportTableLiteral, isCjsJsFile, isJsSourceFile, isModuleExportsAccess, isNodeEsmFile, locOf } from "../program.js";
|
|
11
11
|
import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstOf, builtinModuleFnOf, ISLAND_SURFACE, isChildSurfaceMember, MAP_METHODS, NARROW_FIRST, SET_METHODS, STR_METHODS, UNSUPPORTED_EXPR, sideEffectFreeOptionValue, stdlibGlobalNameOf } from "./surfaces.js";
|
|
12
12
|
import { blockedBindingUseDiag, recordShapeMismatchDiag, requiresDynamicPackageDiag, unsupportedDiag } from "../../diagnostics/diagnostic.js";
|
|
13
|
-
import { PoisonError, dynUndefinedExpr, jsFuncNameOf, neverTaintedJsType, own } from "./lowerer.js";
|
|
13
|
+
import { PoisonError, dynUndefinedExpr, jsFuncNameOf, neverTaintedJsType, nodeThrowExpr, own } from "./lowerer.js";
|
|
14
14
|
import { lowerIndexMergeHelper, lowerNpmStaticSafeIndexRead, strCharsCall } from "./lower-containers.js";
|
|
15
15
|
import { npmStaticPackageOfPath } from "../npm-static.js";
|
|
16
|
+
import { unsupportedModuleFeatureOf } from "../shared.js";
|
|
16
17
|
import { fenceEnumObjectValue, lowerEnumAccess } from "./lower-enums.js";
|
|
17
18
|
import { ambientNsRootOf, ambientUndefReadType, ambientUndefVarRootOf, ambientUndefinedFnSymbolOf, contextualUndefReadType, fenceEarlyAliasUse, fenceEarlyNsMemberRef, lowerNsIdentifierValue, nsMemberIdentOf, nsUndefRead, nsWritableTarget } from "./lower-namespaces.js";
|
|
18
19
|
import { expandoMemberRead, expandoWritableTarget } from "./lower-expando.js";
|
|
19
20
|
import { lowerSocketInstanceOf } from "./lower-server.js";
|
|
20
21
|
import { findGenericMethodOn, lowerStaticFieldRead } from "./lower-classes.js";
|
|
21
|
-
import { bindingNeverReassigned, implicitMonoFile, lowerTaggedTemplate, objLitGenericFnInfoOf, objLitGenericFnNodeOf, requireObjLitGenericReceiver } from "./lower-calls.js";
|
|
22
|
+
import { bindingNeverReassigned, implicitMonoFile, lowerTaggedTemplate, nullishGenericBindingUnitOf, objLitGenericFnInfoOf, objLitGenericFnNodeOf, requireObjLitGenericReceiver } from "./lower-calls.js";
|
|
22
23
|
import { mixinFnOfCallee } from "./lower-mixins.js";
|
|
23
24
|
import { isConstAssertionTypeNode, isGenericCallableMemberType, underConstAssertion, unitOnlyUnion } from "../types.js";
|
|
24
25
|
import { lowerYield } from "./lower-generators.js";
|
|
@@ -692,7 +693,7 @@ function lowerExprInner(L, expr) {
|
|
|
692
693
|
{
|
|
693
694
|
const spec = L.fencedBuiltinImportOf(expr);
|
|
694
695
|
if (spec !== null) {
|
|
695
|
-
L.pushDiag(unsupportedDiag("SC1010", loc,
|
|
696
|
+
L.pushDiag(unsupportedDiag("SC1010", loc, unsupportedModuleFeatureOf(spec)));
|
|
696
697
|
throw new PoisonError();
|
|
697
698
|
}
|
|
698
699
|
}
|
|
@@ -748,8 +749,9 @@ function lowerExprInner(L, expr) {
|
|
|
748
749
|
BigInt: "arbitrary-precision integers have no static representation — f64 is the one number type (Number.MAX_SAFE_INTEGER bounds exact integers)",
|
|
749
750
|
Proxy: "property-access metaprogramming has no static lowering (every property read must resolve at compile time)",
|
|
750
751
|
Reflect: "reflective property access has no static lowering — read and call members directly",
|
|
751
|
-
Intl: "locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data)",
|
|
752
|
+
Intl: "locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat(\"en-US\").format(x) and x.toLocaleString(\"en-US\") with default options",
|
|
752
753
|
SharedArrayBuffer: "no shared-memory threads exist in a compiled program — Uint8Array is the byte storage",
|
|
754
|
+
ArrayBuffer: "no free-standing ArrayBuffer value exists — typed arrays own their storage (new Uint8Array(n) allocates; new Uint8Array(new ArrayBuffer(n)) erases the buffer into the view)",
|
|
753
755
|
WeakRef: "deref()-after-collect exposes GC timing — genuinely dynamic; hold a strong reference instead",
|
|
754
756
|
FinalizationRegistry: "finalization callbacks expose GC timing — genuinely dynamic; release resources explicitly instead",
|
|
755
757
|
eval: "runtime code evaluation cannot be compiled ahead of time",
|
|
@@ -794,6 +796,18 @@ function lowerExprInner(L, expr) {
|
|
|
794
796
|
return nsUndefRead(L, expr.text, expr, t);
|
|
795
797
|
}
|
|
796
798
|
}
|
|
799
|
+
// A read of a TRAP binding — a declaration whose own initializer
|
|
800
|
+
// provably threw (module init unwound there), so this reference can
|
|
801
|
+
// never execute: any lowering is sound, and the trap keeps the
|
|
802
|
+
// shape honest. Typed by the use site when it maps, the F64 dummy
|
|
803
|
+
// otherwise (never observed — never even reached).
|
|
804
|
+
{
|
|
805
|
+
const sym = L.resolveValueSymbol(expr);
|
|
806
|
+
if (sym !== null && L.trapBindings.has(sym)) {
|
|
807
|
+
const t = ambientUndefReadType(L, expr) ?? contextualUndefReadType(L, expr) ?? F64;
|
|
808
|
+
return nsUndefRead(L, expr.text, expr, t);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
797
811
|
// A program CLASS NAME as a value: the classRef over the class's
|
|
798
812
|
// immortal class object (member accesses and construction never
|
|
799
813
|
// reach here — their hooks claim the property/new forms first).
|
|
@@ -1404,12 +1418,25 @@ function lowerExprInner(L, expr) {
|
|
|
1404
1418
|
// read (ARR answers length; everything else JS's own-property
|
|
1405
1419
|
// answer). Mapped receivers keep the fence-first order: their
|
|
1406
1420
|
// members' gaps are real surface gaps ([1,2].entries), not
|
|
1407
|
-
// representation artifacts.
|
|
1408
|
-
|
|
1421
|
+
// representation artifacts. `.length` on a receiver whose checker
|
|
1422
|
+
// ARRAY type lowers to the checked-dynamic representation —
|
|
1423
|
+
// `unknown[]`, the collapsed `(string | object)[]`, and the `any[]`
|
|
1424
|
+
// an Array.isArray guard narrows a collapsed union to — is the DOM
|
|
1425
|
+
// array's OWN length (a keyed read the ARR kind answers exactly),
|
|
1426
|
+
// never an `Array.prototype` surface gap; both source languages.
|
|
1427
|
+
// Prototype-method VALUE reads (`ps.map` unparenthesized) keep the
|
|
1428
|
+
// fence-first order: a stored-member undefined would mis-answer
|
|
1429
|
+
// them, and calls dispatch through the dyn method machinery
|
|
1430
|
+
// instead.
|
|
1431
|
+
if ((isJsSourceFile(expr.getSourceFile()) &&
|
|
1409
1432
|
(L.mapTypeOf(L.typeOf(expr.expression)) === null ||
|
|
1410
1433
|
// A never-tainted receiver type maps (never rides as f64) but
|
|
1411
1434
|
// its VALUE lowered checked-dynamic — same DOM read.
|
|
1412
|
-
neverTaintedJsType(L, expr.expression, L.typeOf(expr.expression))))
|
|
1435
|
+
neverTaintedJsType(L, expr.expression, L.typeOf(expr.expression)))) ||
|
|
1436
|
+
(expr.name.text === "length" &&
|
|
1437
|
+
(L.checkerAnyArray(expr.expression) ||
|
|
1438
|
+
(L.checker.isArrayType(L.typeOf(expr.expression)) &&
|
|
1439
|
+
L.mapTypeOf(L.typeOf(expr.expression))?.kind === "dyn")))) {
|
|
1413
1440
|
const recv = L.lowerExpr(expr.expression);
|
|
1414
1441
|
if (recv.type.kind === "dyn") {
|
|
1415
1442
|
const key = { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) };
|
|
@@ -1477,6 +1504,17 @@ function lowerExprInner(L, expr) {
|
|
|
1477
1504
|
return nsUndefRead(L, ambientRoot.text, expr, t);
|
|
1478
1505
|
}
|
|
1479
1506
|
}
|
|
1507
|
+
// A member read through a NULLISH generic binding (`const i: I<A &
|
|
1508
|
+
// B> = null as any; const _i: I<A> = i.something` — the receiver
|
|
1509
|
+
// provably holds null/undefined forever): the read throws Node's
|
|
1510
|
+
// exact TypeError at the access.
|
|
1511
|
+
if (ts.isIdentifier(expr.expression) && expr.questionDotToken === undefined) {
|
|
1512
|
+
const unit = nullishGenericBindingUnitOf(L, L.resolveValueSymbol(expr.expression));
|
|
1513
|
+
if (unit !== null) {
|
|
1514
|
+
const t = ambientUndefReadType(L, expr) ?? contextualUndefReadType(L, expr) ?? F64;
|
|
1515
|
+
return nodeThrowExpr(1, "", `Cannot read properties of ${unit} (reading '${expr.name.text}')`, t, loc);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1480
1518
|
// The lib fence's PROPERTY chokepoint: a stdlib-declared member that
|
|
1481
1519
|
// no lowering above claimed ([1,2].entries, Math.SQRT2, Promise.all,
|
|
1482
1520
|
// re.exec as a value, ...) reports SC2020 here.
|
|
@@ -2152,7 +2190,18 @@ function pureCondExpr(e) {
|
|
|
2152
2190
|
export function lowerNullishCoalesce(L, expr, loc) {
|
|
2153
2191
|
const left = L.lowerExpr(expr.left);
|
|
2154
2192
|
if (left.type.kind === "dyn") {
|
|
2155
|
-
|
|
2193
|
+
// `a ?? b` on a CHECKED-DYNAMIC left: the deciding test is the
|
|
2194
|
+
// runtime kind (scr_dyn_is_nullish — UNDEF/NULL take the default;
|
|
2195
|
+
// a wrapped island value routes to the engine's test, defensively:
|
|
2196
|
+
// the wrap constructor scalar-normalizes engine null/undefined
|
|
2197
|
+
// away). Both sides live in the DOM — the right converts through
|
|
2198
|
+
// the usual boundary and evaluates lazily in its branch; a default
|
|
2199
|
+
// with no dyn representation keeps the fence.
|
|
2200
|
+
const right = L.coerceToExpected(L.lowerExpr(expr.right), DYN);
|
|
2201
|
+
if (right.type.kind !== "dyn") {
|
|
2202
|
+
L.unsupported("SC1100", expr, "nullish coalescing on 'unknown' values against defaults with no dynamic representation");
|
|
2203
|
+
}
|
|
2204
|
+
return { kind: "nullish", left, right, type: DYN, loc };
|
|
2156
2205
|
}
|
|
2157
2206
|
if (left.type.kind === "jsval") {
|
|
2158
2207
|
// `a ?? b` on an ISLAND value: the engine's own nullish test — the
|
|
@@ -2986,6 +3035,24 @@ export function lowerIntrinsicProperty(L, expr) {
|
|
|
2986
3035
|
return read;
|
|
2987
3036
|
return { kind: "jsExit", value: read, type: F64, loc: locOf(expr) };
|
|
2988
3037
|
}
|
|
3038
|
+
// A CHECKED-DYNAMIC value behind an array-typed checker spelling
|
|
3039
|
+
// (`Object.keys(u).length` — the dyn walk answers a DOM array while
|
|
3040
|
+
// tsc spells string[]): the runtime-world dispatch — a DOM keyed
|
|
3041
|
+
// read validated into the declared number (a lying length throws
|
|
3042
|
+
// the catchable TypeError, the dynCheck stance).
|
|
3043
|
+
if (receiver.type.kind === "dyn") {
|
|
3044
|
+
const read = {
|
|
3045
|
+
kind: "dynKeyGet",
|
|
3046
|
+
key: { kind: "strLit", value: "length", type: STRING, loc: locOf(expr) },
|
|
3047
|
+
...(expr.questionDotToken ? { optional: true } : {}),
|
|
3048
|
+
value: receiver,
|
|
3049
|
+
type: DYN,
|
|
3050
|
+
loc: locOf(expr),
|
|
3051
|
+
};
|
|
3052
|
+
if (expr.questionDotToken)
|
|
3053
|
+
return read;
|
|
3054
|
+
return { kind: "dynCheck", value: read, type: F64, loc: locOf(expr) };
|
|
3055
|
+
}
|
|
2989
3056
|
return kind === "string"
|
|
2990
3057
|
? { kind: "strIntrinsic", method: "length", receiver, args: [], type: F64, loc: locOf(expr) }
|
|
2991
3058
|
: { kind: "arrIntrinsic", method: "length", receiver, args: [], type: F64, loc: locOf(expr) };
|
|
@@ -3146,8 +3213,12 @@ export function lowerArrayLiteral(L, expr, expected) {
|
|
|
3146
3213
|
// []) builds as a DOM ARRAY — one dyn value whose elements each
|
|
3147
3214
|
// convert through the usual boundary (dynFrom's JSON-safe domain);
|
|
3148
3215
|
// an element that cannot convert fences per element. length/index
|
|
3149
|
-
// reads and dynamic consumers ride the keyed-DOM paths.
|
|
3150
|
-
|
|
3216
|
+
// reads and dynamic consumers ride the keyed-DOM paths. TS literals
|
|
3217
|
+
// take the same build when the slot ITSELF is checked-dynamic — an
|
|
3218
|
+
// `unknown[]` annotation or a collapsed `(string | object)[]` maps
|
|
3219
|
+
// to DYN wholesale now (mapType's dyn-element array rule), so the
|
|
3220
|
+
// literal IS the DOM array.
|
|
3221
|
+
if (isJsSourceFile(expr.getSourceFile()) || mapped?.kind === "dyn") {
|
|
3151
3222
|
const elems = expr.elements.map((el) => {
|
|
3152
3223
|
if (ts.isSpreadElement(el)) {
|
|
3153
3224
|
L.unsupported("SC1090", el, "spread elements in a dynamic (unknown[]) array literal");
|
|
@@ -4158,7 +4229,9 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4158
4229
|
}
|
|
4159
4230
|
const shapeMismatch = (node) => {
|
|
4160
4231
|
const own = L.mapTypeOf(L.typeOf(expr));
|
|
4161
|
-
L.pushDiag(recordShapeMismatchDiag(L.fmt(type), own ? L.fmt(own) : L.checker.typeToString(L.typeOf(expr)), locOf(node)
|
|
4232
|
+
L.pushDiag(recordShapeMismatchDiag(L.fmt(type), own ? L.fmt(own) : L.checker.typeToString(L.typeOf(expr)), locOf(node), own?.kind === "record"
|
|
4233
|
+
? (L.describeRecordWidthBlocker(own.shapeId, type.shapeId) ?? undefined)
|
|
4234
|
+
: undefined));
|
|
4162
4235
|
throw new PoisonError();
|
|
4163
4236
|
};
|
|
4164
4237
|
const fields = [];
|
|
@@ -4340,7 +4413,7 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4340
4413
|
if (targetType.kind === "union") {
|
|
4341
4414
|
const retag = L.unionRetagHelper(f.type.unionId, targetType.unionId, locOf(prop));
|
|
4342
4415
|
if (!retag) {
|
|
4343
|
-
L.pushDiag(recordShapeMismatchDiag(L.fmt(type), L.fmt(recArm), locOf(prop)));
|
|
4416
|
+
L.pushDiag(recordShapeMismatchDiag(L.fmt(type), L.fmt(recArm), locOf(prop), `spread field '${f.name}': '${L.fmt(f.type)}' cannot re-tag into '${L.fmt(targetType)}' behind the present-test`));
|
|
4344
4417
|
throw new PoisonError();
|
|
4345
4418
|
}
|
|
4346
4419
|
thenVal = { kind: "call", callee: retag, args: [fRead()], type: targetType, loc: locOf(prop) };
|
|
@@ -4349,7 +4422,7 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4349
4422
|
thenVal = { kind: "unionNarrow", unionId: f.type.unionId, tag: L.armTag(f.type.unionId, targetType), value: fRead(), type: targetType, loc: locOf(prop) };
|
|
4350
4423
|
}
|
|
4351
4424
|
else {
|
|
4352
|
-
L.pushDiag(recordShapeMismatchDiag(L.fmt(type), L.fmt(recArm), locOf(prop)));
|
|
4425
|
+
L.pushDiag(recordShapeMismatchDiag(L.fmt(type), L.fmt(recArm), locOf(prop), `spread field '${f.name}': '${L.fmt(f.type)}' cannot narrow into '${L.fmt(targetType)}' behind the present-test`));
|
|
4353
4426
|
throw new PoisonError();
|
|
4354
4427
|
}
|
|
4355
4428
|
}
|
|
@@ -4361,7 +4434,7 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4361
4434
|
// undefined trap must not shadow.
|
|
4362
4435
|
const lift = L.widthLiftPlan(f.type, targetType);
|
|
4363
4436
|
if (!lift) {
|
|
4364
|
-
L.pushDiag(recordShapeMismatchDiag(L.fmt(type), L.fmt(recArm), locOf(prop)));
|
|
4437
|
+
L.pushDiag(recordShapeMismatchDiag(L.fmt(type), L.fmt(recArm), locOf(prop), `spread field '${f.name}': '${L.fmt(f.type)}' does not lift into '${L.fmt(targetType)}'`));
|
|
4365
4438
|
throw new PoisonError();
|
|
4366
4439
|
}
|
|
4367
4440
|
thenVal = L.applyWidthLift(lift, fRead(), targetType, locOf(prop));
|
|
@@ -4441,7 +4514,7 @@ export function lowerObjectLiteral(L, expr) {
|
|
|
4441
4514
|
// it can render identically to the target while the spread
|
|
4442
4515
|
// source (the thing that actually mismatches) differs — an
|
|
4443
4516
|
// invisible difference is a diagnostics bug.
|
|
4444
|
-
L.pushDiag(recordShapeMismatchDiag(L.fmt(type), L.fmt(srcType), locOf(prop)));
|
|
4517
|
+
L.pushDiag(recordShapeMismatchDiag(L.fmt(type), L.fmt(srcType), locOf(prop), `spread field '${f.name}': '${L.fmt(f.type)}' does not lift into '${L.fmt(targetType)}'`));
|
|
4445
4518
|
throw new PoisonError();
|
|
4446
4519
|
}
|
|
4447
4520
|
const obj = srcLowered ?? L.lowerExpr(srcNode);
|
|
@@ -5049,7 +5122,24 @@ export function lowerElementAccess(L, expr) {
|
|
|
5049
5122
|
? null
|
|
5050
5123
|
: L.mapTypeOf(L.typeOf(expr.expression));
|
|
5051
5124
|
if (receiverIr?.kind === "jsval") {
|
|
5052
|
-
|
|
5125
|
+
// Dispatch follows the RUNTIME world (383(d)): a checker-'any'
|
|
5126
|
+
// receiver whose value LOWERED checked-dynamic (`bag.list[0]` where
|
|
5127
|
+
// bag.list is a routed keyed read off a wrapped island value) takes
|
|
5128
|
+
// the DOM keyed read below — the routed JSVAL arm reads the real
|
|
5129
|
+
// engine element; a jsval-lowered receiver keeps the island read.
|
|
5130
|
+
const recv = L.lowerExpr(expr.expression);
|
|
5131
|
+
if (recv.type.kind !== "dyn")
|
|
5132
|
+
return islandElementRead(L, expr, recv);
|
|
5133
|
+
const rawKey = L.lowerExpr(expr.argumentExpression);
|
|
5134
|
+
const key = rawKey.type.kind === "string"
|
|
5135
|
+
? rawKey
|
|
5136
|
+
: rawKey.type.kind === "f64"
|
|
5137
|
+
? { kind: "toString", operand: rawKey, type: STRING, loc: rawKey.loc }
|
|
5138
|
+
: null;
|
|
5139
|
+
if (key) {
|
|
5140
|
+
const opt = chainGuardedByQuestionDot(expr.expression);
|
|
5141
|
+
return L.maybeNarrow({ kind: "dynKeyGet", key, ...(opt ? { optional: true } : {}), value: recv, type: DYN, loc: locOf(expr) }, expr);
|
|
5142
|
+
}
|
|
5053
5143
|
}
|
|
5054
5144
|
// Typed-array element read `b[i]` — like arrayGet with a scalar
|
|
5055
5145
|
// result; any invalid index traps (the array discipline; JS would
|
|
@@ -5127,9 +5217,12 @@ export function lowerElementAccess(L, expr) {
|
|
|
5127
5217
|
const obj = L.lowerExpr(expr.expression);
|
|
5128
5218
|
if (obj.type.kind === "dyn") {
|
|
5129
5219
|
const rawKey = L.lowerExpr(expr.argumentExpression);
|
|
5220
|
+
// Number, bool, and DYN keys stringify (ToPropertyKey) — the
|
|
5221
|
+
// dyn-keyed read `catchWarning[warning.name]` where the property
|
|
5222
|
+
// chain itself lowered dyn.
|
|
5130
5223
|
const key = rawKey.type.kind === "string"
|
|
5131
5224
|
? rawKey
|
|
5132
|
-
: rawKey.type.kind === "f64"
|
|
5225
|
+
: rawKey.type.kind === "f64" || rawKey.type.kind === "bool" || rawKey.type.kind === "dyn"
|
|
5133
5226
|
? { kind: "toString", operand: rawKey, type: STRING, loc: rawKey.loc }
|
|
5134
5227
|
: null;
|
|
5135
5228
|
if (key) {
|
|
@@ -5495,11 +5588,58 @@ export function lowerElementWrite(L, expr) {
|
|
|
5495
5588
|
const receiverIr = L.mapTypeOf(L.typeOf(target.expression));
|
|
5496
5589
|
if (receiverIr?.kind === "jsval") {
|
|
5497
5590
|
const obj = L.lowerExpr(target.expression);
|
|
5591
|
+
// Dispatch follows the RUNTIME world (383(d)): a checker-'any'
|
|
5592
|
+
// receiver whose value LOWERED checked-dynamic takes the DOM keyed
|
|
5593
|
+
// write — the routed JSVAL arm lands it on the real engine object.
|
|
5594
|
+
if (obj.type.kind === "dyn") {
|
|
5595
|
+
const loc = locOf(expr);
|
|
5596
|
+
const rawKey = L.lowerExpr(target.argumentExpression);
|
|
5597
|
+
const key = rawKey.type.kind === "f64" || rawKey.type.kind === "bool" || rawKey.type.kind === "dyn"
|
|
5598
|
+
? { kind: "toString", operand: rawKey, type: STRING, loc: rawKey.loc }
|
|
5599
|
+
: rawKey;
|
|
5600
|
+
if (key.type.kind !== "string") {
|
|
5601
|
+
L.unsupported("SC1090", target.argumentExpression, `'${L.fmt(key.type)}'-typed keys in keyed writes through 'unknown' values`);
|
|
5602
|
+
}
|
|
5603
|
+
const value = L.coerceToExpected(L.lowerExpr(expr.right), DYN);
|
|
5604
|
+
if (value.type.kind !== "dyn") {
|
|
5605
|
+
L.unsupported("SC1100", expr.right, `assigning '${L.fmt(value.type)}' values through 'unknown' receivers`);
|
|
5606
|
+
}
|
|
5607
|
+
return {
|
|
5608
|
+
kind: "exprStmt",
|
|
5609
|
+
expr: { kind: "libCall", fn: "dyn.keySet", args: [obj, key, value], type: VOID, loc },
|
|
5610
|
+
loc,
|
|
5611
|
+
};
|
|
5612
|
+
}
|
|
5498
5613
|
const key = L.jsvalIn(L.lowerExpr(target.argumentExpression), target.argumentExpression);
|
|
5499
5614
|
const value = L.jsvalIn(L.lowerExpr(expr.right), expr.right);
|
|
5500
5615
|
const loc = locOf(expr);
|
|
5501
5616
|
return { kind: "exprStmt", expr: { kind: "jsOp", op: "setIdx", args: [obj, key, value], type: VOID, loc }, loc };
|
|
5502
5617
|
}
|
|
5618
|
+
// A checked-dynamic receiver TYPE (`unknown[]` and the collapsed
|
|
5619
|
+
// `(string | object)[]` map to DYN wholesale now): the DOM keyed
|
|
5620
|
+
// write — dyn.keySet. Number keys canonicalize through the JS-exact
|
|
5621
|
+
// formatter; ARR receivers take canonical index keys as element
|
|
5622
|
+
// set/extend (undefined-hole padding, JS's length growth exactly),
|
|
5623
|
+
// OBJ receivers set the member, and the runtime throws Node's
|
|
5624
|
+
// TypeErrors on every other kind. Values convert into the DOM;
|
|
5625
|
+
// unconvertible ones fence per site (the dynFrom stance).
|
|
5626
|
+
if (receiverIr?.kind === "dyn") {
|
|
5627
|
+
const obj = L.lowerExpr(target.expression);
|
|
5628
|
+
if (obj.type.kind === "dyn") {
|
|
5629
|
+
const loc = locOf(expr);
|
|
5630
|
+
let key = L.lowerExpr(target.argumentExpression);
|
|
5631
|
+
if (key.type.kind === "f64")
|
|
5632
|
+
key = L.ensureString(key, target.argumentExpression);
|
|
5633
|
+
if (key.type.kind !== "string") {
|
|
5634
|
+
L.unsupported("SC1090", target.argumentExpression, "indexing with non-string or non-number keys");
|
|
5635
|
+
}
|
|
5636
|
+
const value = L.coerceToExpected(L.lowerExpr(expr.right), DYN);
|
|
5637
|
+
if (value.type.kind !== "dyn") {
|
|
5638
|
+
L.unsupported("SC1101", expr.right, `storing '${L.fmt(value.type)}' values in a checked-dynamic array (the value cannot convert into the DOM)`);
|
|
5639
|
+
}
|
|
5640
|
+
return { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet", args: [obj, key, value], type: VOID, loc }, loc };
|
|
5641
|
+
}
|
|
5642
|
+
}
|
|
5503
5643
|
// Typed-array element write `b[i] = v` — bytesSet: the value is an f64
|
|
5504
5644
|
// the runtime coerces JS-exactly; invalid indices trap (no appends —
|
|
5505
5645
|
// typed arrays are fixed-length; JS would ignore the write).
|
|
@@ -5676,6 +5816,39 @@ export function lowerElementWrite(L, expr) {
|
|
|
5676
5816
|
};
|
|
5677
5817
|
}
|
|
5678
5818
|
}
|
|
5819
|
+
// Keyed write `d[k] = v` on a CHECKED-DYNAMIC receiver (a JS `any`
|
|
5820
|
+
// dictionary — the Object.create(null) memo-table idiom writes
|
|
5821
|
+
// `result[key] = value`): dyn.keySet, exactly the record-mapped dyn
|
|
5822
|
+
// arm above — later writes win in insertion order, number keys
|
|
5823
|
+
// canonicalize through the JS-exact formatter (ToPropertyKey's string
|
|
5824
|
+
// side), index keys on DOM arrays set/extend elements, and non-object
|
|
5825
|
+
// receivers throw Node's TypeErrors at runtime. An UNMAPPED checker
|
|
5826
|
+
// type (static `any` — mapTypeOf answers null without --dynamic)
|
|
5827
|
+
// probes the receiver's own lowered world: a dyn value takes the same
|
|
5828
|
+
// write, anything else falls through to the fences.
|
|
5829
|
+
if (receiverIr?.kind === "dyn" || receiverIr === null) {
|
|
5830
|
+
const obj = receiverIr !== null ? L.lowerExpr(target.expression) : probeLower(L, target.expression);
|
|
5831
|
+
if (obj !== null && obj.type.kind === "dyn") {
|
|
5832
|
+
const loc = locOf(expr);
|
|
5833
|
+
const litKey = recordKeyLiteralText(target.argumentExpression);
|
|
5834
|
+
let key = litKey !== null
|
|
5835
|
+
? { kind: "strLit", value: litKey, type: STRING, loc: locOf(target.argumentExpression) }
|
|
5836
|
+
: L.lowerExpr(target.argumentExpression);
|
|
5837
|
+
if (key.type.kind === "f64")
|
|
5838
|
+
key = L.ensureString(key, target.argumentExpression);
|
|
5839
|
+
if (key.type.kind === "bool" || key.type.kind === "dyn") {
|
|
5840
|
+
key = { kind: "toString", operand: key, type: STRING, loc: locOf(target.argumentExpression) };
|
|
5841
|
+
}
|
|
5842
|
+
if (key.type.kind !== "string") {
|
|
5843
|
+
L.unsupported("SC1090", target.argumentExpression, "indexing checked-dynamic values with non-string or non-number keys");
|
|
5844
|
+
}
|
|
5845
|
+
const value = L.coerceToExpected(L.lowerExpr(expr.right), DYN);
|
|
5846
|
+
if (value.type.kind !== "dyn") {
|
|
5847
|
+
L.unsupported("SC1101", expr.right, `storing '${L.fmt(value.type)}' values in a checked-dynamic object (the value cannot convert into the DOM)`);
|
|
5848
|
+
}
|
|
5849
|
+
return { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet", args: [obj, key, value], type: VOID, loc }, loc };
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5679
5852
|
if (receiverIr?.kind !== "array") {
|
|
5680
5853
|
L.unsupported("SC1090", target, "assignment to non-array elements");
|
|
5681
5854
|
}
|
|
@@ -6126,6 +6299,46 @@ export function lowerBinary(L, expr) {
|
|
|
6126
6299
|
const value = L.lowerExprExpecting(expr.right, target.type);
|
|
6127
6300
|
return { kind: "assignExpr", localId: target.id, value, type: target.type, loc };
|
|
6128
6301
|
}
|
|
6302
|
+
// `events.defaultMaxListeners = v` — the module-property write
|
|
6303
|
+
// Node validates (validateNumber(n, 'defaultMaxListeners', 0)):
|
|
6304
|
+
// the value crosses into the DOM and the runtime ladder throws
|
|
6305
|
+
// ERR_INVALID_ARG_TYPE / ERR_OUT_OF_RANGE with Node's exact slot
|
|
6306
|
+
// name; valid numbers apply. The expression's value is the RHS
|
|
6307
|
+
// (JS's assignment yield).
|
|
6308
|
+
if (op === ts.SyntaxKind.EqualsToken &&
|
|
6309
|
+
ts.isPropertyAccessExpression(expr.left) &&
|
|
6310
|
+
!expr.left.questionDotToken &&
|
|
6311
|
+
expr.left.name.text === "defaultMaxListeners") {
|
|
6312
|
+
const bi = L.builtinMemberOf(expr.left);
|
|
6313
|
+
if (bi && bi.module === "events" && bi.member === "defaultMaxListeners") {
|
|
6314
|
+
const rhs = L.lowerExpr(expr.right);
|
|
6315
|
+
if (rhs.type.kind === "dyn" || rhs.kind === "unitLit" || L.dynConvertible(rhs.type)) {
|
|
6316
|
+
const valTmp = L.declareHiddenLocal("%setVal", rhs.type);
|
|
6317
|
+
const valRef = () => ({ kind: "varRef", localId: valTmp.id, type: rhs.type, loc });
|
|
6318
|
+
const dynVal = rhs.type.kind === "dyn" ? valRef() : { kind: "dynFrom", value: valRef(), type: DYN, loc };
|
|
6319
|
+
return {
|
|
6320
|
+
kind: "seqExpr",
|
|
6321
|
+
stmts: [
|
|
6322
|
+
{ kind: "varDecl", localId: valTmp.id, init: rhs, loc },
|
|
6323
|
+
{
|
|
6324
|
+
kind: "exprStmt",
|
|
6325
|
+
expr: {
|
|
6326
|
+
kind: "libCall",
|
|
6327
|
+
fn: "emitter.setDefaultMaxChk",
|
|
6328
|
+
args: [dynVal, { kind: "strLit", value: "defaultMaxListeners", type: STRING, loc }],
|
|
6329
|
+
type: VOID,
|
|
6330
|
+
loc,
|
|
6331
|
+
},
|
|
6332
|
+
loc,
|
|
6333
|
+
},
|
|
6334
|
+
],
|
|
6335
|
+
result: valRef(),
|
|
6336
|
+
type: rhs.type,
|
|
6337
|
+
loc,
|
|
6338
|
+
};
|
|
6339
|
+
}
|
|
6340
|
+
}
|
|
6341
|
+
}
|
|
6129
6342
|
// Member targets whose storage IS a module global — namespace
|
|
6130
6343
|
// members (`N.x`) and expando function members (`Foo.baz`): the
|
|
6131
6344
|
// same assignExpr, since the "member" is a variable.
|
|
@@ -6611,6 +6824,7 @@ export function lowerBinary(L, expr) {
|
|
|
6611
6824
|
kind: "unionEq",
|
|
6612
6825
|
unionId: ut.unionId,
|
|
6613
6826
|
negated,
|
|
6827
|
+
sameValue: false,
|
|
6614
6828
|
left: L.coerceInto(expr.left, left, ut),
|
|
6615
6829
|
right: L.coerceInto(expr.right, right, ut),
|
|
6616
6830
|
type: BOOL,
|