@scriptc/compiler 0.0.36 → 0.1.1
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 +7 -5
- package/ambient/scriptc-overrides.d.ts +0 -7
- package/ambient/scriptc.d.ts +1 -1
- package/dist/backend/c/exprs.js +69 -45
- package/dist/backend/c/exprs.js.map +1 -1
- package/dist/backend/c/may-throw.js +3 -0
- package/dist/backend/c/may-throw.js.map +1 -1
- package/dist/backend/c/stmts.js +18 -0
- package/dist/backend/c/stmts.js.map +1 -1
- package/dist/backend/c/walkers.js +5 -7
- package/dist/backend/c/walkers.js.map +1 -1
- package/dist/backend/external-c.d.ts +33 -0
- package/dist/backend/external-c.js +51 -0
- package/dist/backend/external-c.js.map +1 -0
- package/dist/backend/link-plan.d.ts +37 -0
- package/dist/backend/link-plan.js +26 -0
- package/dist/backend/link-plan.js.map +1 -0
- package/dist/backend/linker.d.ts +22 -0
- package/dist/backend/linker.js +236 -0
- package/dist/backend/linker.js.map +1 -0
- package/dist/backend/llvm/dyn.js +7 -0
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +34 -7
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +68 -54
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-context.d.ts +1 -1
- package/dist/backend/llvm/expr-dispatch.js +2 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +1 -1
- package/dist/backend/llvm/expr-primitives.js +20 -0
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +25 -1
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/walkers.js +31 -4
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +8 -1
- package/dist/backend/native-codegen.js +39 -25
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +42 -4
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info.d.ts +1 -1
- package/dist/backend/native-link-info.js +42 -18
- package/dist/backend/native-link-info.js.map +1 -1
- package/dist/backend/native-toolchain.test.js +5 -1
- package/dist/backend/native-toolchain.test.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.d.ts +1 -0
- package/dist/backend/runtime-pack-targets.test.js +54 -0
- package/dist/backend/runtime-pack-targets.test.js.map +1 -0
- package/dist/backend/runtime-pack.d.ts +5 -30
- package/dist/backend/runtime-pack.js +46 -141
- package/dist/backend/runtime-pack.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +49 -14
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/targets.d.ts +63 -17
- package/dist/backend/targets.js +251 -35
- package/dist/backend/targets.js.map +1 -1
- package/dist/backend/targets.test.js +27 -5
- package/dist/backend/targets.test.js.map +1 -1
- package/dist/coverage/surface-manifest.js +10 -1
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/frontend/lowering/array-values.d.ts +8 -0
- package/dist/frontend/lowering/array-values.js +60 -0
- package/dist/frontend/lowering/array-values.js.map +1 -0
- package/dist/frontend/lowering/lower-array-sort.d.ts +22 -0
- package/dist/frontend/lowering/lower-array-sort.js +619 -0
- package/dist/frontend/lowering/lower-array-sort.js.map +1 -0
- package/dist/frontend/lowering/lower-builtins.js +164 -4
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +3 -4
- package/dist/frontend/lowering/lower-calls.js +260 -27
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.js +728 -655
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +4 -0
- package/dist/frontend/lowering/lower-exprs.js +769 -101
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +47 -33
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +5 -4
- package/dist/frontend/lowering/lower-island.js +10 -5
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +10 -0
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +302 -71
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +74 -2
- package/dist/frontend/lowering/lowerer.js +1087 -10
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +10 -2
- package/dist/frontend/lowering/surfaces.js +15 -3
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +45 -23
- package/dist/index.js.map +1 -1
- package/dist/ir/ir.d.ts +65 -11
- package/dist/ir/ir.js +25 -25
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/serialize.d.ts +1 -1
- package/dist/ir/serialize.js +1 -1
- package/dist/ir/validate.js +84 -37
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/fence-eval.js +3 -1
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/int-infer.js +12 -1
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +4 -4
- package/dist/library/library-cache.test.js +5 -5
- package/dist/startup-cache.d.ts +9 -1
- package/dist/startup-cache.js +16 -1
- package/dist/startup-cache.js.map +1 -1
- package/package.json +17 -4
- package/surface-manifest.json +5 -5
|
@@ -360,10 +360,9 @@ export declare function lowerFfiCall(lowerer: Lowerer, expr: ts.CallExpression):
|
|
|
360
360
|
export declare function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr;
|
|
361
361
|
export declare function lowerDynDispatchMethodCall(lowerer: Lowerer, call: ts.CallExpression, access: ts.PropertyAccessExpression, recv: IrExpr, arrayReceiver: boolean): IrExpr | null;
|
|
362
362
|
/** Tagged templates `tag\`a${x}b\`` — ES's call: tag(strings, ...values).
|
|
363
|
-
* The strings object is
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* the tag the SAME array; two sites never share). TemplateStringsArray
|
|
363
|
+
* The strings object is a per-SITE lazily initialized hidden array global,
|
|
364
|
+
* so the spec's identity contract holds — the same site evaluated twice
|
|
365
|
+
* hands the tag the SAME array; two sites never share. TemplateStringsArray
|
|
367
366
|
* maps to string[] (type-mapper.ts), so the array rides the ordinary
|
|
368
367
|
* slot-directed coercion into whatever the tag's first parameter wants
|
|
369
368
|
* — string[] exactly, an `any` slot through the dyn boundary, a rest
|
|
@@ -101,7 +101,7 @@ export function paramShape(lowerer, param) {
|
|
|
101
101
|
}
|
|
102
102
|
return { type: abi, mode: "omittable", bodyType };
|
|
103
103
|
}
|
|
104
|
-
return { type: lowerer.irTypeOf(param.name), mode: "required" };
|
|
104
|
+
return { type: lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name)), mode: "required" };
|
|
105
105
|
}
|
|
106
106
|
if (param.dotDotDotToken) {
|
|
107
107
|
// A JS rest param with no static element type (`(...args)` — any[]):
|
|
@@ -124,7 +124,7 @@ export function paramShape(lowerer, param) {
|
|
|
124
124
|
return { type: DYN, mode: "dynRest" };
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
|
-
const type = lowerer.irTypeOf(param.name);
|
|
127
|
+
const type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
|
|
128
128
|
// Tuple-typed rest params don't map to an array; generic rest is the
|
|
129
129
|
// generic path's business. Anything non-array here is unmappable.
|
|
130
130
|
if (type.kind !== "array")
|
|
@@ -167,7 +167,7 @@ export function paramShape(lowerer, param) {
|
|
|
167
167
|
}
|
|
168
168
|
return { type: abi, mode: "omittable", bodyType };
|
|
169
169
|
}
|
|
170
|
-
const type = lowerer.irTypeOf(param.name);
|
|
170
|
+
const type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
|
|
171
171
|
if (param.questionToken && !lowerer.bareUndefinedArmedUnion(type) && type.kind !== "dyn" && type.kind !== "jsval") {
|
|
172
172
|
// `x?: unknown` where unknown came from an annotation: undefined is
|
|
173
173
|
// absorbed into the hole type, so no undefined ARM exists — but a
|
|
@@ -195,7 +195,7 @@ export function paramShapes(lowerer, params, signature, blameOf) {
|
|
|
195
195
|
return params.map((declParam, i) => {
|
|
196
196
|
const symbol = signature.getParameters()[i];
|
|
197
197
|
const tsType = symbol ? lowerer.checker.getTypeOfSymbol(symbol) : lowerer.typeOf(declParam.name);
|
|
198
|
-
const mapped = lowerer.mapTypeOf(tsType);
|
|
198
|
+
const mapped = lowerer.runtimeOptionalBindingType(declParam.name, lowerer.mapTypeOf(tsType) ?? lowerer.irTypeOf(declParam.name));
|
|
199
199
|
if (!mapped || mapped.kind === "void")
|
|
200
200
|
lowerer.badType(blameOf?.(declParam, i) ?? declParam.name, tsType);
|
|
201
201
|
if (declParam.dotDotDotToken) {
|
|
@@ -1437,6 +1437,9 @@ export function lowerGenericFnValue(lowerer, ref, info) {
|
|
|
1437
1437
|
fenceUnpinned();
|
|
1438
1438
|
const bindings = new Map();
|
|
1439
1439
|
unifySignatureBindings(lowerer, info, target, bindings);
|
|
1440
|
+
const hofBinding = runtimeOptionalHofGenericBinding(lowerer, ref, info);
|
|
1441
|
+
if (hofBinding)
|
|
1442
|
+
bindings.set(hofBinding.typeParam, hofBinding.type);
|
|
1440
1443
|
bindDefaultTypeParams(lowerer, info.typeParams, info.decl.typeParameters, bindings);
|
|
1441
1444
|
// A pinning signature that itself keeps type parameters (`let g: <T>(x:
|
|
1442
1445
|
// T) => T = identity` — storing the generic signature as such) binds
|
|
@@ -1457,6 +1460,31 @@ export function lowerGenericFnValue(lowerer, ref, info) {
|
|
|
1457
1460
|
lowerer.noteEdge(inst.name);
|
|
1458
1461
|
return { kind: "closure", fnName: inst.name, captures: [], type: funcType, loc };
|
|
1459
1462
|
}
|
|
1463
|
+
function runtimeOptionalHofGenericBinding(lowerer, ref, info) {
|
|
1464
|
+
let argument = ref;
|
|
1465
|
+
while (argument.parent && ts.isParenthesizedExpression(argument.parent))
|
|
1466
|
+
argument = argument.parent;
|
|
1467
|
+
const call = argument.parent;
|
|
1468
|
+
if (!ts.isCallExpression(call) || call.arguments[0] !== argument)
|
|
1469
|
+
return null;
|
|
1470
|
+
if (!ts.isPropertyAccessExpression(call.expression) || call.expression.name.text !== "map")
|
|
1471
|
+
return null;
|
|
1472
|
+
if (!lowerer.isStdlibMember(call.expression))
|
|
1473
|
+
return null;
|
|
1474
|
+
const receiver = lowerer.mapTypeOf(lowerer.typeOf(call.expression.expression));
|
|
1475
|
+
if (receiver?.kind !== "array")
|
|
1476
|
+
return null;
|
|
1477
|
+
const parameter = info.decl.parameters[0];
|
|
1478
|
+
if (!parameter || !ts.isIdentifier(parameter.name))
|
|
1479
|
+
return null;
|
|
1480
|
+
const parameterType = lowerer.typeOf(parameter.name);
|
|
1481
|
+
if ((parameterType.flags & ts.TypeFlags.TypeParameter) === 0)
|
|
1482
|
+
return null;
|
|
1483
|
+
const typeParam = parameterType.getSymbol();
|
|
1484
|
+
if (!typeParam || !info.typeParams.includes(typeParam))
|
|
1485
|
+
return null;
|
|
1486
|
+
return { typeParam, type: lowerer.runtimeOptionalType(receiver.elem) };
|
|
1487
|
+
}
|
|
1460
1488
|
/** The instance a pinned VALUE reference names: the declaration's modes
|
|
1461
1489
|
* over the DECLARED types mapped under the bindings (mapType's resolver
|
|
1462
1490
|
* substitutes — the instance-body trick), which is the same result the
|
|
@@ -3044,6 +3072,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
3044
3072
|
if (arg.type.kind === "string") {
|
|
3045
3073
|
return { kind: "libCall", fn: "num.fromString", args: [arg], type: F64, loc };
|
|
3046
3074
|
}
|
|
3075
|
+
const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc);
|
|
3076
|
+
if (optionalNumber)
|
|
3077
|
+
return optionalNumber;
|
|
3047
3078
|
lowerer.noLowering(`Number of ${lowerer.fmt(arg.type)} values`, argNode, arg.type.kind === "union"
|
|
3048
3079
|
? "numbers, booleans, and strings lower (the full ToNumber string grammar included) — narrow the union first"
|
|
3049
3080
|
: undefined);
|
|
@@ -3335,7 +3366,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3335
3366
|
const radix = expr.arguments[1]
|
|
3336
3367
|
? lowerer.lowerExprExpecting(expr.arguments[1], F64)
|
|
3337
3368
|
: { kind: "numLit", value: 0, type: F64, loc };
|
|
3338
|
-
const optional =
|
|
3369
|
+
const optional = optionalCallValue(lowerer, expr.arguments[0]);
|
|
3339
3370
|
if (optional?.type.kind === "union") {
|
|
3340
3371
|
const def = lowerer.unions.get(optional.type.unionId);
|
|
3341
3372
|
const stringTag = def?.arms.findIndex((arm) => arm.kind === "string") ?? -1;
|
|
@@ -3403,6 +3434,14 @@ export function lowerCall(lowerer, expr) {
|
|
|
3403
3434
|
expr.arguments.length === 1 &&
|
|
3404
3435
|
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
|
|
3405
3436
|
const name = expr.expression.text;
|
|
3437
|
+
if (name === "parseFloat") {
|
|
3438
|
+
const optional = optionalCallValue(lowerer, expr.arguments[0]);
|
|
3439
|
+
if (optional) {
|
|
3440
|
+
const parsed = lowerOptionalStringNumber(lowerer, optional, loc, "num.parseFloat", "parseFloat");
|
|
3441
|
+
if (parsed)
|
|
3442
|
+
return parsed;
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3406
3445
|
const probed = probeLower(lowerer, expr.arguments[0]);
|
|
3407
3446
|
if (name === "parseFloat" && probed?.type.kind === "string") {
|
|
3408
3447
|
return { kind: "libCall", fn: "num.parseFloat", args: [probed], type: F64, loc };
|
|
@@ -3433,13 +3472,12 @@ export function lowerCall(lowerer, expr) {
|
|
|
3433
3472
|
const loc = locOf(expr);
|
|
3434
3473
|
const argNode = expr.arguments[0];
|
|
3435
3474
|
if (name === "decodeURIComponent") {
|
|
3436
|
-
const d = lowerer.lowerExpr(argNode);
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
}
|
|
3440
|
-
return { kind: "libCall", fn: "str.decodeUriComponent", args: [d], type: STRING, loc };
|
|
3475
|
+
const d = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
3476
|
+
const s = lowerer.ensureString(d, argNode);
|
|
3477
|
+
return { kind: "libCall", fn: "str.decodeUriComponent", args: [s], type: STRING, loc };
|
|
3441
3478
|
}
|
|
3442
|
-
const
|
|
3479
|
+
const value = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
3480
|
+
const s = lowerer.ensureString(value, argNode);
|
|
3443
3481
|
return {
|
|
3444
3482
|
kind: "libCall",
|
|
3445
3483
|
fn: name === "encodeURIComponent" ? "str.encodeUriComponent" : "str.encodeUri",
|
|
@@ -3750,7 +3788,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3750
3788
|
lowerPromiseRejectCall(lowerer, expr, expr.expression) ??
|
|
3751
3789
|
// Before the island path: regex-argument replace/replaceAll/split
|
|
3752
3790
|
// lower STATICALLY; only the string-pattern overloads are island.
|
|
3753
|
-
lowerer
|
|
3791
|
+
lowerRegexMethodCallWithOptionalArg(lowerer, expr, expr.expression) ??
|
|
3754
3792
|
lowerer.lowerUrlMethodCall(expr, expr.expression) ??
|
|
3755
3793
|
lowerer.lowerSearchParamsMethodCall(expr, expr.expression) ??
|
|
3756
3794
|
lowerer.lowerStatsMethodCall(expr, expr.expression) ??
|
|
@@ -3789,11 +3827,11 @@ export function lowerCall(lowerer, expr) {
|
|
|
3789
3827
|
// TestContext surface (t.test/t.skip/t.diagnostic), t.assert.*.
|
|
3790
3828
|
lowerer.lowerTestMethodCall(expr, expr.expression) ??
|
|
3791
3829
|
lowerer.lowerTimeoutMethodCall(expr, expr.expression) ??
|
|
3792
|
-
lowerer
|
|
3830
|
+
lowerStringMethodCallWithOptionalArgs(lowerer, expr, expr.expression) ??
|
|
3793
3831
|
// Typed-array/Buffer receivers and the Buffer statics — before the
|
|
3794
3832
|
// island path (bytes never cross the boundary).
|
|
3795
3833
|
lowerer.lowerBytesMethodCall(expr, expr.expression) ??
|
|
3796
|
-
lowerer
|
|
3834
|
+
lowerBufferStaticCallWithOptionalArg(lowerer, expr, expr.expression) ??
|
|
3797
3835
|
// URL.revokeObjectURL's zero-argument contract (the one-argument
|
|
3798
3836
|
// form keeps the fence — createObjectURL does too).
|
|
3799
3837
|
lowerUrlStaticCall(lowerer, expr, expr.expression) ??
|
|
@@ -4057,6 +4095,160 @@ export function lowerCall(lowerer, expr) {
|
|
|
4057
4095
|
}
|
|
4058
4096
|
return { kind: "callValue", callee, args, type: callee.type.ret, loc };
|
|
4059
4097
|
}
|
|
4098
|
+
function lowerRegexMethodCallWithOptionalArg(lowerer, call, access) {
|
|
4099
|
+
const lowered = lowerer.lowerRegexMethodCall(call, access);
|
|
4100
|
+
if (lowered?.kind !== "regexIntrinsic" || lowered.method !== "test" || call.arguments.length !== 1)
|
|
4101
|
+
return lowered;
|
|
4102
|
+
const subject = lowered.args[0];
|
|
4103
|
+
if (subject?.type.kind !== "union" || lowerer.armTag(subject.type.unionId, UNDEFINED_T) < 0)
|
|
4104
|
+
return lowered;
|
|
4105
|
+
if (lowerer.mapTypeOf(lowerer.typeOf(call.arguments[0]))?.kind !== "string")
|
|
4106
|
+
return lowered;
|
|
4107
|
+
const present = lowerer.stripUndefinedArm(subject.type);
|
|
4108
|
+
if (present.kind !== "string")
|
|
4109
|
+
return lowered;
|
|
4110
|
+
return {
|
|
4111
|
+
...lowered,
|
|
4112
|
+
args: [lowerer.ensureString(subject, call.arguments[0])],
|
|
4113
|
+
};
|
|
4114
|
+
}
|
|
4115
|
+
function optionalCallValue(lowerer, node) {
|
|
4116
|
+
return lowerer.runtimeOptionalIdentifierValue(node)?.value ?? lowerAbsenceProbe(lowerer, node);
|
|
4117
|
+
}
|
|
4118
|
+
function lowerBufferStaticCallWithOptionalArg(lowerer, call, access) {
|
|
4119
|
+
const lowered = lowerer.lowerBufferStaticCall(call, access);
|
|
4120
|
+
if (lowered?.kind !== "bytesNew" || !lowered.source || lowered.source.type.kind !== "union")
|
|
4121
|
+
return lowered;
|
|
4122
|
+
const present = lowerer.stripUndefinedArm(lowered.source.type);
|
|
4123
|
+
const validSource = (present.kind === "array" && present.elem.kind === "f64") ||
|
|
4124
|
+
(present.kind === "bytes" && present.elem === "u8");
|
|
4125
|
+
if (!validSource)
|
|
4126
|
+
return lowered;
|
|
4127
|
+
const helper = lowerer.narrowedArmHelper(lowered.source.type.unionId, present, lowered.source.loc);
|
|
4128
|
+
return helper
|
|
4129
|
+
? {
|
|
4130
|
+
...lowered,
|
|
4131
|
+
source: { kind: "call", callee: helper, args: [lowered.source], type: present, loc: lowered.source.loc },
|
|
4132
|
+
}
|
|
4133
|
+
: lowered;
|
|
4134
|
+
}
|
|
4135
|
+
function lowerOptionalNumberDefault(lowerer, value, dflt, loc) {
|
|
4136
|
+
const widened = lowerer.runtimeOptionalWidening(value.type, F64);
|
|
4137
|
+
if (!widened || widened.kind !== "union")
|
|
4138
|
+
return null;
|
|
4139
|
+
const numberTag = lowerer.armTag(widened.unionId, F64);
|
|
4140
|
+
const undefinedTag = lowerer.armTag(widened.unionId, UNDEFINED_T);
|
|
4141
|
+
if (numberTag < 0 || undefinedTag < 0)
|
|
4142
|
+
return null;
|
|
4143
|
+
const key = `number.optionalDefault:${widened.unionId}:${dflt}`;
|
|
4144
|
+
let helper = lowerer.widthHelpers.get(key);
|
|
4145
|
+
if (!helper) {
|
|
4146
|
+
helper = `%number.optionalDefault.${lowerer.widthHelpers.size}`;
|
|
4147
|
+
lowerer.widthHelpers.set(key, helper);
|
|
4148
|
+
const input = varRef("value.0", widened, loc);
|
|
4149
|
+
lowerer.liftedFns.push({
|
|
4150
|
+
name: helper,
|
|
4151
|
+
params: [{ localId: "value.0", name: "value", type: widened }],
|
|
4152
|
+
returnType: F64,
|
|
4153
|
+
locals: [{ id: "value.0", name: "value", type: widened, mutable: false }],
|
|
4154
|
+
body: [
|
|
4155
|
+
{
|
|
4156
|
+
kind: "if",
|
|
4157
|
+
cond: { kind: "unionIsTag", unionId: widened.unionId, tag: undefinedTag, negated: false, value: input, type: BOOL, loc },
|
|
4158
|
+
then: [{ kind: "return", value: { kind: "numLit", value: dflt, type: F64, loc }, loc }],
|
|
4159
|
+
else_: null,
|
|
4160
|
+
loc,
|
|
4161
|
+
},
|
|
4162
|
+
{
|
|
4163
|
+
kind: "return",
|
|
4164
|
+
value: { kind: "unionNarrow", unionId: widened.unionId, tag: numberTag, value: input, type: F64, loc },
|
|
4165
|
+
loc,
|
|
4166
|
+
},
|
|
4167
|
+
],
|
|
4168
|
+
loc,
|
|
4169
|
+
});
|
|
4170
|
+
}
|
|
4171
|
+
return { kind: "call", callee: helper, args: [value], type: F64, loc };
|
|
4172
|
+
}
|
|
4173
|
+
function lowerStringMethodCallWithOptionalArgs(lowerer, call, access) {
|
|
4174
|
+
const lowered = lowerer.lowerStringMethodCall(call, access);
|
|
4175
|
+
if (lowered?.kind !== "strIntrinsic")
|
|
4176
|
+
return lowered;
|
|
4177
|
+
const args = [...lowered.args];
|
|
4178
|
+
let changed = false;
|
|
4179
|
+
const zeroDefaultArgs = lowered.method === "charCodeAt" || lowered.method === "charAt" ||
|
|
4180
|
+
lowered.method === "repeat" || lowered.method === "padStart" || lowered.method === "padEnd"
|
|
4181
|
+
? [0]
|
|
4182
|
+
: lowered.method === "slice" || lowered.method === "substring"
|
|
4183
|
+
? [0]
|
|
4184
|
+
: lowered.method === "indexOf" || lowered.method === "includes"
|
|
4185
|
+
? [1]
|
|
4186
|
+
: [];
|
|
4187
|
+
for (const index of zeroDefaultArgs) {
|
|
4188
|
+
const value = args[index];
|
|
4189
|
+
if (!value)
|
|
4190
|
+
continue;
|
|
4191
|
+
const coerced = lowerOptionalNumberDefault(lowerer, value, 0, value.loc);
|
|
4192
|
+
if (coerced) {
|
|
4193
|
+
args[index] = coerced;
|
|
4194
|
+
changed = true;
|
|
4195
|
+
}
|
|
4196
|
+
}
|
|
4197
|
+
if ((lowered.method === "indexOf" || lowered.method === "includes" ||
|
|
4198
|
+
lowered.method === "startsWith" || lowered.method === "endsWith") &&
|
|
4199
|
+
args[0]?.type.kind === "union" &&
|
|
4200
|
+
lowerer.runtimeOptionalWidening(args[0].type, STRING) !== null) {
|
|
4201
|
+
args[0] = lowerer.ensureString(args[0], call.arguments[0]);
|
|
4202
|
+
changed = true;
|
|
4203
|
+
}
|
|
4204
|
+
return changed ? { ...lowered, args } : lowered;
|
|
4205
|
+
}
|
|
4206
|
+
function lowerOptionalStringNumber(lowerer, arg, loc, fn = "num.fromString", label = "number") {
|
|
4207
|
+
if (arg.type.kind !== "union")
|
|
4208
|
+
return null;
|
|
4209
|
+
const def = lowerer.unions.get(arg.type.unionId);
|
|
4210
|
+
if (!def || def.arms.length !== 2)
|
|
4211
|
+
return null;
|
|
4212
|
+
const stringTag = lowerer.armTag(arg.type.unionId, STRING);
|
|
4213
|
+
const undefinedTag = lowerer.armTag(arg.type.unionId, UNDEFINED_T);
|
|
4214
|
+
if (stringTag < 0 || undefinedTag < 0)
|
|
4215
|
+
return null;
|
|
4216
|
+
const key = `${label}.optionalString:${arg.type.unionId}`;
|
|
4217
|
+
let helper = lowerer.widthHelpers.get(key);
|
|
4218
|
+
if (!helper) {
|
|
4219
|
+
helper = `%${label}.optionalString.${lowerer.widthHelpers.size}`;
|
|
4220
|
+
lowerer.widthHelpers.set(key, helper);
|
|
4221
|
+
const value = varRef("value.0", arg.type, loc);
|
|
4222
|
+
lowerer.liftedFns.push({
|
|
4223
|
+
name: helper,
|
|
4224
|
+
params: [{ localId: "value.0", name: "value", type: arg.type }],
|
|
4225
|
+
returnType: F64,
|
|
4226
|
+
locals: [{ id: "value.0", name: "value", type: arg.type, mutable: false }],
|
|
4227
|
+
body: [
|
|
4228
|
+
{
|
|
4229
|
+
kind: "if",
|
|
4230
|
+
cond: { kind: "unionIsTag", unionId: arg.type.unionId, tag: undefinedTag, negated: false, value, type: BOOL, loc },
|
|
4231
|
+
then: [{ kind: "return", value: { kind: "bin", op: "/", left: { kind: "numLit", value: 0, type: F64, loc }, right: { kind: "numLit", value: 0, type: F64, loc }, type: F64, loc }, loc }],
|
|
4232
|
+
else_: null,
|
|
4233
|
+
loc,
|
|
4234
|
+
},
|
|
4235
|
+
{
|
|
4236
|
+
kind: "return",
|
|
4237
|
+
value: {
|
|
4238
|
+
kind: "libCall",
|
|
4239
|
+
fn,
|
|
4240
|
+
args: [{ kind: "unionNarrow", unionId: arg.type.unionId, tag: stringTag, value, type: STRING, loc }],
|
|
4241
|
+
type: F64,
|
|
4242
|
+
loc,
|
|
4243
|
+
},
|
|
4244
|
+
loc,
|
|
4245
|
+
},
|
|
4246
|
+
],
|
|
4247
|
+
loc,
|
|
4248
|
+
});
|
|
4249
|
+
}
|
|
4250
|
+
return { kind: "call", callee: helper, args: [arg], type: F64, loc };
|
|
4251
|
+
}
|
|
4060
4252
|
/** The RUNTIME-ARITY spread call — `f(...args)`, the rest-forwarding idiom
|
|
4061
4253
|
* (`const f = (...args) => from(...args)`): a spread whose length is a
|
|
4062
4254
|
* runtime fact has no home in the compile-time completion, so the call
|
|
@@ -4920,10 +5112,9 @@ function templateEscapesValid(raw) {
|
|
|
4920
5112
|
return true;
|
|
4921
5113
|
}
|
|
4922
5114
|
/** Tagged templates `tag\`a${x}b\`` — ES's call: tag(strings, ...values).
|
|
4923
|
-
* The strings object is
|
|
4924
|
-
*
|
|
4925
|
-
*
|
|
4926
|
-
* the tag the SAME array; two sites never share). TemplateStringsArray
|
|
5115
|
+
* The strings object is a per-SITE lazily initialized hidden array global,
|
|
5116
|
+
* so the spec's identity contract holds — the same site evaluated twice
|
|
5117
|
+
* hands the tag the SAME array; two sites never share. TemplateStringsArray
|
|
4927
5118
|
* maps to string[] (type-mapper.ts), so the array rides the ordinary
|
|
4928
5119
|
* slot-directed coercion into whatever the tag's first parameter wants
|
|
4929
5120
|
* — string[] exactly, an `any` slot through the dyn boundary, a rest
|
|
@@ -4949,13 +5140,7 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
4949
5140
|
lowerer.unsupported("SC1090", p, "tagged templates with invalid escape sequences (the span cooks to undefined, which the strings array cannot carry)");
|
|
4950
5141
|
}
|
|
4951
5142
|
}
|
|
4952
|
-
const strings =
|
|
4953
|
-
kind: "templateStrings",
|
|
4954
|
-
key: `${loc.file}:${expr.template.getStart()}`,
|
|
4955
|
-
cooked: pieces.map((p) => p.text),
|
|
4956
|
-
type: arrayOf(STRING),
|
|
4957
|
-
loc,
|
|
4958
|
-
};
|
|
5143
|
+
const strings = () => loweredTemplateStrings(lowerer, expr, pieces.map((piece) => piece.text), loc);
|
|
4959
5144
|
const values = ts.isNoSubstitutionTemplateLiteral(expr.template)
|
|
4960
5145
|
? []
|
|
4961
5146
|
: expr.template.templateSpans.map((s) => s.expression);
|
|
@@ -5007,7 +5192,7 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
5007
5192
|
const sig = lowerer.fnSigOf(expr.tag);
|
|
5008
5193
|
if (sig) {
|
|
5009
5194
|
lowerer.noteEdge(sig.name);
|
|
5010
|
-
const args = completeArgs(lowerer, values, sig.params, loc, expr, [strings]);
|
|
5195
|
+
const args = completeArgs(lowerer, values, sig.params, loc, expr, [strings()]);
|
|
5011
5196
|
return reconcileOverloadReturn(lowerer, expr, { kind: "call", callee: sig.name, args, type: sig.returnType, loc });
|
|
5012
5197
|
}
|
|
5013
5198
|
// An ambient `declare function` nothing defines: Node throws
|
|
@@ -5034,7 +5219,7 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
5034
5219
|
const callee = lowerer.lowerExpr(expr.tag);
|
|
5035
5220
|
if (callee.type.kind === "dyn") {
|
|
5036
5221
|
const args = [
|
|
5037
|
-
lowerer.coerceInto(expr.template, strings, DYN),
|
|
5222
|
+
lowerer.coerceInto(expr.template, strings(), DYN),
|
|
5038
5223
|
...values.map((a) => lowerer.lowerExprExpecting(a, DYN)),
|
|
5039
5224
|
];
|
|
5040
5225
|
const calleeName = ts.isPropertyAccessExpression(expr.tag) || ts.isElementAccessExpression(expr.tag)
|
|
@@ -5046,6 +5231,53 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
5046
5231
|
}
|
|
5047
5232
|
lowerer.unsupported("SC1090", expr, "tagged templates with this tag form (top-level functions and dynamic values tag; call the function directly otherwise)");
|
|
5048
5233
|
}
|
|
5234
|
+
function loweredTemplateStrings(lowerer, expr, cooked, loc) {
|
|
5235
|
+
// Normal runtime construction keeps this array aligned with the current
|
|
5236
|
+
// ScrArr layout in both backends. The old static-header IR node encoded the
|
|
5237
|
+
// pre-sparse layout in LLVM and crashed as soon as a tag read its strings.
|
|
5238
|
+
const type = arrayOf(STRING);
|
|
5239
|
+
const key = `templateStringsGlobal:${loc.file}:${expr.template.getStart()}`;
|
|
5240
|
+
let getter = lowerer.widthHelpers.get(key);
|
|
5241
|
+
if (!getter) {
|
|
5242
|
+
const site = lowerer.globalsList.length;
|
|
5243
|
+
const globalId = `%g.templateStrings.${site}`;
|
|
5244
|
+
const readyId = `%g.templateStringsReady.${site}`;
|
|
5245
|
+
getter = `%templateStrings.get.${lowerer.widthHelpers.size}`;
|
|
5246
|
+
lowerer.widthHelpers.set(key, getter);
|
|
5247
|
+
lowerer.globalsList.push({ id: globalId, name: "%templateStrings", type, mutable: true }, { id: readyId, name: "%templateStringsReady", type: BOOL, mutable: true });
|
|
5248
|
+
lowerer.liftedFns.push({
|
|
5249
|
+
name: getter,
|
|
5250
|
+
params: [],
|
|
5251
|
+
returnType: type,
|
|
5252
|
+
locals: [],
|
|
5253
|
+
body: [
|
|
5254
|
+
{
|
|
5255
|
+
kind: "if",
|
|
5256
|
+
cond: { kind: "unary", op: "!", operand: varRef(readyId, BOOL, loc), type: BOOL, loc },
|
|
5257
|
+
then: [
|
|
5258
|
+
{
|
|
5259
|
+
kind: "assign",
|
|
5260
|
+
localId: globalId,
|
|
5261
|
+
value: {
|
|
5262
|
+
kind: "arrayLit",
|
|
5263
|
+
elems: cooked.map((value) => ({ kind: "strLit", value, type: STRING, loc })),
|
|
5264
|
+
type,
|
|
5265
|
+
loc,
|
|
5266
|
+
},
|
|
5267
|
+
loc,
|
|
5268
|
+
},
|
|
5269
|
+
{ kind: "assign", localId: readyId, value: { kind: "boolLit", value: true, type: BOOL, loc }, loc },
|
|
5270
|
+
],
|
|
5271
|
+
else_: null,
|
|
5272
|
+
loc,
|
|
5273
|
+
},
|
|
5274
|
+
{ kind: "return", value: varRef(globalId, type, loc), loc },
|
|
5275
|
+
],
|
|
5276
|
+
loc,
|
|
5277
|
+
});
|
|
5278
|
+
}
|
|
5279
|
+
return { kind: "call", callee: getter, args: [], type, loc };
|
|
5280
|
+
}
|
|
5049
5281
|
/** True when the identifier resolves (through import aliases) to a
|
|
5050
5282
|
* top-level function declaration of ANY program file (not merely a
|
|
5051
5283
|
* same-named local shadowing one). Functions declared directly in a
|
|
@@ -5107,6 +5339,7 @@ export function lambdaSignature(lowerer, node) {
|
|
|
5107
5339
|
let ret = ts.isArrowFunction(node) && !ts.isBlock(node.body) && isStreamUndefCallExpr(lowerer, node.body)
|
|
5108
5340
|
? VOID
|
|
5109
5341
|
: lowerer.declaredReturnType(node, node);
|
|
5342
|
+
ret = lowerer.runtimeOptionalFunctionReturnType(node, ret);
|
|
5110
5343
|
// A contextually-typed arrow/function EXPRESSION whose slot signature
|
|
5111
5344
|
// returns a UNION the inferred return doesn't spell adopts the slot's
|
|
5112
5345
|
// return as its ABI: `(n) => work()` (inferring Promise<void>) against
|