@scriptc/compiler 0.1.5 → 0.1.7
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 +0 -1
- package/ambient/scriptc.d.ts +13 -5
- package/dist/backend/c/c-emitter.d.ts +5 -0
- package/dist/backend/c/c-emitter.js +15 -0
- package/dist/backend/c/c-emitter.js.map +1 -1
- package/dist/backend/c/exprs.js +81 -9
- package/dist/backend/c/exprs.js.map +1 -1
- package/dist/backend/c/stmts.js +25 -1
- package/dist/backend/c/stmts.js.map +1 -1
- package/dist/backend/c/walkers.js +2 -3
- package/dist/backend/c/walkers.js.map +1 -1
- package/dist/backend/debug-symbols.d.ts +8 -0
- package/dist/backend/debug-symbols.js +52 -0
- package/dist/backend/debug-symbols.js.map +1 -0
- package/dist/backend/link-plan.d.ts +1 -0
- package/dist/backend/link-plan.js +2 -0
- package/dist/backend/link-plan.js.map +1 -1
- package/dist/backend/linker.js +8 -0
- package/dist/backend/linker.js.map +1 -1
- package/dist/backend/llvm/blocks.d.ts +2 -0
- package/dist/backend/llvm/blocks.js +18 -2
- package/dist/backend/llvm/blocks.js.map +1 -1
- package/dist/backend/llvm/debug-info.d.ts +32 -0
- package/dist/backend/llvm/debug-info.js +203 -0
- package/dist/backend/llvm/debug-info.js.map +1 -0
- package/dist/backend/llvm/dyn.js +4 -10
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +2 -0
- package/dist/backend/llvm/emitter.js +49 -4
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +28 -2
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +10 -0
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +37 -0
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +4 -3
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +9 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/split.js +4 -1
- package/dist/backend/llvm/split.js.map +1 -1
- package/dist/backend/llvm/split.test.js +26 -1
- package/dist/backend/llvm/split.test.js.map +1 -1
- package/dist/backend/native-toolchain.js +58 -8
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/backend/native-toolchain.test.js +10 -0
- package/dist/backend/native-toolchain.test.js.map +1 -1
- package/dist/backend/source-locations.d.ts +12 -0
- package/dist/backend/source-locations.js +32 -0
- package/dist/backend/source-locations.js.map +1 -0
- package/dist/backend/source-locations.test.d.ts +1 -0
- package/dist/backend/source-locations.test.js +16 -0
- package/dist/backend/source-locations.test.js.map +1 -0
- package/dist/coverage/surface-manifest.js +6 -1
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +4 -0
- package/dist/diagnostics/diagnostic.js +12 -0
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/executable/executable-cache.js +28 -4
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +23 -0
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/frontend/arguments-usage.d.ts +6 -0
- package/dist/frontend/arguments-usage.js +40 -0
- package/dist/frontend/arguments-usage.js.map +1 -0
- package/dist/frontend/binding-source.d.ts +4 -0
- package/dist/frontend/binding-source.js +18 -0
- package/dist/frontend/binding-source.js.map +1 -0
- package/dist/frontend/lowering/array-indexed-mutation.d.ts +8 -0
- package/dist/frontend/lowering/array-indexed-mutation.js +176 -0
- package/dist/frontend/lowering/array-indexed-mutation.js.map +1 -0
- package/dist/frontend/lowering/containers/string-and-regexp.d.ts +7 -0
- package/dist/frontend/lowering/containers/string-and-regexp.js +190 -13
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +13 -8
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.d.ts +5 -6
- package/dist/frontend/lowering/expressions/optional-chains.js +7 -6
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/indexed-comparison.d.ts +6 -0
- package/dist/frontend/lowering/indexed-comparison.js +30 -0
- package/dist/frontend/lowering/indexed-comparison.js.map +1 -0
- package/dist/frontend/lowering/lower-builtins.d.ts +1 -1
- package/dist/frontend/lowering/lower-builtins.js +21 -10
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +2 -9
- package/dist/frontend/lowering/lower-calls.js +406 -40
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +3 -27
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +8 -2
- package/dist/frontend/lowering/lower-containers.js +454 -104
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +134 -18
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +1 -1
- package/dist/frontend/lowering/lower-island.js +1 -1
- package/dist/frontend/lowering/lower-modules.js +19 -8
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +4 -37
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.js +14 -3
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +3 -1
- package/dist/frontend/lowering/surfaces.js +50 -7
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/program.d.ts +5 -0
- package/dist/frontend/program.js +216 -32
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.d.ts +1 -0
- package/dist/frontend/program.test.js +117 -0
- package/dist/frontend/program.test.js.map +1 -0
- package/dist/frontend/type-mapper.d.ts +4 -2
- package/dist/frontend/type-mapper.js +249 -186
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/type-mapper.test.d.ts +1 -0
- package/dist/frontend/type-mapper.test.js +86 -0
- package/dist/frontend/type-mapper.test.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.js +4 -2
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/ir.d.ts +33 -14
- package/dist/ir/ir.js +5 -1
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/validate.js +57 -31
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +17 -0
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/compiler-self-identity.d.ts +1 -1
- package/dist/library/compiler-self-identity.js +31 -15
- package/dist/library/compiler-self-identity.js.map +1 -1
- package/dist/library/compiler-self-identity.test.d.ts +1 -0
- package/dist/library/compiler-self-identity.test.js +93 -0
- package/dist/library/compiler-self-identity.test.js.map +1 -0
- package/package.json +17 -17
- package/surface-manifest.json +155 -4
|
@@ -11,11 +11,12 @@ import { pathToFileURL } from "node:url";
|
|
|
11
11
|
import { wasiGuestPath } from "../../wasi-paths.js";
|
|
12
12
|
import { BIGINT_T, BOOL, CAUGHT, DYN, DYN_HANDLE_KINDS, F64, JSVAL, NULL_T, REF_TRUTHY_KINDS, REGEX, RUNTIME_ERROR_CLASSES, SEARCH_PARAMS_T, STRING, UNDEFINED_T, VOID, arrayOf, canAdaptDynFuncTo, canBoxFuncIntoDyn, funcOf, isDynTypedRefType, isJsonSafeType, isSupportedArrayElem, isUnitType, jsOpResultKind, shapeHasAccessorSlots, typeEquals, typeKey, unionFuncSetArmsOk } from "../../ir/ir.js";
|
|
13
13
|
import { cjsClassExprWholeExportOf, cjsExportAssignmentOf, cjsExportDiscardReason, isCjsExportTableLiteral, isCjsJsFile, isJsSourceFile, isModuleExportsAccess, isNodeEsmFile, locOf } from "../program.js";
|
|
14
|
-
import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstOf, builtinModulesArrayLit, builtinModuleFnOf, COMPOUND_ASSIGN_OPS, ISLAND_SURFACE, isChildSurfaceMember, MAP_METHODS, NARROW_FIRST, SET_METHODS, STR_METHODS, UNSUPPORTED_EXPR, sideEffectFreeOptionValue, stdlibGlobalNameOf } from "./surfaces.js";
|
|
14
|
+
import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstOf, builtinModulesArrayLit, builtinModuleFnOf, COMPOUND_ASSIGN_OPS, ISLAND_SURFACE, isChildSurfaceMember, MAP_METHODS, NARROW_FIRST, SET_METHODS, STRING_INDEX_METHODS, STR_METHODS, UNSUPPORTED_EXPR, sideEffectFreeOptionValue, stdlibGlobalNameOf } from "./surfaces.js";
|
|
15
15
|
import { blockedBindingUseDiag, requiresDynamicPackageDiag, unsupportedDiag } from "../../diagnostics/diagnostic.js";
|
|
16
16
|
import { PoisonError, dynUndefinedExpr, jsFuncNameOf, neverTaintedJsType, nodeThrowExpr, own } from "./lowerer.js";
|
|
17
17
|
import { lowerNpmStaticSafeIndexRead, lowerSafeIndexRead, strCharsCall, tryLowerNumericIndexRead } from "./lower-containers.js";
|
|
18
18
|
import { arrayValueRead, arrayValueStore } from "./array-values.js";
|
|
19
|
+
import { tryLowerIndexedComparison } from "./indexed-comparison.js";
|
|
19
20
|
import { npmStaticPackageOfPath } from "../npm-static.js";
|
|
20
21
|
import { unsupportedModuleFeatureOf } from "../builtin-modules.js";
|
|
21
22
|
import { fenceEnumObjectValue, lowerEnumAccess } from "./lower-enums.js";
|
|
@@ -554,6 +555,18 @@ function lowerExprInner(lowerer, expr) {
|
|
|
554
555
|
return { kind: "strLit", value: "object", type: STRING, loc };
|
|
555
556
|
}
|
|
556
557
|
if (ts.isPropertyAccessExpression(expr.expression)) {
|
|
558
|
+
const member = expr.expression;
|
|
559
|
+
const prototype = member.expression;
|
|
560
|
+
if (STRING_INDEX_METHODS.has(member.name.text) && ts.isPropertyAccessExpression(prototype) &&
|
|
561
|
+
prototype.name.text === "prototype" && ts.isIdentifier(prototype.expression) &&
|
|
562
|
+
lowerer.isStdlibGlobal(prototype.expression, "String") && lowerer.isStdlibMember(member)) {
|
|
563
|
+
return { kind: "strLit", value: "function", type: STRING, loc };
|
|
564
|
+
}
|
|
565
|
+
if (member.name.text === "at" && ts.isPropertyAccessExpression(prototype) &&
|
|
566
|
+
prototype.name.text === "prototype" && ts.isIdentifier(prototype.expression) &&
|
|
567
|
+
lowerer.isStdlibGlobal(prototype.expression, "Array") && lowerer.isStdlibMember(member)) {
|
|
568
|
+
return { kind: "strLit", value: "function", type: STRING, loc };
|
|
569
|
+
}
|
|
557
570
|
const presence = lowerPromiseThenPresence(lowerer, expr.expression, { kind: "strLit", value: "function", type: STRING, loc });
|
|
558
571
|
if (presence !== null)
|
|
559
572
|
return presence;
|
|
@@ -993,6 +1006,13 @@ function lowerExprInner(lowerer, expr) {
|
|
|
993
1006
|
const canonical = stdlibGlobalNameOf(lowerer, expr) ?? expr.text;
|
|
994
1007
|
return { kind: "strLit", value: `[builtin ${canonical}]`, type: STRING, loc };
|
|
995
1008
|
}
|
|
1009
|
+
// In a dynamic TypeScript build, the real global object is the
|
|
1010
|
+
// escape hatch for host capabilities without static lowering.
|
|
1011
|
+
// Direct globalThis.member uses still take their static surface
|
|
1012
|
+
// paths; an explicit `as any` or `: any` can reach engine ops.
|
|
1013
|
+
if (lowerer.dynamic && expr.text === "globalThis") {
|
|
1014
|
+
return { kind: "jsOp", op: "globalGet", name: "globalThis", args: [], type: JSVAL, loc };
|
|
1015
|
+
}
|
|
996
1016
|
// The families with a WHY: each hint states what makes the
|
|
997
1017
|
// surface genuinely non-static (or what to use instead).
|
|
998
1018
|
const globalHints = {
|
|
@@ -2294,8 +2314,25 @@ export function maybeNarrow(lowerer, expr, node) {
|
|
|
2294
2314
|
return expr;
|
|
2295
2315
|
}
|
|
2296
2316
|
const tag = lowerer.armTag(expr.type.unionId, narrowed);
|
|
2297
|
-
if (tag < 0)
|
|
2317
|
+
if (tag < 0) {
|
|
2318
|
+
// A proven-present optional base class can narrow further to a
|
|
2319
|
+
// subclass. The payload is still stored under the base class tag;
|
|
2320
|
+
// unwrap it before applying the ordinary class downcast.
|
|
2321
|
+
const arms = lowerer.unions.get(expr.type.unionId)?.arms ?? [];
|
|
2322
|
+
const valueTag = arms.findIndex((arm) => !isUnitType(arm));
|
|
2323
|
+
const valueType = arms[valueTag];
|
|
2324
|
+
if (narrowed.kind === "object" && valueType?.kind === "object" &&
|
|
2325
|
+
arms.every((arm, i) => i === valueTag || isUnitType(arm)) &&
|
|
2326
|
+
lowerer.isSubclassOf(narrowed.className, valueType.className)) {
|
|
2327
|
+
return {
|
|
2328
|
+
kind: "downcast",
|
|
2329
|
+
value: { kind: "unionNarrow", unionId: expr.type.unionId, tag: valueTag, value: expr, type: valueType, loc: expr.loc },
|
|
2330
|
+
type: narrowed,
|
|
2331
|
+
loc: expr.loc,
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2298
2334
|
return expr;
|
|
2335
|
+
}
|
|
2299
2336
|
return {
|
|
2300
2337
|
kind: "unionNarrow",
|
|
2301
2338
|
unionId: expr.type.unionId,
|
|
@@ -2352,12 +2389,11 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
|
|
|
2352
2389
|
}
|
|
2353
2390
|
return { kind: "call", callee: helper, args: [varRef(local.id, local.type, loc)], type: narrowed, loc };
|
|
2354
2391
|
}
|
|
2355
|
-
const valueTag = lowerer.armTag(local.type.unionId, narrowed);
|
|
2356
2392
|
const undefTag = lowerer.armTag(local.type.unionId, UNDEFINED_T);
|
|
2357
|
-
if (valueTag < 0 || undefTag < 0)
|
|
2358
|
-
throw new InternalCompilerError("runtime-optional local is missing its value or undefined arm");
|
|
2359
2393
|
const def = lowerer.unions.get(local.type.unionId);
|
|
2360
|
-
if (!def ||
|
|
2394
|
+
if (!def || undefTag < 0)
|
|
2395
|
+
throw new InternalCompilerError("runtime-optional local is missing its undefined arm");
|
|
2396
|
+
if (def.arms.length !== 2) {
|
|
2361
2397
|
// The checker may narrow a runtime-optional capture to one arm of a
|
|
2362
2398
|
// value union (`Circle | Square | undefined` -> `Circle`). The
|
|
2363
2399
|
// two-arm fast path below cannot extract that arm safely: a later
|
|
@@ -2370,10 +2406,19 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
|
|
|
2370
2406
|
}
|
|
2371
2407
|
return { kind: "call", callee: helper, args: [varRef(local.id, local.type, loc)], type: narrowed, loc };
|
|
2372
2408
|
}
|
|
2409
|
+
// A predicate can strengthen a record's fields or narrow a base class
|
|
2410
|
+
// to a subclass without changing the slot's stored value arm. Extract
|
|
2411
|
+
// that actual arm first: record reads need its original field layout,
|
|
2412
|
+
// and class reads apply the ordinary downcast bridge afterward.
|
|
2413
|
+
const valueTag = undefTag === 0 ? 1 : 0;
|
|
2414
|
+
const valueType = def.arms[valueTag];
|
|
2415
|
+
if (!valueType || isUnitType(valueType)) {
|
|
2416
|
+
lowerer.unsupported("SC1090", expr, "a runtime-optional receiver without a representable value arm");
|
|
2417
|
+
}
|
|
2373
2418
|
const message = property === null
|
|
2374
2419
|
? `${expr.text} is not a function`
|
|
2375
2420
|
: `Cannot read properties of undefined (reading '${property}')`;
|
|
2376
|
-
return {
|
|
2421
|
+
return lowerer.maybeNarrow({
|
|
2377
2422
|
kind: "ternary",
|
|
2378
2423
|
cond: {
|
|
2379
2424
|
kind: "unionIsTag",
|
|
@@ -2384,18 +2429,18 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
|
|
|
2384
2429
|
type: BOOL,
|
|
2385
2430
|
loc,
|
|
2386
2431
|
},
|
|
2387
|
-
then: nodeThrowExpr(1, "", message,
|
|
2432
|
+
then: nodeThrowExpr(1, "", message, valueType, loc),
|
|
2388
2433
|
else_: {
|
|
2389
2434
|
kind: "unionNarrow",
|
|
2390
2435
|
unionId: local.type.unionId,
|
|
2391
2436
|
tag: valueTag,
|
|
2392
2437
|
value: varRef(local.id, local.type, loc),
|
|
2393
|
-
type:
|
|
2438
|
+
type: valueType,
|
|
2394
2439
|
loc,
|
|
2395
2440
|
},
|
|
2396
|
-
type:
|
|
2441
|
+
type: valueType,
|
|
2397
2442
|
loc,
|
|
2398
|
-
};
|
|
2443
|
+
}, narrowedNode);
|
|
2399
2444
|
}
|
|
2400
2445
|
function runtimeOptionalUseOf(expr) {
|
|
2401
2446
|
let receiver = expr;
|
|
@@ -3399,7 +3444,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3399
3444
|
: { kind: "arrIntrinsic", method: "length", receiver, args: [], type: F64, loc: locOf(expr) };
|
|
3400
3445
|
}
|
|
3401
3446
|
if (kind === "string"
|
|
3402
|
-
? own(STR_METHODS, name) !== undefined || own(ISLAND_SURFACE.string, name) !== undefined
|
|
3447
|
+
? own(STR_METHODS, name) !== undefined || STRING_INDEX_METHODS.has(name) || own(ISLAND_SURFACE.string, name) !== undefined
|
|
3403
3448
|
: ARRAY_METHODS.has(name)) {
|
|
3404
3449
|
lowerer.unsupported("SC1090", expr, `${kind} methods as values (call '${name}' directly)`);
|
|
3405
3450
|
}
|
|
@@ -3416,7 +3461,10 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3416
3461
|
export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
3417
3462
|
const loc = locOf(expr);
|
|
3418
3463
|
const ctxType = lowerer.checker.getContextualType(expr);
|
|
3419
|
-
const
|
|
3464
|
+
// `as const satisfies readonly T[]` checks against an array but keeps
|
|
3465
|
+
// the literal's inferred tuple type. Build that shape; an actual array
|
|
3466
|
+
// destination can use the ordinary tuple-to-array coercion afterward.
|
|
3467
|
+
const tsType = underConstAssertion(expr) ? lowerer.typeOf(expr) : ctxType ?? lowerer.typeOf(expr);
|
|
3420
3468
|
let mapped = expected ?? lowerer.mapTypeOf(tsType);
|
|
3421
3469
|
// A JS literal whose OWN inferred type is never-tainted
|
|
3422
3470
|
// (neverTaintedJsType — the evolving `const gb = []`, the mixed
|
|
@@ -3529,13 +3577,13 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
3529
3577
|
// literal constructs the tuple's record shape — one positional field
|
|
3530
3578
|
// per element, source order (which IS index order, so evaluation order
|
|
3531
3579
|
// is JS-exact). tsc has already checked the arity; the recount below
|
|
3532
|
-
// backstops `as` smuggling.
|
|
3580
|
+
// backstops `as` smuggling. Fixed tuple spreads have known positions.
|
|
3533
3581
|
if (mapped?.kind === "record") {
|
|
3534
3582
|
const shape = lowerer.shapes.get(mapped.shapeId);
|
|
3535
3583
|
if (shape?.tuple) {
|
|
3536
3584
|
const spread = expr.elements.find(ts.isSpreadElement);
|
|
3537
3585
|
if (spread) {
|
|
3538
|
-
lowerer
|
|
3586
|
+
return lowerTupleSpreadLiteral(lowerer, expr, mapped, shape);
|
|
3539
3587
|
}
|
|
3540
3588
|
if (expr.elements.length !== shape.fields.length) {
|
|
3541
3589
|
// tsc padded an UNDER-LENGTH literal against an optional-element
|
|
@@ -3804,6 +3852,62 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
3804
3852
|
loc,
|
|
3805
3853
|
};
|
|
3806
3854
|
}
|
|
3855
|
+
/** Build a fixed tuple from positional elements and fixed tuple spreads.
|
|
3856
|
+
* Capture each value in source order: deferring the reads until recordLit
|
|
3857
|
+
* would observe a later element's mutations of the spread source. */
|
|
3858
|
+
function lowerTupleSpreadLiteral(lowerer, expr, type, shape) {
|
|
3859
|
+
const loc = locOf(expr);
|
|
3860
|
+
const byName = new Map(shape.fields.map((field) => [field.name, field.type]));
|
|
3861
|
+
const stmts = [];
|
|
3862
|
+
const fields = [];
|
|
3863
|
+
const append = (node, value) => {
|
|
3864
|
+
const name = String(fields.length);
|
|
3865
|
+
const expected = byName.get(name);
|
|
3866
|
+
if (!expected)
|
|
3867
|
+
lowerer.badType(expr, lowerer.typeOf(expr));
|
|
3868
|
+
const coerced = lowerer.coerceInto(node, value, expected);
|
|
3869
|
+
const temp = lowerer.declareHiddenLocal("%tupleElement", expected);
|
|
3870
|
+
const at = locOf(node);
|
|
3871
|
+
stmts.push({ kind: "varDecl", localId: temp.id, init: coerced, loc: at });
|
|
3872
|
+
fields.push({ name, value: varRef(temp.id, expected, at) });
|
|
3873
|
+
};
|
|
3874
|
+
for (const element of expr.elements) {
|
|
3875
|
+
if (!ts.isSpreadElement(element)) {
|
|
3876
|
+
const expected = byName.get(String(fields.length));
|
|
3877
|
+
if (!expected)
|
|
3878
|
+
lowerer.badType(element, lowerer.typeOf(element));
|
|
3879
|
+
append(element, lowerer.lowerExprExpecting(element, expected));
|
|
3880
|
+
continue;
|
|
3881
|
+
}
|
|
3882
|
+
const source = lowerer.lowerExpr(element.expression);
|
|
3883
|
+
const sourceShape = source.type.kind === "record" ? lowerer.shapes.get(source.type.shapeId) : undefined;
|
|
3884
|
+
if (!sourceShape?.tuple) {
|
|
3885
|
+
// Empty tuples use a zero-length array representation. Preserve a
|
|
3886
|
+
// producing call's effects even though there are no positions to copy.
|
|
3887
|
+
const sourceTs = lowerer.typeOf(element.expression);
|
|
3888
|
+
if (source.type.kind === "array" && lowerer.checker.isTupleType(sourceTs) &&
|
|
3889
|
+
lowerer.checker.getTypeArguments(sourceTs).length === 0) {
|
|
3890
|
+
stmts.push({ kind: "exprStmt", expr: source, loc: locOf(element) });
|
|
3891
|
+
continue;
|
|
3892
|
+
}
|
|
3893
|
+
lowerer.unsupported("SC1090", element, "spreading a variable-length value into a fixed tuple literal");
|
|
3894
|
+
}
|
|
3895
|
+
const temp = lowerer.declareHiddenLocal("%tupleSpread", source.type);
|
|
3896
|
+
const at = locOf(element);
|
|
3897
|
+
stmts.push({ kind: "varDecl", localId: temp.id, init: source, loc: at });
|
|
3898
|
+
const receiver = varRef(temp.id, source.type, at);
|
|
3899
|
+
const positions = [...sourceShape.fields].sort((a, b) => Number(a.name) - Number(b.name));
|
|
3900
|
+
for (const field of positions) {
|
|
3901
|
+
append(element.expression, {
|
|
3902
|
+
kind: "recordGet", obj: receiver, shapeId: sourceShape.id,
|
|
3903
|
+
field: field.name, type: field.type, loc: at,
|
|
3904
|
+
});
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3907
|
+
if (fields.length !== shape.fields.length)
|
|
3908
|
+
lowerer.badType(expr, lowerer.typeOf(expr));
|
|
3909
|
+
return { kind: "seqExpr", stmts, result: { kind: "recordLit", fields, type, loc }, type, loc };
|
|
3910
|
+
}
|
|
3807
3911
|
/** Convert an undefined-armed numeric value at an arithmetic use. Ordinary
|
|
3808
3912
|
* reads preserve their tagged value; JavaScript's ToNumber(undefined) is NaN,
|
|
3809
3913
|
* so compounds and binary arithmetic use this checked one-time extraction. */
|
|
@@ -4371,6 +4475,16 @@ export function lowerRecordKeyRead(lowerer, expr, shapeId, shape, includeUndefin
|
|
|
4371
4475
|
// to observe the missing value instead of throwing during that check.
|
|
4372
4476
|
return includeUndefined ? read : lowerer.maybeNarrow(read, expr);
|
|
4373
4477
|
}
|
|
4478
|
+
// Predicates can strengthen optional fields without changing the
|
|
4479
|
+
// receiver's stored layout. Use that layout for bracket reads just as
|
|
4480
|
+
// fieldTarget does for the corresponding dot reads.
|
|
4481
|
+
if (obj.type.kind === "record") {
|
|
4482
|
+
const actualShape = lowerer.shapes.get(obj.type.shapeId);
|
|
4483
|
+
if (!actualShape)
|
|
4484
|
+
throw new InternalCompilerError("record receiver is missing its stored shape");
|
|
4485
|
+
shapeId = obj.type.shapeId;
|
|
4486
|
+
shape = actualShape;
|
|
4487
|
+
}
|
|
4374
4488
|
if (litKey !== null) {
|
|
4375
4489
|
const field = shape.fields.find((f) => f.name === litKey);
|
|
4376
4490
|
if (field) {
|
|
@@ -6276,6 +6390,9 @@ export function lowerBinary(lowerer, expr) {
|
|
|
6276
6390
|
case ts.SyntaxKind.EqualsEqualsEqualsToken:
|
|
6277
6391
|
case ts.SyntaxKind.ExclamationEqualsEqualsToken: {
|
|
6278
6392
|
const negated = op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
6393
|
+
const indexed = tryLowerIndexedComparison(lowerer, left, right, negated, loc);
|
|
6394
|
+
if (indexed)
|
|
6395
|
+
return indexed;
|
|
6279
6396
|
if (plainBothNum)
|
|
6280
6397
|
return { kind: "bin", op: negated ? "!==" : "===", left, right, type: BOOL, loc };
|
|
6281
6398
|
if (bothStr)
|
|
@@ -6603,7 +6720,7 @@ export function lowerCaughtTypeofTest(lowerer, expr, loc) {
|
|
|
6603
6720
|
if (!ts.isStringLiteral(b)) {
|
|
6604
6721
|
lowerer.unsupported("SC1090", expr, "'typeof' catch-binding tests against non-literal strings");
|
|
6605
6722
|
}
|
|
6606
|
-
if (b.text === "string" || b.text === "number" || b.text === "boolean") {
|
|
6723
|
+
if (b.text === "string" || b.text === "number" || b.text === "boolean" || b.text === "object") {
|
|
6607
6724
|
return {
|
|
6608
6725
|
kind: "caughtTest",
|
|
6609
6726
|
value: { kind: "varRef", localId: local.id, type: CAUGHT, loc },
|
|
@@ -6613,8 +6730,7 @@ export function lowerCaughtTypeofTest(lowerer, expr, loc) {
|
|
|
6613
6730
|
loc,
|
|
6614
6731
|
};
|
|
6615
6732
|
}
|
|
6616
|
-
lowerer.unsupported("SC1090", b, `'typeof' catch-binding tests against "${b.text}" (only "string"/"number"/"boolean" `
|
|
6617
|
-
`narrow a catch binding; use 'instanceof' for objects)`);
|
|
6733
|
+
lowerer.unsupported("SC1090", b, `'typeof' catch-binding tests against "${b.text}" (only "string"/"number"/"boolean"/"object" are supported)`);
|
|
6618
6734
|
}
|
|
6619
6735
|
return null;
|
|
6620
6736
|
}
|