@scriptc/compiler 0.1.6 → 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 +45 -1
- 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-dynamic.js +10 -0
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +29 -0
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +8 -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/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/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/lower-builtins.js +15 -4
- 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 +140 -30
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +116 -16
- 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 +1 -1
- package/dist/frontend/lowering/surfaces.js +37 -6
- 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 +18 -12
- package/dist/ir/ir.js +3 -1
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/validate.js +14 -5
- package/dist/ir/validate.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 +120 -1
|
@@ -1006,6 +1006,13 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1006
1006
|
const canonical = stdlibGlobalNameOf(lowerer, expr) ?? expr.text;
|
|
1007
1007
|
return { kind: "strLit", value: `[builtin ${canonical}]`, type: STRING, loc };
|
|
1008
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
|
+
}
|
|
1009
1016
|
// The families with a WHY: each hint states what makes the
|
|
1010
1017
|
// surface genuinely non-static (or what to use instead).
|
|
1011
1018
|
const globalHints = {
|
|
@@ -2307,8 +2314,25 @@ export function maybeNarrow(lowerer, expr, node) {
|
|
|
2307
2314
|
return expr;
|
|
2308
2315
|
}
|
|
2309
2316
|
const tag = lowerer.armTag(expr.type.unionId, narrowed);
|
|
2310
|
-
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
|
+
}
|
|
2311
2334
|
return expr;
|
|
2335
|
+
}
|
|
2312
2336
|
return {
|
|
2313
2337
|
kind: "unionNarrow",
|
|
2314
2338
|
unionId: expr.type.unionId,
|
|
@@ -2365,12 +2389,11 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
|
|
|
2365
2389
|
}
|
|
2366
2390
|
return { kind: "call", callee: helper, args: [varRef(local.id, local.type, loc)], type: narrowed, loc };
|
|
2367
2391
|
}
|
|
2368
|
-
const valueTag = lowerer.armTag(local.type.unionId, narrowed);
|
|
2369
2392
|
const undefTag = lowerer.armTag(local.type.unionId, UNDEFINED_T);
|
|
2370
|
-
if (valueTag < 0 || undefTag < 0)
|
|
2371
|
-
throw new InternalCompilerError("runtime-optional local is missing its value or undefined arm");
|
|
2372
2393
|
const def = lowerer.unions.get(local.type.unionId);
|
|
2373
|
-
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) {
|
|
2374
2397
|
// The checker may narrow a runtime-optional capture to one arm of a
|
|
2375
2398
|
// value union (`Circle | Square | undefined` -> `Circle`). The
|
|
2376
2399
|
// two-arm fast path below cannot extract that arm safely: a later
|
|
@@ -2383,10 +2406,19 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
|
|
|
2383
2406
|
}
|
|
2384
2407
|
return { kind: "call", callee: helper, args: [varRef(local.id, local.type, loc)], type: narrowed, loc };
|
|
2385
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
|
+
}
|
|
2386
2418
|
const message = property === null
|
|
2387
2419
|
? `${expr.text} is not a function`
|
|
2388
2420
|
: `Cannot read properties of undefined (reading '${property}')`;
|
|
2389
|
-
return {
|
|
2421
|
+
return lowerer.maybeNarrow({
|
|
2390
2422
|
kind: "ternary",
|
|
2391
2423
|
cond: {
|
|
2392
2424
|
kind: "unionIsTag",
|
|
@@ -2397,18 +2429,18 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
|
|
|
2397
2429
|
type: BOOL,
|
|
2398
2430
|
loc,
|
|
2399
2431
|
},
|
|
2400
|
-
then: nodeThrowExpr(1, "", message,
|
|
2432
|
+
then: nodeThrowExpr(1, "", message, valueType, loc),
|
|
2401
2433
|
else_: {
|
|
2402
2434
|
kind: "unionNarrow",
|
|
2403
2435
|
unionId: local.type.unionId,
|
|
2404
2436
|
tag: valueTag,
|
|
2405
2437
|
value: varRef(local.id, local.type, loc),
|
|
2406
|
-
type:
|
|
2438
|
+
type: valueType,
|
|
2407
2439
|
loc,
|
|
2408
2440
|
},
|
|
2409
|
-
type:
|
|
2441
|
+
type: valueType,
|
|
2410
2442
|
loc,
|
|
2411
|
-
};
|
|
2443
|
+
}, narrowedNode);
|
|
2412
2444
|
}
|
|
2413
2445
|
function runtimeOptionalUseOf(expr) {
|
|
2414
2446
|
let receiver = expr;
|
|
@@ -3429,7 +3461,10 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3429
3461
|
export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
3430
3462
|
const loc = locOf(expr);
|
|
3431
3463
|
const ctxType = lowerer.checker.getContextualType(expr);
|
|
3432
|
-
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);
|
|
3433
3468
|
let mapped = expected ?? lowerer.mapTypeOf(tsType);
|
|
3434
3469
|
// A JS literal whose OWN inferred type is never-tainted
|
|
3435
3470
|
// (neverTaintedJsType — the evolving `const gb = []`, the mixed
|
|
@@ -3542,13 +3577,13 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
3542
3577
|
// literal constructs the tuple's record shape — one positional field
|
|
3543
3578
|
// per element, source order (which IS index order, so evaluation order
|
|
3544
3579
|
// is JS-exact). tsc has already checked the arity; the recount below
|
|
3545
|
-
// backstops `as` smuggling.
|
|
3580
|
+
// backstops `as` smuggling. Fixed tuple spreads have known positions.
|
|
3546
3581
|
if (mapped?.kind === "record") {
|
|
3547
3582
|
const shape = lowerer.shapes.get(mapped.shapeId);
|
|
3548
3583
|
if (shape?.tuple) {
|
|
3549
3584
|
const spread = expr.elements.find(ts.isSpreadElement);
|
|
3550
3585
|
if (spread) {
|
|
3551
|
-
lowerer
|
|
3586
|
+
return lowerTupleSpreadLiteral(lowerer, expr, mapped, shape);
|
|
3552
3587
|
}
|
|
3553
3588
|
if (expr.elements.length !== shape.fields.length) {
|
|
3554
3589
|
// tsc padded an UNDER-LENGTH literal against an optional-element
|
|
@@ -3817,6 +3852,62 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
3817
3852
|
loc,
|
|
3818
3853
|
};
|
|
3819
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
|
+
}
|
|
3820
3911
|
/** Convert an undefined-armed numeric value at an arithmetic use. Ordinary
|
|
3821
3912
|
* reads preserve their tagged value; JavaScript's ToNumber(undefined) is NaN,
|
|
3822
3913
|
* so compounds and binary arithmetic use this checked one-time extraction. */
|
|
@@ -4384,6 +4475,16 @@ export function lowerRecordKeyRead(lowerer, expr, shapeId, shape, includeUndefin
|
|
|
4384
4475
|
// to observe the missing value instead of throwing during that check.
|
|
4385
4476
|
return includeUndefined ? read : lowerer.maybeNarrow(read, expr);
|
|
4386
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
|
+
}
|
|
4387
4488
|
if (litKey !== null) {
|
|
4388
4489
|
const field = shape.fields.find((f) => f.name === litKey);
|
|
4389
4490
|
if (field) {
|
|
@@ -6619,7 +6720,7 @@ export function lowerCaughtTypeofTest(lowerer, expr, loc) {
|
|
|
6619
6720
|
if (!ts.isStringLiteral(b)) {
|
|
6620
6721
|
lowerer.unsupported("SC1090", expr, "'typeof' catch-binding tests against non-literal strings");
|
|
6621
6722
|
}
|
|
6622
|
-
if (b.text === "string" || b.text === "number" || b.text === "boolean") {
|
|
6723
|
+
if (b.text === "string" || b.text === "number" || b.text === "boolean" || b.text === "object") {
|
|
6623
6724
|
return {
|
|
6624
6725
|
kind: "caughtTest",
|
|
6625
6726
|
value: { kind: "varRef", localId: local.id, type: CAUGHT, loc },
|
|
@@ -6629,8 +6730,7 @@ export function lowerCaughtTypeofTest(lowerer, expr, loc) {
|
|
|
6629
6730
|
loc,
|
|
6630
6731
|
};
|
|
6631
6732
|
}
|
|
6632
|
-
lowerer.unsupported("SC1090", b, `'typeof' catch-binding tests against "${b.text}" (only "string"/"number"/"boolean" `
|
|
6633
|
-
`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)`);
|
|
6634
6734
|
}
|
|
6635
6735
|
return null;
|
|
6636
6736
|
}
|