@scriptc/compiler 0.0.16 → 0.0.18
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 +4 -4
- package/dist/backend/cc.d.ts +5 -0
- package/dist/backend/cc.js +2 -0
- package/dist/backend/cc.js.map +1 -1
- package/dist/backend/emission/emit-async.js +35 -2
- package/dist/backend/emission/emit-async.js.map +1 -1
- package/dist/backend/emission/emit-exprs.js +44 -6
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emitter.js +69 -11
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/emission/may-throw.d.ts +3 -3
- package/dist/backend/emission/may-throw.js +15 -4
- package/dist/backend/emission/may-throw.js.map +1 -1
- package/dist/backend/llvm/emitter.js +200 -21
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/coverage/surface-manifest.js +27 -9
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.js +4 -7
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +4 -4
- package/dist/frontend/lowering/lower-calls.js +44 -11
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +22 -17
- package/dist/frontend/lowering/lower-containers.js +628 -51
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +19 -1
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +2 -2
- package/dist/frontend/lowering/lower-island.js +57 -9
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +144 -10
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +8 -0
- package/dist/frontend/lowering/lower-stmts.js +408 -21
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +38 -0
- package/dist/frontend/lowering/lowerer.js +149 -2
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +8 -0
- package/dist/frontend/lowering/surfaces.js +10 -0
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/shared.d.ts +4 -0
- package/dist/frontend/shared.js +9 -3
- package/dist/frontend/shared.js.map +1 -1
- package/dist/frontend/ts7/program.js +5 -4
- package/dist/frontend/ts7/program.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +53 -22
- package/dist/ir/nodes.js +42 -0
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/serialize.d.ts +1 -1
- package/dist/ir/serialize.js +1 -1
- package/dist/ir/validate.js +99 -39
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/fence-eval.js +9 -1
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/int-infer.js +191 -25
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +206 -1
- package/dist/library/int-infer.test.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +27 -3
|
@@ -5,12 +5,75 @@
|
|
|
5
5
|
import * as ts from "../ts7/adapter.js";
|
|
6
6
|
import { BOOL, BYTES_U8, CAUGHT, DYN, F64, JSVAL, STRING, UNDEFINED_T, VOID, arrayOf, bytesOf, funcOf, isRefCounted, isSupportedIndexValue, isUnitType, typeEquals } from "../../ir/nodes.js";
|
|
7
7
|
import { ARRAY_METHODS, MAP_METHODS, SET_COMBINE_METHODS, SET_METHODS, STR_METHODS } from "./surfaces.js";
|
|
8
|
-
import { isRequireMainFilename, lowerDynObjectLiteral, probeLower, pureReemittable } from "./lower-exprs.js";
|
|
8
|
+
import { droppableStatic, isRequireMainFilename, lowerDynObjectLiteral, probeLower, pureReemittable } from "./lower-exprs.js";
|
|
9
9
|
import { forOfVarTarget, lowerDestructuringAssign } from "./lower-stmts.js";
|
|
10
10
|
import { isJsSourceFile, locOf } from "../program.js";
|
|
11
11
|
import { DYN_DISPATCH_METHODS, islandPrimitiveExit } from "./lower-calls.js";
|
|
12
12
|
import { typeKey } from "../types.js";
|
|
13
13
|
import { dynUndefinedExpr, own } from "./lowerer.js";
|
|
14
|
+
/** Lower an expression whose checker type is statically `undefined`/`void`.
|
|
15
|
+
* Optional builtin arguments use this before their ordinary expected-type
|
|
16
|
+
* coercion so every equivalent spelling (`undefined`, `void 0`, a typed
|
|
17
|
+
* binding, or an effectful call returning undefined) selects the default.
|
|
18
|
+
* An effectful `void e` is exact in this context: evaluate e, then produce
|
|
19
|
+
* undefined, instead of hitting value-position void's general fence. */
|
|
20
|
+
function lowerStaticallyUndefinedArg(L, node) {
|
|
21
|
+
const peelErasableWrappers = (value) => {
|
|
22
|
+
let expr = value;
|
|
23
|
+
while (ts.isParenthesizedExpression(expr) ||
|
|
24
|
+
ts.isAsExpression(expr) ||
|
|
25
|
+
ts.isTypeAssertion(expr) ||
|
|
26
|
+
ts.isSatisfiesExpression(expr)) {
|
|
27
|
+
expr = expr.expression;
|
|
28
|
+
}
|
|
29
|
+
return expr;
|
|
30
|
+
};
|
|
31
|
+
let expr = node;
|
|
32
|
+
while (ts.isParenthesizedExpression(expr))
|
|
33
|
+
expr = expr.expression;
|
|
34
|
+
if ((L.typeOf(expr).flags &
|
|
35
|
+
(ts.TypeFlags.Undefined | ts.TypeFlags.Void)) ===
|
|
36
|
+
0) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
// TypeScript erases `as`, angle-bracket assertions, and `satisfies`.
|
|
40
|
+
// Peel them only for the void recognition: a non-void assertion still
|
|
41
|
+
// lowers through the ordinary path below, preserving the checked-dynamic
|
|
42
|
+
// cast discipline. Nested voids add no effects of their own, so the one
|
|
43
|
+
// innermost operand carries the complete runtime evaluation.
|
|
44
|
+
expr = peelErasableWrappers(expr);
|
|
45
|
+
let sawVoid = false;
|
|
46
|
+
while (ts.isVoidExpression(expr)) {
|
|
47
|
+
sawVoid = true;
|
|
48
|
+
expr = peelErasableWrappers(expr.expression);
|
|
49
|
+
}
|
|
50
|
+
if (sawVoid) {
|
|
51
|
+
// The caller discards this token before producing the parameter
|
|
52
|
+
// default, so the operand itself carries exactly the required effects;
|
|
53
|
+
// no bare undefined value needs to enter the IR.
|
|
54
|
+
return L.lowerExpr(expr);
|
|
55
|
+
}
|
|
56
|
+
return L.lowerExpr(node);
|
|
57
|
+
}
|
|
58
|
+
/** Preserve a statically-undefined argument's effects, then answer the
|
|
59
|
+
* optional parameter's already-lowered default value. */
|
|
60
|
+
function defaultAfterUndefined(value, defaultValue) {
|
|
61
|
+
if (droppableStatic(value))
|
|
62
|
+
return defaultValue;
|
|
63
|
+
return {
|
|
64
|
+
kind: "seqExpr",
|
|
65
|
+
stmts: [{ kind: "exprStmt", expr: value, loc: value.loc }],
|
|
66
|
+
result: defaultValue,
|
|
67
|
+
type: defaultValue.type,
|
|
68
|
+
loc: value.loc,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function lowerOptionalDefaultArg(L, node, expected, defaultValue) {
|
|
72
|
+
const undefinedArg = lowerStaticallyUndefinedArg(L, node);
|
|
73
|
+
return undefinedArg
|
|
74
|
+
? defaultAfterUndefined(undefinedArg, defaultValue)
|
|
75
|
+
: L.lowerExprExpecting(node, expected);
|
|
76
|
+
}
|
|
14
77
|
/** Ambient array method calls. `push`/`pop`/`indexOf`/`includes`/`join`
|
|
15
78
|
* lower to arrIntrinsic; the HOF family — `map`/`filter`/`forEach`/
|
|
16
79
|
* `find`/`some`/`every`/`flatMap`/`reduce`/`reduceRight` — desugars to a
|
|
@@ -105,8 +168,72 @@ export function lowerArrayMethodCall(L, call, access) {
|
|
|
105
168
|
elem = receiver.type.elem;
|
|
106
169
|
}
|
|
107
170
|
}
|
|
108
|
-
if (name === "sort")
|
|
171
|
+
if (name === "sort" || name === "toSorted") {
|
|
109
172
|
return lowerArraySortCall(L, call, access, elem, receiverIr);
|
|
173
|
+
}
|
|
174
|
+
if (name === "toReversed") {
|
|
175
|
+
if (call.arguments.length !== 0) {
|
|
176
|
+
L.noLowering(`.toReversed with ${call.arguments.length} arguments`, call);
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
kind: "arrIntrinsic",
|
|
180
|
+
method: "toReversed",
|
|
181
|
+
receiver: L.lowerExpr(access.expression),
|
|
182
|
+
args: [],
|
|
183
|
+
type: receiverIr,
|
|
184
|
+
loc,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (name === "with") {
|
|
188
|
+
if (call.arguments.length !== 2 || call.arguments.some(ts.isSpreadElement)) {
|
|
189
|
+
L.noLowering(`.with with ${call.arguments.length} arguments`, call);
|
|
190
|
+
}
|
|
191
|
+
const receiver = L.lowerExpr(access.expression);
|
|
192
|
+
const index = L.lowerExprExpecting(call.arguments[0], F64);
|
|
193
|
+
const value = L.coerceInto(call.arguments[1], L.lowerExpr(call.arguments[1]), elem);
|
|
194
|
+
return {
|
|
195
|
+
kind: "arrIntrinsic",
|
|
196
|
+
method: "with",
|
|
197
|
+
receiver,
|
|
198
|
+
args: [index, value],
|
|
199
|
+
type: receiverIr,
|
|
200
|
+
loc,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (name === "toSpliced") {
|
|
204
|
+
if (call.arguments.some(ts.isSpreadElement)) {
|
|
205
|
+
L.unsupported("SC1090", call, "spread arguments to Array.toSpliced");
|
|
206
|
+
}
|
|
207
|
+
const receiver = L.lowerExpr(access.expression);
|
|
208
|
+
const start = call.arguments[0]
|
|
209
|
+
? L.lowerExprExpecting(call.arguments[0], F64)
|
|
210
|
+
: { kind: "numLit", value: 0, type: F64, loc };
|
|
211
|
+
const deleteCountDefault = {
|
|
212
|
+
kind: "numLit",
|
|
213
|
+
value: NaN,
|
|
214
|
+
type: F64,
|
|
215
|
+
loc,
|
|
216
|
+
};
|
|
217
|
+
const deleteCount = call.arguments.length === 0
|
|
218
|
+
? { kind: "numLit", value: 0, type: F64, loc }
|
|
219
|
+
: call.arguments[1]
|
|
220
|
+
? lowerOptionalDefaultArg(L, call.arguments[1], F64, deleteCountDefault)
|
|
221
|
+
: { kind: "numLit", value: Infinity, type: F64, loc };
|
|
222
|
+
const items = {
|
|
223
|
+
kind: "arrayLit",
|
|
224
|
+
elems: call.arguments.slice(2).map((arg) => L.coerceInto(arg, L.lowerExpr(arg), elem)),
|
|
225
|
+
type: receiverIr,
|
|
226
|
+
loc,
|
|
227
|
+
};
|
|
228
|
+
return {
|
|
229
|
+
kind: "arrIntrinsic",
|
|
230
|
+
method: "toSpliced",
|
|
231
|
+
receiver,
|
|
232
|
+
args: [start, deleteCount, items],
|
|
233
|
+
type: receiverIr,
|
|
234
|
+
loc,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
110
237
|
// The lib declares wider call forms than the lowered surface —
|
|
111
238
|
// indexOf/includes take a fromIndex, join's separator is optional, the
|
|
112
239
|
// predicate/mapping HOFs take a thisArg. Each unlowered form is fenced
|
|
@@ -1287,40 +1414,45 @@ function reduceHelper(L, method, elem, accT, arity, hasInit, loc) {
|
|
|
1287
1414
|
L.liftedFns.push({ name, params, returnType: accT, locals, body, loc });
|
|
1288
1415
|
return name;
|
|
1289
1416
|
}
|
|
1290
|
-
/** `a.sort(cmp)`
|
|
1291
|
-
*
|
|
1292
|
-
*
|
|
1293
|
-
*
|
|
1294
|
-
*
|
|
1295
|
-
*
|
|
1296
|
-
*
|
|
1297
|
-
*
|
|
1298
|
-
*
|
|
1299
|
-
*
|
|
1300
|
-
*
|
|
1301
|
-
*
|
|
1302
|
-
*
|
|
1303
|
-
*
|
|
1417
|
+
/** `a.sort(cmp)` / `a.toSorted(cmp)`, desugared to an interned synthetic
|
|
1418
|
+
* function like the other array HOFs. sort mutates and returns the receiver;
|
|
1419
|
+
* toSorted takes its shallow snapshot INSIDE the helper, after the receiver
|
|
1420
|
+
* and comparator expressions have both been evaluated, then sorts and
|
|
1421
|
+
* returns that copy without touching the receiver. The loop is a
|
|
1422
|
+
* binary-free INSERTION sort: stable (equal-comparing elements keep their
|
|
1423
|
+
* source order, which is what Node's stable TimSort produces for any
|
|
1424
|
+
* consistent comparator) and JS-faithful on the comparator contract — an
|
|
1425
|
+
* element moves left only while cmp(left, v) > 0, so a NaN or 0 result holds
|
|
1426
|
+
* position exactly like the spec's "treat as equal". The SEQUENCE of
|
|
1427
|
+
* comparator calls differs from V8's TimSort (SEMANTICS.md); results are
|
|
1428
|
+
* identical for consistent comparators. The comparator-less form lowers for
|
|
1429
|
+
* STRING elements only — JS's default converts every element to string and
|
|
1430
|
+
* compares UTF-16 units, so the interned synthesized comparator selects the
|
|
1431
|
+
* runtime's code-unit ordering rather than scriptc's documented code-point
|
|
1432
|
+
* relational operators. For numbers that default is the notorious string
|
|
1433
|
+
* sort ([10, 9, 1] → [1, 10, 9]), deliberately fenced toward an explicit
|
|
1304
1434
|
* comparator. */
|
|
1305
1435
|
export function lowerArraySortCall(L, call, access, elem, arrT) {
|
|
1306
1436
|
const loc = locOf(call);
|
|
1437
|
+
const method = access.name.text === "toSorted" ? "toSorted" : "sort";
|
|
1438
|
+
const copyFirst = method === "toSorted";
|
|
1307
1439
|
if (call.arguments.length === 0 && elem.kind === "string") {
|
|
1308
1440
|
const receiver = L.lowerExpr(access.expression);
|
|
1309
1441
|
const cmp = defaultStringCmpHelper(L, loc);
|
|
1310
1442
|
const fnT = funcOf([STRING, STRING], F64);
|
|
1311
|
-
const key =
|
|
1443
|
+
const key = `${method}:${typeKey(STRING)}:2`;
|
|
1312
1444
|
let helper = L.arrHofHelpers.get(key);
|
|
1313
1445
|
if (!helper) {
|
|
1314
|
-
helper = `%arr
|
|
1446
|
+
helper = `%arr.${method}.${L.arrHofHelpers.size}`;
|
|
1315
1447
|
L.arrHofHelpers.set(key, helper);
|
|
1316
|
-
L.liftedFns.push(buildArraySortFn(helper, STRING, 2, loc));
|
|
1448
|
+
L.liftedFns.push(buildArraySortFn(helper, STRING, 2, copyFirst, null, loc));
|
|
1317
1449
|
}
|
|
1318
1450
|
const fnArg = { kind: "closure", fnName: cmp, captures: [], type: fnT, loc };
|
|
1319
1451
|
return { kind: "call", callee: helper, args: [receiver, fnArg], type: arrT, loc };
|
|
1320
1452
|
}
|
|
1321
1453
|
if (call.arguments.length !== 1) {
|
|
1322
|
-
L.noLowering(
|
|
1323
|
-
|
|
1454
|
+
L.noLowering(`.${method} with ${call.arguments.length} arguments`, call, "the default string-conversion ordering lowers only for string[] — pass a comparator: " +
|
|
1455
|
+
`${method}((a, b) => a - b) for numbers`);
|
|
1324
1456
|
}
|
|
1325
1457
|
const receiver = L.lowerExpr(access.expression);
|
|
1326
1458
|
const argNode = call.arguments[0];
|
|
@@ -1335,12 +1467,13 @@ export function lowerArraySortCall(L, call, access, elem, arrT) {
|
|
|
1335
1467
|
L.badType(argNode, L.typeOf(argNode));
|
|
1336
1468
|
}
|
|
1337
1469
|
const arity = fnArg.type.params.length;
|
|
1338
|
-
const key =
|
|
1470
|
+
const key = `${method}:${typeKey(elem)}:${arity}`;
|
|
1339
1471
|
let helper = L.arrHofHelpers.get(key);
|
|
1340
1472
|
if (!helper) {
|
|
1341
|
-
helper = `%arr
|
|
1473
|
+
helper = `%arr.${method}.${L.arrHofHelpers.size}`;
|
|
1342
1474
|
L.arrHofHelpers.set(key, helper);
|
|
1343
|
-
L.
|
|
1475
|
+
const undefinedTag = elem.kind === "union" ? L.armTag(elem.unionId, UNDEFINED_T) : -1;
|
|
1476
|
+
L.liftedFns.push(buildArraySortFn(helper, elem, arity, copyFirst, undefinedTag >= 0 ? undefinedTag : null, loc));
|
|
1344
1477
|
}
|
|
1345
1478
|
return { kind: "call", callee: helper, args: [receiver, fnArg], type: arrT, loc };
|
|
1346
1479
|
}
|
|
@@ -1348,9 +1481,9 @@ export function lowerArraySortCall(L, call, access, elem, arrT) {
|
|
|
1348
1481
|
*
|
|
1349
1482
|
* (a, b) => a < b ? -1 : a > b ? 1 : 0
|
|
1350
1483
|
*
|
|
1351
|
-
*
|
|
1352
|
-
*
|
|
1353
|
-
*
|
|
1484
|
+
* The dedicated UTF-16 comparison flag keeps this exact across
|
|
1485
|
+
* supplementary-plane code points and U+E000..U+FFFF, where the runtime's
|
|
1486
|
+
* ordinary code-point relational order deliberately differs. */
|
|
1354
1487
|
function defaultStringCmpHelper(L, loc) {
|
|
1355
1488
|
const key = "sortCmpStr";
|
|
1356
1489
|
const existing = L.arrHofHelpers.get(key);
|
|
@@ -1361,7 +1494,7 @@ function defaultStringCmpHelper(L, loc) {
|
|
|
1361
1494
|
const ref = (localId) => ({ kind: "varRef", localId, type: STRING, loc });
|
|
1362
1495
|
const num = (value) => ({ kind: "numLit", value, type: F64, loc });
|
|
1363
1496
|
const cmp = (op) => ({
|
|
1364
|
-
kind: "strCmp", op, left: ref("a.0"), right: ref("b.0"), type: BOOL, loc,
|
|
1497
|
+
kind: "strCmp", op, left: ref("a.0"), right: ref("b.0"), utf16: true, type: BOOL, loc,
|
|
1365
1498
|
});
|
|
1366
1499
|
const body = [
|
|
1367
1500
|
{
|
|
@@ -1396,16 +1529,18 @@ function defaultStringCmpHelper(L, loc) {
|
|
|
1396
1529
|
/** The insertion-sort loop, from existing IR nodes:
|
|
1397
1530
|
*
|
|
1398
1531
|
* n = a.length;
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1532
|
+
* for (i = 1; i < n; i++) {
|
|
1533
|
+
* v = a[i]; j = i - 1;
|
|
1534
|
+
* while (j >= 0) {
|
|
1535
|
+
* if (CompareArrayElements(a[j], v, f) > 0) {
|
|
1536
|
+
* a[j + 1] = a[j]; j = j - 1;
|
|
1537
|
+
* } else break;
|
|
1403
1538
|
* }
|
|
1404
1539
|
* a[j + 1] = v;
|
|
1405
1540
|
* }
|
|
1406
1541
|
* return a;
|
|
1407
1542
|
*/
|
|
1408
|
-
function buildArraySortFn(name, elem, arity, loc) {
|
|
1543
|
+
function buildArraySortFn(name, elem, arity, copyFirst, undefinedTag, loc) {
|
|
1409
1544
|
const arrT = arrayOf(elem);
|
|
1410
1545
|
const fnT = funcOf([elem, elem].slice(0, arity), F64);
|
|
1411
1546
|
const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
|
|
@@ -1413,26 +1548,80 @@ function buildArraySortFn(name, elem, arity, loc) {
|
|
|
1413
1548
|
const j = ref("j.0", F64);
|
|
1414
1549
|
const at = (index) => ({ kind: "arrayGet", arr: ref("a.0", arrT), index, type: elem, loc });
|
|
1415
1550
|
const jPlus1 = { kind: "bin", op: "+", left: j, right: num(1), type: F64, loc };
|
|
1551
|
+
const isUndefined = (value) => {
|
|
1552
|
+
if (elem.kind === "union" && undefinedTag !== null) {
|
|
1553
|
+
return {
|
|
1554
|
+
kind: "unionIsTag",
|
|
1555
|
+
unionId: elem.unionId,
|
|
1556
|
+
tag: undefinedTag,
|
|
1557
|
+
negated: false,
|
|
1558
|
+
value,
|
|
1559
|
+
type: BOOL,
|
|
1560
|
+
loc,
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
if (elem.kind === "jsval") {
|
|
1564
|
+
return {
|
|
1565
|
+
kind: "jsOp",
|
|
1566
|
+
op: "eq",
|
|
1567
|
+
args: [
|
|
1568
|
+
value,
|
|
1569
|
+
{ kind: "jsOp", op: "undefLit", args: [], type: JSVAL, loc },
|
|
1570
|
+
],
|
|
1571
|
+
type: BOOL,
|
|
1572
|
+
loc,
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
return null;
|
|
1576
|
+
};
|
|
1577
|
+
const compareGreater = {
|
|
1578
|
+
kind: "bin",
|
|
1579
|
+
op: ">",
|
|
1580
|
+
left: {
|
|
1581
|
+
kind: "callValue",
|
|
1582
|
+
callee: ref("f.0", fnT),
|
|
1583
|
+
args: [at(j), ref("v.0", elem)].slice(0, arity),
|
|
1584
|
+
type: F64,
|
|
1585
|
+
loc,
|
|
1586
|
+
},
|
|
1587
|
+
right: num(0),
|
|
1588
|
+
type: BOOL,
|
|
1589
|
+
loc,
|
|
1590
|
+
};
|
|
1591
|
+
const leftUndefined = isUndefined(at(j));
|
|
1592
|
+
const valueUndefined = isUndefined(ref("v.0", elem));
|
|
1593
|
+
// CompareArrayElements: undefined always sinks and never reaches the
|
|
1594
|
+
// user comparator. Ternaries preserve that callback suppression.
|
|
1595
|
+
const shouldShift = leftUndefined !== null && valueUndefined !== null
|
|
1596
|
+
? {
|
|
1597
|
+
kind: "ternary",
|
|
1598
|
+
cond: leftUndefined,
|
|
1599
|
+
then: {
|
|
1600
|
+
kind: "unary",
|
|
1601
|
+
op: "!",
|
|
1602
|
+
operand: valueUndefined,
|
|
1603
|
+
type: BOOL,
|
|
1604
|
+
loc,
|
|
1605
|
+
},
|
|
1606
|
+
else_: {
|
|
1607
|
+
kind: "ternary",
|
|
1608
|
+
cond: valueUndefined,
|
|
1609
|
+
then: { kind: "boolLit", value: false, type: BOOL, loc },
|
|
1610
|
+
else_: compareGreater,
|
|
1611
|
+
type: BOOL,
|
|
1612
|
+
loc,
|
|
1613
|
+
},
|
|
1614
|
+
type: BOOL,
|
|
1615
|
+
loc,
|
|
1616
|
+
}
|
|
1617
|
+
: compareGreater;
|
|
1416
1618
|
const shiftLoop = {
|
|
1417
1619
|
kind: "while",
|
|
1418
1620
|
cond: { kind: "bin", op: ">=", left: j, right: num(0), type: BOOL, loc },
|
|
1419
1621
|
body: [
|
|
1420
1622
|
{
|
|
1421
1623
|
kind: "if",
|
|
1422
|
-
cond:
|
|
1423
|
-
kind: "bin",
|
|
1424
|
-
op: ">",
|
|
1425
|
-
left: {
|
|
1426
|
-
kind: "callValue",
|
|
1427
|
-
callee: ref("f.0", fnT),
|
|
1428
|
-
args: [at(j), ref("v.0", elem)].slice(0, arity),
|
|
1429
|
-
type: F64,
|
|
1430
|
-
loc,
|
|
1431
|
-
},
|
|
1432
|
-
right: num(0),
|
|
1433
|
-
type: BOOL,
|
|
1434
|
-
loc,
|
|
1435
|
-
},
|
|
1624
|
+
cond: shouldShift,
|
|
1436
1625
|
then: [
|
|
1437
1626
|
{ kind: "arraySet", arr: ref("a.0", arrT), index: jPlus1, value: at(j), loc },
|
|
1438
1627
|
{ kind: "assign", localId: "j.0", value: { kind: "bin", op: "-", left: j, right: num(1), type: F64, loc }, loc },
|
|
@@ -1444,6 +1633,21 @@ function buildArraySortFn(name, elem, arity, loc) {
|
|
|
1444
1633
|
loc,
|
|
1445
1634
|
};
|
|
1446
1635
|
const body = [
|
|
1636
|
+
...(copyFirst
|
|
1637
|
+
? [{
|
|
1638
|
+
kind: "assign",
|
|
1639
|
+
localId: "a.0",
|
|
1640
|
+
value: {
|
|
1641
|
+
kind: "arrIntrinsic",
|
|
1642
|
+
method: "slice",
|
|
1643
|
+
receiver: ref("a.0", arrT),
|
|
1644
|
+
args: [],
|
|
1645
|
+
type: arrT,
|
|
1646
|
+
loc,
|
|
1647
|
+
},
|
|
1648
|
+
loc,
|
|
1649
|
+
}]
|
|
1650
|
+
: []),
|
|
1447
1651
|
readLenStmt(arrT, loc),
|
|
1448
1652
|
{
|
|
1449
1653
|
kind: "for",
|
|
@@ -1484,6 +1688,294 @@ function buildArraySortFn(name, elem, arity, loc) {
|
|
|
1484
1688
|
loc,
|
|
1485
1689
|
};
|
|
1486
1690
|
}
|
|
1691
|
+
/** Uint8Array.prototype.toSorted. The receiver/comparator expressions are
|
|
1692
|
+
* evaluated before entering the helper; the helper snapshots with
|
|
1693
|
+
* TypedArray.prototype.slice before its first comparison, then performs
|
|
1694
|
+
* the same stable insertion walk as Array.toSorted. Uint8Array's default
|
|
1695
|
+
* comparator is numeric ascending, so its comparator-less form needs no
|
|
1696
|
+
* string-conversion machinery. */
|
|
1697
|
+
function lowerBytesToSortedCall(L, call, access, bytesT) {
|
|
1698
|
+
const loc = locOf(call);
|
|
1699
|
+
if (call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement)) {
|
|
1700
|
+
L.noLowering(`.toSorted with ${call.arguments.length} arguments on Uint8Array`, call);
|
|
1701
|
+
}
|
|
1702
|
+
const receiver = L.lowerExpr(access.expression);
|
|
1703
|
+
const undefinedArg = call.arguments[0]
|
|
1704
|
+
? lowerStaticallyUndefinedArg(L, call.arguments[0])
|
|
1705
|
+
: null;
|
|
1706
|
+
if (call.arguments.length === 0 || undefinedArg) {
|
|
1707
|
+
const key = "bytes.toSorted:u8:default";
|
|
1708
|
+
let helper = L.arrHofHelpers.get(key);
|
|
1709
|
+
if (!helper) {
|
|
1710
|
+
helper = `%bytes.toSorted.${L.arrHofHelpers.size}`;
|
|
1711
|
+
L.arrHofHelpers.set(key, helper);
|
|
1712
|
+
L.liftedFns.push(buildBytesSortFn(helper, 0, false, loc));
|
|
1713
|
+
}
|
|
1714
|
+
if (!undefinedArg || droppableStatic(undefinedArg)) {
|
|
1715
|
+
return { kind: "call", callee: helper, args: [receiver], type: bytesT, loc };
|
|
1716
|
+
}
|
|
1717
|
+
// The default helper takes no comparator argument. Snapshot the
|
|
1718
|
+
// receiver into a hidden local so the discarded undefined argument
|
|
1719
|
+
// still evaluates after the receiver and before the helper call.
|
|
1720
|
+
const saved = L.declareHiddenLocal("%bytesSortRecv", bytesT);
|
|
1721
|
+
const savedRef = {
|
|
1722
|
+
kind: "varRef",
|
|
1723
|
+
localId: saved.id,
|
|
1724
|
+
type: bytesT,
|
|
1725
|
+
loc,
|
|
1726
|
+
};
|
|
1727
|
+
return {
|
|
1728
|
+
kind: "seqExpr",
|
|
1729
|
+
stmts: [
|
|
1730
|
+
{ kind: "varDecl", localId: saved.id, init: receiver, loc },
|
|
1731
|
+
{ kind: "exprStmt", expr: undefinedArg, loc: undefinedArg.loc },
|
|
1732
|
+
],
|
|
1733
|
+
result: {
|
|
1734
|
+
kind: "call",
|
|
1735
|
+
callee: helper,
|
|
1736
|
+
args: [savedRef],
|
|
1737
|
+
type: bytesT,
|
|
1738
|
+
loc,
|
|
1739
|
+
},
|
|
1740
|
+
type: bytesT,
|
|
1741
|
+
loc,
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
const argNode = call.arguments[0];
|
|
1745
|
+
const fnArg = L.lowerExpr(argNode);
|
|
1746
|
+
if (fnArg.type.kind !== "func" ||
|
|
1747
|
+
fnArg.type.params.length > 2 ||
|
|
1748
|
+
!fnArg.type.params.every((p) => p.kind === "f64") ||
|
|
1749
|
+
fnArg.type.ret.kind !== "f64") {
|
|
1750
|
+
L.badType(argNode, L.typeOf(argNode));
|
|
1751
|
+
}
|
|
1752
|
+
const arity = fnArg.type.params.length;
|
|
1753
|
+
const key = `bytes.toSorted:u8:${arity}`;
|
|
1754
|
+
let helper = L.arrHofHelpers.get(key);
|
|
1755
|
+
if (!helper) {
|
|
1756
|
+
helper = `%bytes.toSorted.${L.arrHofHelpers.size}`;
|
|
1757
|
+
L.arrHofHelpers.set(key, helper);
|
|
1758
|
+
L.liftedFns.push(buildBytesSortFn(helper, arity, true, loc));
|
|
1759
|
+
}
|
|
1760
|
+
return {
|
|
1761
|
+
kind: "call",
|
|
1762
|
+
callee: helper,
|
|
1763
|
+
args: [receiver, fnArg],
|
|
1764
|
+
type: bytesT,
|
|
1765
|
+
loc,
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
function buildBytesSortFn(name, arity, hasComparator, loc) {
|
|
1769
|
+
const bytesT = BYTES_U8;
|
|
1770
|
+
const fnT = funcOf([F64, F64].slice(0, arity), F64);
|
|
1771
|
+
const ref = (localId, type) => ({
|
|
1772
|
+
kind: "varRef",
|
|
1773
|
+
localId,
|
|
1774
|
+
type,
|
|
1775
|
+
loc,
|
|
1776
|
+
});
|
|
1777
|
+
const num = (value) => ({
|
|
1778
|
+
kind: "numLit",
|
|
1779
|
+
value,
|
|
1780
|
+
type: F64,
|
|
1781
|
+
loc,
|
|
1782
|
+
});
|
|
1783
|
+
const j = ref("j.0", F64);
|
|
1784
|
+
const at = (index) => ({
|
|
1785
|
+
kind: "bytesIntrinsic",
|
|
1786
|
+
method: "get",
|
|
1787
|
+
receiver: ref("a.0", bytesT),
|
|
1788
|
+
args: [index],
|
|
1789
|
+
type: F64,
|
|
1790
|
+
loc,
|
|
1791
|
+
});
|
|
1792
|
+
const jPlus1 = {
|
|
1793
|
+
kind: "bin",
|
|
1794
|
+
op: "+",
|
|
1795
|
+
left: j,
|
|
1796
|
+
right: num(1),
|
|
1797
|
+
type: F64,
|
|
1798
|
+
loc,
|
|
1799
|
+
};
|
|
1800
|
+
const compare = hasComparator
|
|
1801
|
+
? {
|
|
1802
|
+
kind: "callValue",
|
|
1803
|
+
callee: ref("f.0", fnT),
|
|
1804
|
+
args: [at(j), ref("v.0", F64)].slice(0, arity),
|
|
1805
|
+
type: F64,
|
|
1806
|
+
loc,
|
|
1807
|
+
}
|
|
1808
|
+
: {
|
|
1809
|
+
kind: "bin",
|
|
1810
|
+
op: "-",
|
|
1811
|
+
left: at(j),
|
|
1812
|
+
right: ref("v.0", F64),
|
|
1813
|
+
type: F64,
|
|
1814
|
+
loc,
|
|
1815
|
+
};
|
|
1816
|
+
const shiftLoop = {
|
|
1817
|
+
kind: "while",
|
|
1818
|
+
cond: {
|
|
1819
|
+
kind: "bin",
|
|
1820
|
+
op: ">=",
|
|
1821
|
+
left: j,
|
|
1822
|
+
right: num(0),
|
|
1823
|
+
type: BOOL,
|
|
1824
|
+
loc,
|
|
1825
|
+
},
|
|
1826
|
+
body: [
|
|
1827
|
+
{
|
|
1828
|
+
kind: "if",
|
|
1829
|
+
cond: {
|
|
1830
|
+
kind: "bin",
|
|
1831
|
+
op: ">",
|
|
1832
|
+
left: compare,
|
|
1833
|
+
right: num(0),
|
|
1834
|
+
type: BOOL,
|
|
1835
|
+
loc,
|
|
1836
|
+
},
|
|
1837
|
+
then: [
|
|
1838
|
+
{
|
|
1839
|
+
kind: "bytesSet",
|
|
1840
|
+
arr: ref("a.0", bytesT),
|
|
1841
|
+
index: jPlus1,
|
|
1842
|
+
value: at(j),
|
|
1843
|
+
loc,
|
|
1844
|
+
},
|
|
1845
|
+
{
|
|
1846
|
+
kind: "assign",
|
|
1847
|
+
localId: "j.0",
|
|
1848
|
+
value: {
|
|
1849
|
+
kind: "bin",
|
|
1850
|
+
op: "-",
|
|
1851
|
+
left: j,
|
|
1852
|
+
right: num(1),
|
|
1853
|
+
type: F64,
|
|
1854
|
+
loc,
|
|
1855
|
+
},
|
|
1856
|
+
loc,
|
|
1857
|
+
},
|
|
1858
|
+
],
|
|
1859
|
+
else_: [{ kind: "break", loc }],
|
|
1860
|
+
loc,
|
|
1861
|
+
},
|
|
1862
|
+
],
|
|
1863
|
+
loc,
|
|
1864
|
+
};
|
|
1865
|
+
const params = [
|
|
1866
|
+
{ localId: "a.0", name: "a", type: bytesT },
|
|
1867
|
+
...(hasComparator
|
|
1868
|
+
? [{ localId: "f.0", name: "f", type: fnT }]
|
|
1869
|
+
: []),
|
|
1870
|
+
];
|
|
1871
|
+
const locals = [
|
|
1872
|
+
{ id: "a.0", name: "a", type: bytesT, mutable: true },
|
|
1873
|
+
...(hasComparator
|
|
1874
|
+
? [{ id: "f.0", name: "f", type: fnT, mutable: true }]
|
|
1875
|
+
: []),
|
|
1876
|
+
{ id: "n.0", name: "n", type: F64, mutable: false },
|
|
1877
|
+
{ id: "i.0", name: "i", type: F64, mutable: true },
|
|
1878
|
+
{ id: "v.0", name: "v", type: F64, mutable: false },
|
|
1879
|
+
{ id: "j.0", name: "j", type: F64, mutable: true },
|
|
1880
|
+
];
|
|
1881
|
+
const body = [
|
|
1882
|
+
{
|
|
1883
|
+
kind: "assign",
|
|
1884
|
+
localId: "a.0",
|
|
1885
|
+
value: {
|
|
1886
|
+
kind: "bytesIntrinsic",
|
|
1887
|
+
method: "slice",
|
|
1888
|
+
receiver: ref("a.0", bytesT),
|
|
1889
|
+
args: [],
|
|
1890
|
+
type: bytesT,
|
|
1891
|
+
loc,
|
|
1892
|
+
},
|
|
1893
|
+
loc,
|
|
1894
|
+
},
|
|
1895
|
+
{
|
|
1896
|
+
kind: "varDecl",
|
|
1897
|
+
localId: "n.0",
|
|
1898
|
+
init: {
|
|
1899
|
+
kind: "bytesIntrinsic",
|
|
1900
|
+
method: "length",
|
|
1901
|
+
receiver: ref("a.0", bytesT),
|
|
1902
|
+
args: [],
|
|
1903
|
+
type: F64,
|
|
1904
|
+
loc,
|
|
1905
|
+
},
|
|
1906
|
+
loc,
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
kind: "for",
|
|
1910
|
+
init: {
|
|
1911
|
+
kind: "varDecl",
|
|
1912
|
+
localId: "i.0",
|
|
1913
|
+
init: num(1),
|
|
1914
|
+
loc,
|
|
1915
|
+
},
|
|
1916
|
+
cond: {
|
|
1917
|
+
kind: "bin",
|
|
1918
|
+
op: "<",
|
|
1919
|
+
left: ref("i.0", F64),
|
|
1920
|
+
right: ref("n.0", F64),
|
|
1921
|
+
type: BOOL,
|
|
1922
|
+
loc,
|
|
1923
|
+
},
|
|
1924
|
+
update: {
|
|
1925
|
+
kind: "assign",
|
|
1926
|
+
localId: "i.0",
|
|
1927
|
+
value: {
|
|
1928
|
+
kind: "bin",
|
|
1929
|
+
op: "+",
|
|
1930
|
+
left: ref("i.0", F64),
|
|
1931
|
+
right: num(1),
|
|
1932
|
+
type: F64,
|
|
1933
|
+
loc,
|
|
1934
|
+
},
|
|
1935
|
+
loc,
|
|
1936
|
+
},
|
|
1937
|
+
body: [
|
|
1938
|
+
{
|
|
1939
|
+
kind: "varDecl",
|
|
1940
|
+
localId: "v.0",
|
|
1941
|
+
init: at(ref("i.0", F64)),
|
|
1942
|
+
loc,
|
|
1943
|
+
},
|
|
1944
|
+
{
|
|
1945
|
+
kind: "varDecl",
|
|
1946
|
+
localId: "j.0",
|
|
1947
|
+
init: {
|
|
1948
|
+
kind: "bin",
|
|
1949
|
+
op: "-",
|
|
1950
|
+
left: ref("i.0", F64),
|
|
1951
|
+
right: num(1),
|
|
1952
|
+
type: F64,
|
|
1953
|
+
loc,
|
|
1954
|
+
},
|
|
1955
|
+
loc,
|
|
1956
|
+
},
|
|
1957
|
+
shiftLoop,
|
|
1958
|
+
{
|
|
1959
|
+
kind: "bytesSet",
|
|
1960
|
+
arr: ref("a.0", bytesT),
|
|
1961
|
+
index: jPlus1,
|
|
1962
|
+
value: ref("v.0", F64),
|
|
1963
|
+
loc,
|
|
1964
|
+
},
|
|
1965
|
+
],
|
|
1966
|
+
loc,
|
|
1967
|
+
},
|
|
1968
|
+
{ kind: "return", value: ref("a.0", bytesT), loc },
|
|
1969
|
+
];
|
|
1970
|
+
return {
|
|
1971
|
+
name,
|
|
1972
|
+
params,
|
|
1973
|
+
returnType: bytesT,
|
|
1974
|
+
locals,
|
|
1975
|
+
body,
|
|
1976
|
+
loc,
|
|
1977
|
+
};
|
|
1978
|
+
}
|
|
1487
1979
|
/** `n = a.length` — the once-up-front length read every array HOF loop
|
|
1488
1980
|
* starts with (locals a.0/n.0 by convention). */
|
|
1489
1981
|
function readLenStmt(arrT, loc) {
|
|
@@ -3462,7 +3954,7 @@ export function lowerForOfSearchParams(L, stmt, iterable, proj) {
|
|
|
3462
3954
|
L.scopes.pop();
|
|
3463
3955
|
}
|
|
3464
3956
|
}
|
|
3465
|
-
/** for-of over an ARRAY
|
|
3957
|
+
/** for-of over an ARRAY/typed-array keys()/entries() projection consumed directly
|
|
3466
3958
|
* by the head (`for (const [index, line] of lines.entries())` — the
|
|
3467
3959
|
* dominant formatter idiom): the LIVE index walk — the length re-reads
|
|
3468
3960
|
* every pass, exactly the array iterator's contract (elements appended
|
|
@@ -3477,7 +3969,7 @@ export function lowerForOfSearchParams(L, stmt, iterable, proj) {
|
|
|
3477
3969
|
export function lowerForOfArrayIter(L, stmt, iterable, proj) {
|
|
3478
3970
|
const loc = locOf(stmt);
|
|
3479
3971
|
const arrT = iterable.type;
|
|
3480
|
-
const elemT = arrT.elem;
|
|
3972
|
+
const elemT = arrT.kind === "array" ? arrT.elem : F64;
|
|
3481
3973
|
const yieldsPair = proj === "entries";
|
|
3482
3974
|
if (!ts.isVariableDeclarationList(stmt.initializer)) {
|
|
3483
3975
|
L.unsupported("SC1090", stmt.initializer, "for-of over a pre-declared variable (declare the loop variable in the loop: for (const x of ...))");
|
|
@@ -3497,7 +3989,22 @@ export function lowerForOfArrayIter(L, stmt, iterable, proj) {
|
|
|
3497
3989
|
const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
|
|
3498
3990
|
const num = (value) => ({ kind: "numLit", value, type: F64, loc });
|
|
3499
3991
|
const keyRead = () => ref(i.id, F64);
|
|
3500
|
-
const valRead = () =>
|
|
3992
|
+
const valRead = () => arrT.kind === "array"
|
|
3993
|
+
? {
|
|
3994
|
+
kind: "arrayGet",
|
|
3995
|
+
arr: ref(arr.id, arrT),
|
|
3996
|
+
index: ref(i.id, F64),
|
|
3997
|
+
type: elemT,
|
|
3998
|
+
loc,
|
|
3999
|
+
}
|
|
4000
|
+
: {
|
|
4001
|
+
kind: "bytesIntrinsic",
|
|
4002
|
+
method: "get",
|
|
4003
|
+
receiver: ref(arr.id, arrT),
|
|
4004
|
+
args: [ref(i.id, F64)],
|
|
4005
|
+
type: F64,
|
|
4006
|
+
loc,
|
|
4007
|
+
};
|
|
3501
4008
|
const binds = [];
|
|
3502
4009
|
const isPlainIdent = (el) => ts.isBindingElement(el) && el.name !== undefined && ts.isIdentifier(el.name) && !el.initializer && !el.dotDotDotToken;
|
|
3503
4010
|
if (yieldsPair &&
|
|
@@ -3576,7 +4083,23 @@ export function lowerForOfArrayIter(L, stmt, iterable, proj) {
|
|
|
3576
4083
|
kind: "bin",
|
|
3577
4084
|
op: "<",
|
|
3578
4085
|
left: ref(i.id, F64),
|
|
3579
|
-
right:
|
|
4086
|
+
right: arrT.kind === "array"
|
|
4087
|
+
? {
|
|
4088
|
+
kind: "arrIntrinsic",
|
|
4089
|
+
method: "length",
|
|
4090
|
+
receiver: ref(arr.id, arrT),
|
|
4091
|
+
args: [],
|
|
4092
|
+
type: F64,
|
|
4093
|
+
loc,
|
|
4094
|
+
}
|
|
4095
|
+
: {
|
|
4096
|
+
kind: "bytesIntrinsic",
|
|
4097
|
+
method: "length",
|
|
4098
|
+
receiver: ref(arr.id, arrT),
|
|
4099
|
+
args: [],
|
|
4100
|
+
type: F64,
|
|
4101
|
+
loc,
|
|
4102
|
+
},
|
|
3580
4103
|
type: BOOL,
|
|
3581
4104
|
loc,
|
|
3582
4105
|
},
|
|
@@ -4406,6 +4929,60 @@ export function lowerBytesMethodCall(L, call, access) {
|
|
|
4406
4929
|
return null;
|
|
4407
4930
|
const loc = locOf(call);
|
|
4408
4931
|
const nArgs = call.arguments.length;
|
|
4932
|
+
if (receiverIr.elem === "u8" && name === "toSorted") {
|
|
4933
|
+
return lowerBytesToSortedCall(L, call, access, receiverIr);
|
|
4934
|
+
}
|
|
4935
|
+
if (receiverIr.elem === "u8" && name === "toReversed") {
|
|
4936
|
+
if (nArgs !== 0) {
|
|
4937
|
+
L.noLowering(`.toReversed with ${nArgs} arguments on Uint8Array`, call);
|
|
4938
|
+
}
|
|
4939
|
+
return {
|
|
4940
|
+
kind: "bytesIntrinsic",
|
|
4941
|
+
method: "toReversed",
|
|
4942
|
+
receiver: L.lowerExpr(access.expression),
|
|
4943
|
+
args: [],
|
|
4944
|
+
type: receiverIr,
|
|
4945
|
+
loc,
|
|
4946
|
+
};
|
|
4947
|
+
}
|
|
4948
|
+
if (receiverIr.elem === "u8" && name === "with") {
|
|
4949
|
+
if (nArgs !== 2 || call.arguments.some(ts.isSpreadElement)) {
|
|
4950
|
+
L.noLowering(`.with with ${nArgs} arguments on Uint8Array`, call);
|
|
4951
|
+
}
|
|
4952
|
+
return {
|
|
4953
|
+
kind: "bytesIntrinsic",
|
|
4954
|
+
method: "with",
|
|
4955
|
+
receiver: L.lowerExpr(access.expression),
|
|
4956
|
+
args: [
|
|
4957
|
+
L.lowerExprExpecting(call.arguments[0], F64),
|
|
4958
|
+
L.lowerExprExpecting(call.arguments[1], F64),
|
|
4959
|
+
],
|
|
4960
|
+
type: receiverIr,
|
|
4961
|
+
loc,
|
|
4962
|
+
};
|
|
4963
|
+
}
|
|
4964
|
+
if (receiverIr.elem === "u8" && name === "join") {
|
|
4965
|
+
if (nArgs > 1 || call.arguments.some(ts.isSpreadElement)) {
|
|
4966
|
+
L.noLowering(`.join with ${nArgs} arguments on Uint8Array`, call);
|
|
4967
|
+
}
|
|
4968
|
+
const separatorDefault = {
|
|
4969
|
+
kind: "strLit",
|
|
4970
|
+
value: ",",
|
|
4971
|
+
type: STRING,
|
|
4972
|
+
loc,
|
|
4973
|
+
};
|
|
4974
|
+
const separator = call.arguments[0]
|
|
4975
|
+
? lowerOptionalDefaultArg(L, call.arguments[0], STRING, separatorDefault)
|
|
4976
|
+
: separatorDefault;
|
|
4977
|
+
return {
|
|
4978
|
+
kind: "bytesIntrinsic",
|
|
4979
|
+
method: "join",
|
|
4980
|
+
receiver: L.lowerExpr(access.expression),
|
|
4981
|
+
args: [separator],
|
|
4982
|
+
type: STRING,
|
|
4983
|
+
loc,
|
|
4984
|
+
};
|
|
4985
|
+
}
|
|
4409
4986
|
if (name === "slice" || name === "subarray") {
|
|
4410
4987
|
if (nArgs > 2) {
|
|
4411
4988
|
L.noLowering(`.${name} with ${nArgs} arguments on typed arrays`, call);
|