@scriptc/compiler 0.1.4 → 0.1.5
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 +75 -11
- package/dist/backend/c/c-emitter.d.ts +5 -1
- package/dist/backend/c/c-emitter.js +22 -9
- package/dist/backend/c/c-emitter.js.map +1 -1
- package/dist/backend/c/exprs.d.ts +2 -2
- package/dist/backend/c/exprs.js +264 -21
- package/dist/backend/c/exprs.js.map +1 -1
- package/dist/backend/c/stmts.js +5 -3
- package/dist/backend/c/stmts.js.map +1 -1
- package/dist/backend/c/types.d.ts +2 -3
- package/dist/backend/c/types.js +8 -1
- package/dist/backend/c/types.js.map +1 -1
- package/dist/backend/c/walkers.js +1 -1
- package/dist/backend/c/walkers.js.map +1 -1
- package/dist/backend/link-plan.d.ts +1 -0
- package/dist/backend/link-plan.js +2 -1
- package/dist/backend/link-plan.js.map +1 -1
- package/dist/backend/llvm/dyn.js +1 -1
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +25 -9
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.d.ts +1 -2
- package/dist/backend/llvm/expr-bytes.js +22 -17
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-containers.d.ts +1 -0
- package/dist/backend/llvm/expr-containers.js +32 -4
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-context.d.ts +6 -2
- package/dist/backend/llvm/expr-primitives.js +22 -7
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +12 -0
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +53 -10
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +64 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/native-toolchain.d.ts +2 -0
- package/dist/backend/native-toolchain.js +2 -1
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/backend/targets.d.ts +3 -0
- package/dist/backend/targets.js +13 -0
- package/dist/backend/targets.js.map +1 -1
- package/dist/coverage/surface-manifest.js +6 -4
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +2 -0
- package/dist/executable/executable-cache.js +3 -1
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +3 -3
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.d.ts +1 -1
- package/dist/frontend/lowering/containers/bytes.js +6 -5
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.d.ts +7 -6
- package/dist/frontend/lowering/containers/string-and-regexp.js +237 -28
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +8 -0
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +4 -5
- package/dist/frontend/lowering/lower-builtins.js +18 -10
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +3 -2
- package/dist/frontend/lowering/lower-calls.js +265 -88
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +2 -2
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +7 -9
- package/dist/frontend/lowering/lower-containers.js +143 -51
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +12 -0
- package/dist/frontend/lowering/lower-exprs.js +128 -10
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-island.js +17 -6
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +2 -4
- package/dist/frontend/lowering/lower-server.js +288 -32
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +4 -4
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.js +37 -2
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/optional-arguments.d.ts +9 -1
- package/dist/frontend/lowering/optional-arguments.js +67 -1
- package/dist/frontend/lowering/optional-arguments.js.map +1 -1
- package/dist/frontend/lowering/pairs-snapshot.d.ts +3 -1
- package/dist/frontend/lowering/pairs-snapshot.js +12 -4
- package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +8 -14
- package/dist/frontend/lowering/surfaces.js +37 -27
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm-static-prune.d.ts +6 -0
- package/dist/frontend/npm-static-prune.js +203 -0
- package/dist/frontend/npm-static-prune.js.map +1 -0
- package/dist/frontend/npm-static-prune.test.d.ts +1 -0
- package/dist/frontend/npm-static-prune.test.js +48 -0
- package/dist/frontend/npm-static-prune.test.js.map +1 -0
- package/dist/frontend/npm.js +7 -6
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/program.js +15 -4
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/provenance.js +8 -3
- package/dist/frontend/provenance.js.map +1 -1
- package/dist/frontend/type-mapper.js +16 -5
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +13 -41
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +5 -3
- package/dist/ir/analysis.js +25 -11
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/analysis.test.js +50 -2
- package/dist/ir/analysis.test.js.map +1 -1
- package/dist/ir/constant-tables.d.ts +17 -0
- package/dist/ir/constant-tables.js +99 -0
- package/dist/ir/constant-tables.js.map +1 -0
- package/dist/ir/constant-tables.test.d.ts +1 -0
- package/dist/ir/constant-tables.test.js +78 -0
- package/dist/ir/constant-tables.test.js.map +1 -0
- package/dist/ir/integer-ranges.d.ts +13 -0
- package/dist/ir/integer-ranges.js +122 -0
- package/dist/ir/integer-ranges.js.map +1 -0
- package/dist/ir/integer-ranges.test.d.ts +1 -0
- package/dist/ir/integer-ranges.test.js +63 -0
- package/dist/ir/integer-ranges.test.js.map +1 -0
- package/dist/ir/ir.d.ts +42 -34
- package/dist/ir/ir.js +7 -1
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +6 -0
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/scalar-records.d.ts +8 -0
- package/dist/ir/scalar-records.js +216 -0
- package/dist/ir/scalar-records.js.map +1 -0
- package/dist/ir/scalar-records.test.d.ts +1 -0
- package/dist/ir/scalar-records.test.js +142 -0
- package/dist/ir/scalar-records.test.js.map +1 -0
- package/dist/ir/validate.js +92 -8
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.d.ts +1 -0
- package/dist/ir/validate.test.js +31 -0
- package/dist/ir/validate.test.js.map +1 -0
- package/dist/library/cache-primitives.d.ts +1 -1
- package/dist/library/cache-primitives.js +3 -3
- package/dist/library/cache-primitives.js.map +1 -1
- package/dist/library/fence-eval.js +11 -4
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/library-cache.js +0 -1
- package/dist/library/library-cache.js.map +1 -1
- package/dist/library/library-cache.test.js +3 -3
- package/dist/library/library-cache.test.js.map +1 -1
- package/package.json +17 -17
- package/surface-manifest.json +55 -42
|
@@ -9,8 +9,9 @@ import { type ClassInfo } from "./lower-classes.js";
|
|
|
9
9
|
* `omittable` params (declared `x?: T` or `x: T = e`) may be omitted by a
|
|
10
10
|
* trailing-suffix call, and the frontend appends the interned undefined arm;
|
|
11
11
|
* `rest` (always last) receives the surplus arguments packed into one array
|
|
12
|
-
* literal at each call site.
|
|
13
|
-
|
|
12
|
+
* literal at each call site. `arguments` is a hidden slot containing every
|
|
13
|
+
* actual argument, including those bound to named parameters. */
|
|
14
|
+
export type ParamMode = "required" | "omittable" | "rest" | "dynRest" | "islandRest" | "arguments";
|
|
14
15
|
/** One parameter of a signature, as call sites and callee prologues see it.
|
|
15
16
|
* `type` is the ABI type — what the emitted C parameter carries: the
|
|
16
17
|
* checker's `T | undefined` union for `x?: T`, a synthesized `T | undefined`
|
|
@@ -6,18 +6,18 @@ import { InternalCompilerError } from "../../errors.js";
|
|
|
6
6
|
import * as ts from "../ts7/adapter.js";
|
|
7
7
|
import { lowerGenMethodCall } from "./lower-generators.js";
|
|
8
8
|
import { BIGINT_T, BOOL, CAUGHT, DYN, F64, JSVAL, STRING, SYMBOL_T, UNDEFINED_T, VOID, arrayOf, canBoxFuncIntoDyn, canConvertToDyn, canDynCheckTo, canMarshalTypedFuncIntoIsland, ffiClassType, ffiSourceParamTypes, funcOf, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isUnitType, shapeHasAccessorSlots, typeEquals } from "../../ir/ir.js";
|
|
9
|
-
import { isJsSourceFile, locOf } from "../program.js";
|
|
9
|
+
import { isJsSourceFile, isNodeEsmFile, locOf } from "../program.js";
|
|
10
10
|
import { genResultRecord, isGenericCallableMemberType, typeKey } from "../type-mapper.js";
|
|
11
11
|
import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, newFnCtx, nodeThrowExpr, staticImportNamespaceType } from "./lowerer.js";
|
|
12
12
|
import { enforceLibBoundary } from "./lib-boundary.js";
|
|
13
|
-
import { NARROW_FIRST, builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.js";
|
|
13
|
+
import { NARROW_FIRST, STR_METHODS, builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.js";
|
|
14
14
|
import { ffiBindingDiag, ffiSignatureDiag, libCallbackDiag, requiresDynamicDiag } from "../../diagnostics/diagnostic.js";
|
|
15
15
|
import { mixinFnShapeOf } from "./lower-mixins.js";
|
|
16
16
|
import { dynStringReceiver, lowerArrayFromCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
|
|
17
17
|
import { bufEncoding } from "./containers/bytes.js";
|
|
18
|
-
import { lowerRegexMethodCall, lowerStringMethodCall } from "./containers/string-and-regexp.js";
|
|
18
|
+
import { lowerRegexMethodCall, lowerStringMethodCall, lowerStringPaddingCall } from "./containers/string-and-regexp.js";
|
|
19
19
|
import { lowerChildStreamMethodCall, lowerChildWriterMethodCall, lowerCreateRequireCall, lowerCryptoHashMethodCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerNodeModuleCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerRequireResolveCall, lowerWatcherMethodCall } from "./lower-builtins.js";
|
|
20
|
-
import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, templateRawTextOf } from "./lower-exprs.js";
|
|
20
|
+
import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, stringWrapperToString, templateRawTextOf } from "./lower-exprs.js";
|
|
21
21
|
import { isSafeToDiscard } from "./expressions/evaluation-safety.js";
|
|
22
22
|
import { tryLowerExpression } from "./expressions/try-lower-expression.js";
|
|
23
23
|
import { httpClientFnBindingOf, isStreamUndefCallExpr, lowerCompatReqStreamOptionalCall, lowerHttpClientFnCall } from "./lower-server.js";
|
|
@@ -32,6 +32,7 @@ import { npmStaticPackageOfPath } from "../npm-static.js";
|
|
|
32
32
|
import { countedFor, varRef } from "../../ir/build.js";
|
|
33
33
|
import { rejectStaticThis } from "./static-this.js";
|
|
34
34
|
import { fenceNodeModuleMutationCall, lowerRequireCacheKeys } from "./lower-node-module.js";
|
|
35
|
+
import { defaultAfterUndefined, lowerOptionalArgument, lowerStaticallyUndefinedArgument, positionNumber } from "./optional-arguments.js";
|
|
35
36
|
/** The one func-type projection of completed parameter shapes. Typed rest
|
|
36
37
|
* parameters keep their packed array as the trailing native ABI slot and
|
|
37
38
|
* mark the value variadic so indirect call sites run completeArgs before
|
|
@@ -40,12 +41,14 @@ import { fenceNodeModuleMutationCall, lowerRequireCacheKeys } from "./lower-node
|
|
|
40
41
|
export function funcTypeFromParamShapes(shapes, ret) {
|
|
41
42
|
const typedRest = shapes.some((shape) => shape.mode === "rest");
|
|
42
43
|
const dynRest = shapes.some((shape) => shape.mode === "dynRest");
|
|
44
|
+
const argumentsAll = shapes.some((shape) => shape.mode === "arguments");
|
|
43
45
|
const islandRest = shapes.some((shape) => shape.mode === "islandRest");
|
|
44
46
|
return {
|
|
45
47
|
kind: "func",
|
|
46
|
-
params: shapes.filter((shape) => shape.mode !== "dynRest").map((shape) => shape.type),
|
|
48
|
+
params: shapes.filter((shape) => shape.mode !== "dynRest" && shape.mode !== "arguments").map((shape) => shape.type),
|
|
47
49
|
ret,
|
|
48
|
-
...(typedRest || dynRest || islandRest ? { rest: true } : {}),
|
|
50
|
+
...(typedRest || dynRest || islandRest || argumentsAll ? { rest: true } : {}),
|
|
51
|
+
...(argumentsAll ? { argumentsAll: true } : {}),
|
|
49
52
|
...(typedRest
|
|
50
53
|
? { restAbi: "typed" }
|
|
51
54
|
: islandRest
|
|
@@ -382,8 +385,42 @@ leading) {
|
|
|
382
385
|
});
|
|
383
386
|
});
|
|
384
387
|
}
|
|
385
|
-
const restAt = shapes.findIndex((s) => s.mode === "rest" || s.mode === "dynRest" || s.mode === "islandRest");
|
|
388
|
+
const restAt = shapes.findIndex((s) => s.mode === "rest" || s.mode === "dynRest" || s.mode === "islandRest" || s.mode === "arguments");
|
|
386
389
|
const positional = restAt >= 0 ? shapes.slice(0, restAt) : [...shapes];
|
|
390
|
+
if (restAt >= 0 && shapes[restAt].mode === "arguments") {
|
|
391
|
+
// JS `arguments` contains every supplied value, including fixed
|
|
392
|
+
// parameters. Store each call expression once, in source order, so
|
|
393
|
+
// both the native parameter slots and the full array read it.
|
|
394
|
+
const stmts = [];
|
|
395
|
+
const passed = sources.map((source, i) => {
|
|
396
|
+
if (!isIr(source) && ts.isSpreadElement(source)) {
|
|
397
|
+
lowerer.unsupported("SC1090", source, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
|
|
398
|
+
}
|
|
399
|
+
const slotType = i < restAt ? positional[i].type : DYN;
|
|
400
|
+
const value = isIr(source)
|
|
401
|
+
? lowerer.coerceInto(blame, source.ir, slotType)
|
|
402
|
+
: lowerer.lowerExprExpecting(source, slotType);
|
|
403
|
+
const saved = lowerer.declareHiddenLocal("%callArg", slotType);
|
|
404
|
+
stmts.push({ kind: "varDecl", localId: saved.id, init: value, loc: value.loc });
|
|
405
|
+
return { kind: "varRef", localId: saved.id, type: slotType, loc: value.loc };
|
|
406
|
+
});
|
|
407
|
+
const fixed = positional.map((shape, i) => {
|
|
408
|
+
if (i < passed.length)
|
|
409
|
+
return passed[i];
|
|
410
|
+
if (shape.mode === "omittable")
|
|
411
|
+
return shape.callDefault ?? lowerer.undefinedArgFor(shape.type, loc, blame);
|
|
412
|
+
if (shape.type.kind === "dyn")
|
|
413
|
+
return { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc };
|
|
414
|
+
lowerer.unsupported("SC1090", blame, "this call form");
|
|
415
|
+
});
|
|
416
|
+
const elems = passed.map((value) => lowerer.coerceInto(blame, value, DYN));
|
|
417
|
+
const full = { kind: "dynArrLit", elems, type: DYN, loc };
|
|
418
|
+
const out = [...fixed, full];
|
|
419
|
+
if (stmts.length > 0) {
|
|
420
|
+
out[0] = { kind: "seqExpr", stmts, result: out[0], type: out[0].type, loc };
|
|
421
|
+
}
|
|
422
|
+
return out;
|
|
423
|
+
}
|
|
387
424
|
const out = positional.map((shape, i) => {
|
|
388
425
|
const src = sources[i];
|
|
389
426
|
if (isIr(src))
|
|
@@ -617,6 +654,7 @@ export function requireExactArityValue(lowerer, blame, contextual, shapes, funcT
|
|
|
617
654
|
// tier's undefined (omittedArgFor).
|
|
618
655
|
if (shapes.every((s) => s.mode === "required" ||
|
|
619
656
|
s.mode === "dynRest" ||
|
|
657
|
+
s.mode === "arguments" ||
|
|
620
658
|
s.mode === "islandRest" ||
|
|
621
659
|
(s.mode === "omittable" && (s.type.kind === "dyn" || s.type.kind === "jsval")))) {
|
|
622
660
|
return;
|
|
@@ -915,18 +953,16 @@ export function collectSignatureInner(lowerer, decl) {
|
|
|
915
953
|
}
|
|
916
954
|
}
|
|
917
955
|
const params = lowerer.paramShapes(decl.parameters);
|
|
918
|
-
//
|
|
919
|
-
//
|
|
920
|
-
//
|
|
921
|
-
|
|
922
|
-
// indirect ones; lowerFunction declares the `arguments` local).
|
|
923
|
-
if (!params.some((sh) => sh.mode === "dynRest") &&
|
|
956
|
+
// A declared function reading `arguments` receives a hidden dyn array.
|
|
957
|
+
// The zero-parameter form uses the existing rest pack; named parameters
|
|
958
|
+
// use the full argument pack for both direct and boxed calls.
|
|
959
|
+
if (!params.some((sh) => sh.mode === "rest" || sh.mode === "dynRest" || sh.mode === "islandRest") &&
|
|
924
960
|
isJsSourceFile(decl.getSourceFile()) &&
|
|
925
961
|
bodyReadsArguments(decl)) {
|
|
926
|
-
if (decl.parameters.length > 0) {
|
|
927
|
-
lowerer.unsupported("SC1090", decl, "'arguments'
|
|
962
|
+
if (decl.parameters.length > 0 && !isNodeEsmFile(decl.getSourceFile())) {
|
|
963
|
+
lowerer.unsupported("SC1090", decl, "parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases)");
|
|
928
964
|
}
|
|
929
|
-
params.push({ type: DYN, mode: "dynRest" });
|
|
965
|
+
params.push({ type: DYN, mode: decl.parameters.length > 0 ? "arguments" : "dynRest" });
|
|
930
966
|
}
|
|
931
967
|
const nameBlame = decl.name ?? decl;
|
|
932
968
|
const returnType = lowerer.declaredReturnType(decl, nameBlame);
|
|
@@ -3339,13 +3375,12 @@ export function lowerCall(lowerer, expr) {
|
|
|
3339
3375
|
// String(x) is exactly the template-literal ToString, Boolean(x) is
|
|
3340
3376
|
// exactly the condition ToBoolean (union arms included), Number(x) is
|
|
3341
3377
|
// ToNumber where it lowers exactly: numbers pass through, booleans
|
|
3342
|
-
// become 1/0, and
|
|
3343
|
-
// StringToNumber (num.fromString — the full
|
|
3344
|
-
// grammar
|
|
3345
|
-
// narrow first) keep the fence.
|
|
3378
|
+
// become 1/0, null becomes 0, and undefined becomes NaN. Strings use
|
|
3379
|
+
// the runtime's StringToNumber parser (num.fromString — the full
|
|
3380
|
+
// StringNumericLiteral grammar in scr_string.c).
|
|
3346
3381
|
// Provenance-checked like setTimeout; zero-arg forms are the JS
|
|
3347
|
-
// constants ("", false, 0).
|
|
3348
|
-
//
|
|
3382
|
+
// constants ("", false, 0). Wrapper objects stay fenced except where
|
|
3383
|
+
// the receiver is immediately converted by a direct String method call.
|
|
3349
3384
|
if (ts.isIdentifier(expr.expression) &&
|
|
3350
3385
|
expr.expression.text === "BigInt" &&
|
|
3351
3386
|
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
|
|
@@ -3406,33 +3441,11 @@ export function lowerCall(lowerer, expr) {
|
|
|
3406
3441
|
// bool) that a value lowering of the `&&` would fence on.
|
|
3407
3442
|
if (name === "Boolean")
|
|
3408
3443
|
return lowerer.lowerCondition(argNode);
|
|
3444
|
+
if (name === "Number")
|
|
3445
|
+
return lowerNumberConstructorValue(lowerer, argNode, loc);
|
|
3409
3446
|
const arg = lowerer.lowerExpr(argNode);
|
|
3410
3447
|
if (name === "String")
|
|
3411
3448
|
return lowerer.ensureString(arg, argNode);
|
|
3412
|
-
if (name === "Number" && arg.type.kind === "bigint") {
|
|
3413
|
-
return { kind: "libCall", fn: "bigint.toF64", args: [arg], type: F64, loc };
|
|
3414
|
-
}
|
|
3415
|
-
if (arg.type.kind === "f64")
|
|
3416
|
-
return arg;
|
|
3417
|
-
if (arg.type.kind === "bool") {
|
|
3418
|
-
return {
|
|
3419
|
-
kind: "ternary",
|
|
3420
|
-
cond: arg,
|
|
3421
|
-
then: { kind: "numLit", value: 1, type: F64, loc },
|
|
3422
|
-
else_: { kind: "numLit", value: 0, type: F64, loc },
|
|
3423
|
-
type: F64,
|
|
3424
|
-
loc,
|
|
3425
|
-
};
|
|
3426
|
-
}
|
|
3427
|
-
if (arg.type.kind === "string") {
|
|
3428
|
-
return { kind: "libCall", fn: "num.fromString", args: [arg], type: F64, loc };
|
|
3429
|
-
}
|
|
3430
|
-
const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc);
|
|
3431
|
-
if (optionalNumber)
|
|
3432
|
-
return optionalNumber;
|
|
3433
|
-
lowerer.noLowering(`Number of ${lowerer.fmt(arg.type)} values`, argNode, arg.type.kind === "union"
|
|
3434
|
-
? "numbers, booleans, and strings lower (the full ToNumber string grammar included) — narrow the union first"
|
|
3435
|
-
: undefined);
|
|
3436
3449
|
}
|
|
3437
3450
|
// __island_eval: the internal island testing hook (eval in the embedded
|
|
3438
3451
|
// engine, String(result) back). Provenance-checked like setTimeout.
|
|
@@ -4175,11 +4188,12 @@ export function lowerCall(lowerer, expr) {
|
|
|
4175
4188
|
// TestContext surface (t.test/t.skip/t.diagnostic), t.assert.*.
|
|
4176
4189
|
lowerer.lowerTestMethodCall(expr, expr.expression) ??
|
|
4177
4190
|
lowerer.lowerTimeoutMethodCall(expr, expr.expression) ??
|
|
4191
|
+
lowerStringPrototypeCall(lowerer, expr, expr.expression) ??
|
|
4178
4192
|
lowerStringMethodCallWithOptionalArgs(lowerer, expr, expr.expression) ??
|
|
4179
4193
|
// Typed-array/Buffer receivers and the Buffer statics — before the
|
|
4180
4194
|
// island path (bytes never cross the boundary).
|
|
4181
4195
|
lowerer.lowerBytesMethodCall(expr, expr.expression) ??
|
|
4182
|
-
|
|
4196
|
+
lowerBufferStaticCallWithNarrowedArg(lowerer, expr, expr.expression) ??
|
|
4183
4197
|
// URL.revokeObjectURL's zero-argument contract (the one-argument
|
|
4184
4198
|
// form keeps the fence — createObjectURL does too).
|
|
4185
4199
|
lowerUrlStaticCall(lowerer, expr, expr.expression) ??
|
|
@@ -4454,22 +4468,29 @@ function lowerRegexMethodCallWithOptionalArg(lowerer, call, access) {
|
|
|
4454
4468
|
function optionalCallValue(lowerer, node) {
|
|
4455
4469
|
return lowerer.runtimeOptionalIdentifierValue(node)?.value ?? lowerAbsenceProbe(lowerer, node);
|
|
4456
4470
|
}
|
|
4457
|
-
function
|
|
4471
|
+
function lowerBufferStaticCallWithNarrowedArg(lowerer, call, access) {
|
|
4458
4472
|
const lowered = lowerer.lowerBufferStaticCall(call, access);
|
|
4459
4473
|
if (lowered?.kind !== "bytesNew" || !lowered.source || lowered.source.type.kind !== "union")
|
|
4460
4474
|
return lowered;
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4475
|
+
// A callback can store a wider union than the checker sees at this use
|
|
4476
|
+
// (including an added undefined arm). Extract the exact arm proven by
|
|
4477
|
+
// control-flow narrowing, not merely the union with undefined removed.
|
|
4478
|
+
const narrowed = lowerer.mapTypeOf(lowerer.typeOf(call.arguments[0]));
|
|
4479
|
+
if (!narrowed ||
|
|
4480
|
+
!(narrowed.kind === "f64" ||
|
|
4481
|
+
(narrowed.kind === "array" && narrowed.elem.kind === "f64") ||
|
|
4482
|
+
(narrowed.kind === "bytes" && narrowed.elem === "u8")) ||
|
|
4483
|
+
lowerer.armTag(lowered.source.type.unionId, narrowed) < 0) {
|
|
4484
|
+
lowerer.unsupported("SC1090", call.arguments[0], "a Buffer constructor argument whose narrowed type is not a stored source arm");
|
|
4485
|
+
}
|
|
4486
|
+
const helper = lowerer.narrowedArmHelper(lowered.source.type.unionId, narrowed, lowered.source.loc);
|
|
4487
|
+
if (!helper) {
|
|
4488
|
+
lowerer.unsupported("SC1090", call.arguments[0], "a Buffer constructor argument whose narrowed type is not a stored source arm");
|
|
4489
|
+
}
|
|
4490
|
+
return {
|
|
4491
|
+
...lowered,
|
|
4492
|
+
source: { kind: "call", callee: helper, args: [lowered.source], type: narrowed, loc: lowered.source.loc },
|
|
4493
|
+
};
|
|
4473
4494
|
}
|
|
4474
4495
|
function lowerOptionalNumberDefault(lowerer, value, dflt, loc) {
|
|
4475
4496
|
const widened = lowerer.runtimeOptionalWidening(value.type, F64);
|
|
@@ -4509,14 +4530,14 @@ function lowerOptionalNumberDefault(lowerer, value, dflt, loc) {
|
|
|
4509
4530
|
}
|
|
4510
4531
|
return { kind: "call", callee: helper, args: [value], type: F64, loc };
|
|
4511
4532
|
}
|
|
4512
|
-
function lowerStringMethodCallWithOptionalArgs(lowerer, call, access) {
|
|
4513
|
-
const lowered =
|
|
4533
|
+
function lowerStringMethodCallWithOptionalArgs(lowerer, call, access, receiver, argumentNodes = call.arguments) {
|
|
4534
|
+
const lowered = lowerStringMethodCall(lowerer, call, access, receiver, argumentNodes);
|
|
4514
4535
|
if (lowered?.kind !== "strIntrinsic")
|
|
4515
4536
|
return lowered;
|
|
4516
4537
|
const args = [...lowered.args];
|
|
4517
4538
|
let changed = false;
|
|
4518
4539
|
const zeroDefaultArgs = lowered.method === "charCodeAt" || lowered.method === "charAt" ||
|
|
4519
|
-
lowered.method === "repeat"
|
|
4540
|
+
lowered.method === "repeat"
|
|
4520
4541
|
? [0]
|
|
4521
4542
|
: lowered.method === "slice" || lowered.method === "substring"
|
|
4522
4543
|
? [0]
|
|
@@ -4537,11 +4558,170 @@ function lowerStringMethodCallWithOptionalArgs(lowerer, call, access) {
|
|
|
4537
4558
|
lowered.method === "startsWith" || lowered.method === "endsWith") &&
|
|
4538
4559
|
args[0]?.type.kind === "union" &&
|
|
4539
4560
|
lowerer.runtimeOptionalWidening(args[0].type, STRING) !== null) {
|
|
4540
|
-
args[0] = lowerer.ensureString(args[0],
|
|
4561
|
+
args[0] = lowerer.ensureString(args[0], argumentNodes[0]);
|
|
4541
4562
|
changed = true;
|
|
4542
4563
|
}
|
|
4543
4564
|
return changed ? { ...lowered, args } : lowered;
|
|
4544
4565
|
}
|
|
4566
|
+
function lowerNumberConstructorValue(lowerer, argNode, loc) {
|
|
4567
|
+
const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, argNode);
|
|
4568
|
+
if (undefinedArg) {
|
|
4569
|
+
return defaultAfterUndefined(undefinedArg, {
|
|
4570
|
+
kind: "bin", op: "/", left: { kind: "numLit", value: 0, type: F64, loc },
|
|
4571
|
+
right: { kind: "numLit", value: 0, type: F64, loc }, type: F64, loc,
|
|
4572
|
+
});
|
|
4573
|
+
}
|
|
4574
|
+
const arg = lowerer.lowerExpr(argNode);
|
|
4575
|
+
if (arg.type.kind === "nullT")
|
|
4576
|
+
return defaultAfterUndefined(arg, { kind: "numLit", value: 0, type: F64, loc });
|
|
4577
|
+
if (arg.type.kind === "bigint")
|
|
4578
|
+
return { kind: "libCall", fn: "bigint.toF64", args: [arg], type: F64, loc };
|
|
4579
|
+
if (arg.type.kind === "f64")
|
|
4580
|
+
return arg;
|
|
4581
|
+
if (arg.type.kind === "bool") {
|
|
4582
|
+
return {
|
|
4583
|
+
kind: "ternary",
|
|
4584
|
+
cond: arg,
|
|
4585
|
+
then: { kind: "numLit", value: 1, type: F64, loc },
|
|
4586
|
+
else_: { kind: "numLit", value: 0, type: F64, loc },
|
|
4587
|
+
type: F64,
|
|
4588
|
+
loc,
|
|
4589
|
+
};
|
|
4590
|
+
}
|
|
4591
|
+
if (arg.type.kind === "string")
|
|
4592
|
+
return { kind: "libCall", fn: "num.fromString", args: [arg], type: F64, loc };
|
|
4593
|
+
const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc);
|
|
4594
|
+
if (optionalNumber)
|
|
4595
|
+
return optionalNumber;
|
|
4596
|
+
const scalarUnionNumber = lowerScalarUnionNumber(lowerer, arg, argNode, loc);
|
|
4597
|
+
if (scalarUnionNumber)
|
|
4598
|
+
return scalarUnionNumber;
|
|
4599
|
+
return lowerer.noLowering(`Number of ${lowerer.fmt(arg.type)} values`, argNode, arg.type.kind === "union"
|
|
4600
|
+
? "unions of numbers, booleans, strings, null, and undefined lower — narrow other arms first"
|
|
4601
|
+
: undefined);
|
|
4602
|
+
}
|
|
4603
|
+
function immediatePrimitiveWrapperToString(lowerer, node) {
|
|
4604
|
+
const stringValue = stringWrapperToString(lowerer, node);
|
|
4605
|
+
if (stringValue)
|
|
4606
|
+
return stringValue;
|
|
4607
|
+
let wrapped = node;
|
|
4608
|
+
while (ts.isParenthesizedExpression(wrapped))
|
|
4609
|
+
wrapped = wrapped.expression;
|
|
4610
|
+
if (!ts.isNewExpression(wrapped) || !ts.isIdentifier(wrapped.expression))
|
|
4611
|
+
return null;
|
|
4612
|
+
const name = wrapped.expression.text;
|
|
4613
|
+
if ((name !== "Boolean" && name !== "Number") ||
|
|
4614
|
+
!lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(wrapped.expression) ?? undefined))
|
|
4615
|
+
return null;
|
|
4616
|
+
const args = wrapped.arguments ?? [];
|
|
4617
|
+
if (args.length > 1 || args.some(ts.isSpreadElement))
|
|
4618
|
+
return null;
|
|
4619
|
+
const loc = locOf(wrapped);
|
|
4620
|
+
const primitive = name === "Boolean"
|
|
4621
|
+
? args.length ? lowerer.lowerCondition(args[0]) : { kind: "boolLit", value: false, type: BOOL, loc }
|
|
4622
|
+
: args.length ? lowerNumberConstructorValue(lowerer, args[0], loc) : { kind: "numLit", value: 0, type: F64, loc };
|
|
4623
|
+
return lowerer.ensureString(primitive, wrapped);
|
|
4624
|
+
}
|
|
4625
|
+
function plainObjectCoercionReceiver(lowerer, node) {
|
|
4626
|
+
const plainLiteral = (literal) => literal.properties.every((prop) => ts.isPropertyAssignment(prop) &&
|
|
4627
|
+
(ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name) || ts.isNumericLiteral(prop.name)) &&
|
|
4628
|
+
prop.name.text !== "__proto__");
|
|
4629
|
+
let value = node;
|
|
4630
|
+
while (ts.isParenthesizedExpression(value))
|
|
4631
|
+
value = value.expression;
|
|
4632
|
+
if (ts.isObjectLiteralExpression(value))
|
|
4633
|
+
return plainLiteral(value);
|
|
4634
|
+
if (!ts.isIdentifier(value))
|
|
4635
|
+
return false;
|
|
4636
|
+
const symbol = lowerer.resolveValueSymbol(value);
|
|
4637
|
+
const decl = symbol ? lowerer.checker.valueDeclarationOf(symbol) : undefined;
|
|
4638
|
+
if (!symbol || !decl || !ts.isVariableDeclaration(decl) || !decl.initializer ||
|
|
4639
|
+
!ts.isObjectLiteralExpression(decl.initializer) || !plainLiteral(decl.initializer))
|
|
4640
|
+
return false;
|
|
4641
|
+
return bindingNeverReassigned(lowerer, symbol, decl);
|
|
4642
|
+
}
|
|
4643
|
+
function lowerStringPrototypeCall(lowerer, call, access) {
|
|
4644
|
+
if (access.name.text !== "call" || !ts.isPropertyAccessExpression(access.expression))
|
|
4645
|
+
return null;
|
|
4646
|
+
const methodAccess = access.expression;
|
|
4647
|
+
const prototypeAccess = methodAccess.expression;
|
|
4648
|
+
if (!ts.isPropertyAccessExpression(prototypeAccess) || prototypeAccess.name.text !== "prototype" ||
|
|
4649
|
+
!ts.isIdentifier(prototypeAccess.expression) || prototypeAccess.expression.text !== "String" ||
|
|
4650
|
+
!Object.hasOwn(STR_METHODS, methodAccess.name.text) || !lowerer.isStdlibMember(methodAccess))
|
|
4651
|
+
return null;
|
|
4652
|
+
if (call.arguments.some(ts.isSpreadElement))
|
|
4653
|
+
return null;
|
|
4654
|
+
const entry = STR_METHODS[methodAccess.name.text];
|
|
4655
|
+
const method = methodAccess.name.text === "trimStart" ? "trimLeft" :
|
|
4656
|
+
methodAccess.name.text === "trimEnd" ? "trimRight" : methodAccess.name.text;
|
|
4657
|
+
const loc = locOf(call);
|
|
4658
|
+
const nullishError = nodeThrowExpr(1, "", `String.prototype.${method} called on null or undefined`, entry.result, loc);
|
|
4659
|
+
const receiverNode = call.arguments[0];
|
|
4660
|
+
if (!receiverNode)
|
|
4661
|
+
return nullishError;
|
|
4662
|
+
// Receiver coercion runs after .call has evaluated its arguments; keep
|
|
4663
|
+
// contextual wrapper lowering on forms without later method arguments.
|
|
4664
|
+
const immediateWrapper = entry.maxArgs === 0 && call.arguments.length === 1
|
|
4665
|
+
? immediatePrimitiveWrapperToString(lowerer, receiverNode) : null;
|
|
4666
|
+
const receiverValue = immediateWrapper ?? lowerer.lowerExpr(receiverNode);
|
|
4667
|
+
const receiverType = receiverValue.type;
|
|
4668
|
+
const nullish = isUnitType(receiverType) || receiverType.kind === "void" ||
|
|
4669
|
+
(receiverType.kind === "union" && (lowerer.unions.get(receiverType.unionId)?.arms.every((arm) => isUnitType(arm) || arm.kind === "void") ?? false));
|
|
4670
|
+
if (nullish) {
|
|
4671
|
+
const values = [receiverValue, ...call.arguments.slice(1).map((arg) => lowerer.lowerExpr(arg))];
|
|
4672
|
+
return {
|
|
4673
|
+
kind: "seqExpr",
|
|
4674
|
+
stmts: values.filter((value) => !isSafeToDiscard(value)).map((value) => ({ kind: "exprStmt", expr: value, loc: value.loc })),
|
|
4675
|
+
result: nullishError,
|
|
4676
|
+
type: entry.result,
|
|
4677
|
+
loc,
|
|
4678
|
+
};
|
|
4679
|
+
}
|
|
4680
|
+
const padding = entry.method === "padStart" || entry.method === "padEnd";
|
|
4681
|
+
const scalar = receiverType.kind === "string" || receiverType.kind === "f64" ||
|
|
4682
|
+
receiverType.kind === "bool" || receiverType.kind === "bigint" ||
|
|
4683
|
+
(receiverType.kind === "union" && (lowerer.unions.get(receiverType.unionId)?.arms.every((arm) => arm.kind === "string" || arm.kind === "f64" || arm.kind === "bool" || arm.kind === "bigint") ?? false));
|
|
4684
|
+
// Other methods convert object receivers before lowering their arguments;
|
|
4685
|
+
// padding uses a helper that delays conversion until every argument is ready.
|
|
4686
|
+
const objectWithoutMethodArgs = entry.maxArgs === 0 && call.arguments.length === 1 &&
|
|
4687
|
+
(receiverType.kind === "record" || receiverType.kind === "array" || receiverType.kind === "object");
|
|
4688
|
+
const dynObjectWithoutMethodArgs = entry.maxArgs === 0 && call.arguments.length === 1 &&
|
|
4689
|
+
receiverType.kind === "dyn" && plainObjectCoercionReceiver(lowerer, receiverNode);
|
|
4690
|
+
if (!scalar && !objectWithoutMethodArgs && !dynObjectWithoutMethodArgs && !(padding && receiverType.kind === "dyn")) {
|
|
4691
|
+
return lowerer.noLowering(`String.prototype.${methodAccess.name.text}.call with ${lowerer.fmt(receiverType)} receivers`, call);
|
|
4692
|
+
}
|
|
4693
|
+
if (padding) {
|
|
4694
|
+
return lowerStringPaddingCall(lowerer, call, entry.method, receiverValue, receiverNode, call.arguments.slice(1));
|
|
4695
|
+
}
|
|
4696
|
+
const receiver = dynObjectWithoutMethodArgs
|
|
4697
|
+
? { kind: "libCall", fn: "dyn.toStringCoerce", args: [receiverValue], type: STRING, loc }
|
|
4698
|
+
: lowerer.ensureString(receiverValue, receiverNode);
|
|
4699
|
+
return lowerStringMethodCallWithOptionalArgs(lowerer, call, methodAccess, () => receiver, call.arguments.slice(1));
|
|
4700
|
+
}
|
|
4701
|
+
function lowerScalarUnionNumber(lowerer, arg, node, loc) {
|
|
4702
|
+
if (arg.type.kind !== "union" || !lowerer.unions.get(arg.type.unionId)?.arms.every((arm) => arm.kind === "f64" || arm.kind === "string" || arm.kind === "bool" || isUnitType(arm)))
|
|
4703
|
+
return null;
|
|
4704
|
+
const key = `number.scalar:${arg.type.unionId}`;
|
|
4705
|
+
let helper = lowerer.widthHelpers.get(key);
|
|
4706
|
+
if (!helper) {
|
|
4707
|
+
helper = `%number.scalar.${lowerer.widthHelpers.size}`;
|
|
4708
|
+
lowerer.widthHelpers.set(key, helper);
|
|
4709
|
+
const value = varRef("value.0", arg.type, loc);
|
|
4710
|
+
const nan = {
|
|
4711
|
+
kind: "bin", op: "/", left: { kind: "numLit", value: 0, type: F64, loc },
|
|
4712
|
+
right: { kind: "numLit", value: 0, type: F64, loc }, type: F64, loc,
|
|
4713
|
+
};
|
|
4714
|
+
lowerer.liftedFns.push({
|
|
4715
|
+
name: helper,
|
|
4716
|
+
params: [{ localId: "value.0", name: "value", type: arg.type }],
|
|
4717
|
+
returnType: F64,
|
|
4718
|
+
locals: [{ id: "value.0", name: "value", type: arg.type, mutable: false }],
|
|
4719
|
+
body: [{ kind: "return", value: positionNumber(lowerer, value, nan, node, "Number argument"), loc }],
|
|
4720
|
+
loc,
|
|
4721
|
+
});
|
|
4722
|
+
}
|
|
4723
|
+
return { kind: "call", callee: helper, args: [arg], type: F64, loc };
|
|
4724
|
+
}
|
|
4545
4725
|
function lowerOptionalStringNumber(lowerer, arg, loc, fn = "num.fromString", label = "number") {
|
|
4546
4726
|
if (arg.type.kind !== "union")
|
|
4547
4727
|
return null;
|
|
@@ -5893,26 +6073,23 @@ export function lambdaSignature(lowerer, node) {
|
|
|
5893
6073
|
ret = VOID;
|
|
5894
6074
|
}
|
|
5895
6075
|
}
|
|
5896
|
-
//
|
|
5897
|
-
//
|
|
5898
|
-
//
|
|
5899
|
-
//
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
// declared params the alias story has no model — the fence says to
|
|
5904
|
-
// use a rest parameter. Arrows never claim it (JS: an arrow's
|
|
5905
|
-
// `arguments` is the enclosing function's).
|
|
5906
|
-
const hasDynRest = shapes.some((s) => s.mode === "dynRest");
|
|
5907
|
-
const usesArguments = !hasDynRest &&
|
|
5908
|
-
!ts.isArrowFunction(node) &&
|
|
6076
|
+
// A plain JS function reading `arguments` receives one hidden dyn
|
|
6077
|
+
// array. With named parameters, the array contains every actual
|
|
6078
|
+
// argument and only ES modules are admitted: sloppy-mode arguments
|
|
6079
|
+
// alias named parameters. Arrows inherit the enclosing `arguments`.
|
|
6080
|
+
const hasRest = shapes.some((s) => s.mode === "rest" || s.mode === "dynRest" || s.mode === "islandRest");
|
|
6081
|
+
const usesArguments = !hasRest &&
|
|
6082
|
+
(ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) &&
|
|
5909
6083
|
isJsSourceFile(node.getSourceFile()) &&
|
|
5910
6084
|
bodyReadsArguments(node);
|
|
5911
6085
|
if (usesArguments && node.parameters.length > 0) {
|
|
5912
|
-
|
|
6086
|
+
if (!isNodeEsmFile(node.getSourceFile())) {
|
|
6087
|
+
lowerer.unsupported("SC1090", node, "parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases)");
|
|
6088
|
+
}
|
|
6089
|
+
shapes.push({ type: DYN, mode: "arguments" });
|
|
5913
6090
|
}
|
|
5914
6091
|
const funcType = funcTypeFromParamShapes(shapes, ret);
|
|
5915
|
-
if (usesArguments
|
|
6092
|
+
if (usesArguments)
|
|
5916
6093
|
funcType.rest = true;
|
|
5917
6094
|
return { shapes, funcType };
|
|
5918
6095
|
}
|
|
@@ -5988,9 +6165,9 @@ export function lowerLambda(lowerer, node) {
|
|
|
5988
6165
|
lowerer.fnStack.push(fnCtx);
|
|
5989
6166
|
try {
|
|
5990
6167
|
const { params, prologue } = lowerer.declareParams(node.parameters, shapes);
|
|
5991
|
-
// The
|
|
5992
|
-
//
|
|
5993
|
-
//
|
|
6168
|
+
// The synthetic trailing dyn-array param carries `arguments`.
|
|
6169
|
+
// Parameterized functions receive all actual arguments; zero-param
|
|
6170
|
+
// functions receive the same array through their rest ABI.
|
|
5994
6171
|
if (funcType.rest && !shapes.some((s) => s.mode === "dynRest" || s.mode === "islandRest")) {
|
|
5995
6172
|
const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
|
|
5996
6173
|
params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
|
|
@@ -7072,9 +7249,10 @@ function lowerBigIntMethodCall(lowerer, call, access) {
|
|
|
7072
7249
|
if (name === "valueOf" && call.arguments.length === 0)
|
|
7073
7250
|
return receiver;
|
|
7074
7251
|
if (name === "toString" && call.arguments.length <= 1) {
|
|
7252
|
+
const defaultRadix = { kind: "numLit", value: 10, type: F64, loc };
|
|
7075
7253
|
const radix = call.arguments[0]
|
|
7076
|
-
? lowerer
|
|
7077
|
-
:
|
|
7254
|
+
? lowerOptionalArgument(lowerer, call.arguments[0], F64, defaultRadix)
|
|
7255
|
+
: defaultRadix;
|
|
7078
7256
|
return { kind: "libCall", fn: "bigint.toString", args: [receiver, radix], type: STRING, loc };
|
|
7079
7257
|
}
|
|
7080
7258
|
return null;
|
|
@@ -8092,10 +8270,9 @@ export function lowerFunction(lowerer, decl) {
|
|
|
8092
8270
|
lowerer.fnStack.push(ctx);
|
|
8093
8271
|
try {
|
|
8094
8272
|
const { params, prologue } = lowerer.declareParams(decl.parameters, sig.params);
|
|
8095
|
-
// The synthetic `arguments` slot
|
|
8096
|
-
//
|
|
8097
|
-
|
|
8098
|
-
if (sig.params.length > decl.parameters.length && sig.params[sig.params.length - 1].mode === "dynRest") {
|
|
8273
|
+
// The synthetic `arguments` slot follows the declared parameters;
|
|
8274
|
+
// reads resolve to this dyn array.
|
|
8275
|
+
if (sig.params.length > decl.parameters.length && (sig.params[sig.params.length - 1].mode === "dynRest" || sig.params[sig.params.length - 1].mode === "arguments")) {
|
|
8099
8276
|
const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
|
|
8100
8277
|
params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
|
|
8101
8278
|
ctx.argumentsLocal = argsLocal;
|