Read and write the "undefined" property for element indexes that are undefined (#1930)

This commit is contained in:
Chris Tate
2026-10-22 21:39:58 -05:00
committed by GitHub
15 changed files with 374 additions and 41 deletions
@@ -1583,6 +1583,7 @@ export const LIB_FN_SYMS: Record<string, string> = {
"regex.resultProp": "scr_regex_result_prop",
"array.namedKeys": "scr_arr_named_keys",
"array.hasNamedKey": "scr_arr_has_named_key",
"array.undefinedKey": "scr_arr_undefined_key",
// queueMicrotask's checked-dynamic form (borrowed dyn; a non-function
// throws synchronously), the minted setImmediate value, and the
// timers/promises immediate — all mark the loop live.
@@ -1,10 +1,10 @@
import * as ts from "../../ts7/adapter.js";
import { lowerOptionalIndex } from "../undefined-index.js";
import { locOf } from "../../program.js";
import { varRef } from "../../../ir/build.js";
import { DYN, type IrExpr, type IrStmt, isUnitType } from "../../../ir/ir.js";
import type { Lowerer } from "../lowerer.js";
import { completeFuncValueArgs } from "../call-arguments.js";
import { lowerOptionalNumber } from "../lower-exprs.js";
import { lowerSafeIndexRead } from "../array-values.js";
/** Retain native function slots during indexed calls. The array remains
@@ -37,7 +37,7 @@ export function lowerArrayCallbackCall(
return varRef(local.id, local.type, loc);
};
const receiver = store(array, "%callbackArray");
const index = lowerOptionalNumber(
const index = lowerOptionalIndex(
lowerer,
lowerer.lowerExpr(access.argumentExpression),
locOf(access.argumentExpression),
@@ -1,6 +1,11 @@
/* Binary operators: arithmetic, comparisons and equality, logical and nullish pairs, and string conversion for concatenation. */
import { keyedHelperName } from "../stable-names.js";
import * as ts from "../../ts7/adapter.js";
import {
lowerOptionalIndex,
splitUndefinedIndex,
undefinedTypedArrayKeyFence,
} from "../undefined-index.js";
import { cleanFuncAdaptable } from "../coercions/function-adapters.js";
import { type Lowerer, jsFuncNameOf } from "../lowerer.js";
import {
@@ -1160,12 +1165,26 @@ export function lowerBinary(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr
}
if (recv?.type.kind === "array" || recv?.type.kind === "bytes") {
const receiver = lowerer.declareHiddenLocal("%setArray", recv.type);
const index = lowerOptionalNumber(
lowerer,
lowerer.lowerExpr(expr.left.argumentExpression),
locOf(expr.left.argumentExpression),
expr.left.argumentExpression,
);
// An undefined index names the "undefined" property
// (undefined-index.ts), which a typed array cannot hold.
const rawIndex = lowerer.lowerExpr(expr.left.argumentExpression);
const split =
recv.type.kind === "bytes"
? splitUndefinedIndex(
lowerer,
rawIndex,
expr.left.argumentExpression,
locOf(expr.left.argumentExpression),
)
: null;
const index =
split?.index ??
lowerOptionalIndex(
lowerer,
rawIndex,
locOf(expr.left.argumentExpression),
expr.left.argumentExpression,
);
if (index.type.kind !== "f64")
lowerer.unsupported(
"SC1090",
@@ -1178,7 +1197,7 @@ export function lowerBinary(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr
const result = varRef(value.id, raw.type, loc);
const arr = varRef(receiver.id, recv.type, loc);
const idx = varRef(key.id, F64, loc);
const write: IrStmt =
const store: IrStmt =
recv.type.kind === "array"
? arrayValueStore(lowerer, arr, idx, result, recv.type.elem, loc)
: {
@@ -1188,10 +1207,20 @@ export function lowerBinary(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr
value: lowerer.coerceInto(expr.right, result, F64),
loc,
};
const write: IrStmt = split
? {
kind: "if",
cond: split.isUndefined,
then: [undefinedTypedArrayKeyFence(lowerer, expr.left, loc)],
else_: [store],
loc,
}
: store;
return {
kind: "seqExpr",
stmts: [
{ kind: "varDecl", localId: receiver.id, init: recv, loc },
...(split?.stmts ?? []),
{ kind: "varDecl", localId: key.id, init: index, loc },
{ kind: "varDecl", localId: value.id, init: raw, loc },
write,
@@ -1,5 +1,10 @@
/* Element reads and writes (`a[i]`, `a[i] = v`), compound element updates, and keyed record reads. */
import * as ts from "../../ts7/adapter.js";
import {
lowerOptionalIndex,
splitUndefinedIndex,
undefinedTypedArrayKeyFence,
} from "../undefined-index.js";
import { type Lowerer, jsFuncNameOf, neverTaintedJsType } from "../lowerer.js";
import {
BOOL,
@@ -779,9 +784,9 @@ export function lowerElementAccess(lowerer: Lowerer, expr: ts.ElementAccessExpre
}
}
// Array reads can themselves supply an index. A missing numeric value
// is undefined, whose property lookup misses just like NaN; keep that
// value instead of rejecting a checker-number index with optional IR.
const index = lowerOptionalNumber(
// is undefined, which names the array's "undefined" property
// (undefined-index.ts).
const index = lowerOptionalIndex(
lowerer,
lowerer.lowerExpr(expr.argumentExpression),
locOf(expr.argumentExpression),
@@ -1531,12 +1536,26 @@ export function lowerElementCompoundParts(
"compound assignment through a non-native array or byte view",
);
}
const index = lowerOptionalNumber(
lowerer,
lowerer.lowerExpr(target.argumentExpression),
locOf(target.argumentExpression),
target.argumentExpression,
);
// An undefined index names the "undefined" property (undefined-index.ts),
// which a typed array cannot hold.
const rawIndex = lowerer.lowerExpr(target.argumentExpression);
const split =
receiver.type.kind === "bytes"
? splitUndefinedIndex(
lowerer,
rawIndex,
target.argumentExpression,
locOf(target.argumentExpression),
)
: null;
const index =
split?.index ??
lowerOptionalIndex(
lowerer,
rawIndex,
locOf(target.argumentExpression),
target.argumentExpression,
);
if (index.type.kind !== "f64")
lowerer.unsupported("SC1090", target.argumentExpression, "indexing with non-number keys");
const receiverLocal = lowerer.declareHiddenLocal("%compoundArray", receiver.type);
@@ -1645,15 +1664,25 @@ export function lowerElementCompoundParts(
}
const resultLocal = lowerer.declareHiddenLocal("%compoundResult", computed.type);
const resultRef = (): IrExpr => varRef(resultLocal.id, computed.type, loc);
const write: IrStmt =
const store: IrStmt =
receiver.type.kind === "array"
? arrayValueStore(lowerer, receiverRef(), indexRef(), resultRef(), receiver.type.elem, loc)
: { kind: "bytesSet", arr: receiverRef(), index: indexRef(), value: resultRef(), loc };
const write: IrStmt = split
? {
kind: "if",
cond: split.isUndefined,
then: [undefinedTypedArrayKeyFence(lowerer, target, loc)],
else_: [store],
loc,
}
: store;
return {
expr: {
kind: "seqExpr",
stmts: [
{ kind: "varDecl", localId: receiverLocal.id, init: receiver, loc },
...(split?.stmts ?? []),
{ kind: "varDecl", localId: indexLocal.id, init: index, loc },
{ kind: "varDecl", localId: oldLocal.id, init: oldValue, loc },
{ kind: "varDecl", localId: resultLocal.id, init: computed, loc },
@@ -1880,13 +1909,23 @@ export function lowerElementWrite(lowerer: Lowerer, expr: ts.BinaryExpression):
// The checker's flow type is a typed array, but the storage is wider.
if (recv.type.kind !== "bytes") return lowerWiderBytesWrite(lowerer, expr, target, recv);
// An index the checker types as a number but whose storage may hold
// undefined (a hole read) converts with ToNumber, as the reads do.
const index = lowerOptionalNumber(
// undefined (a hole read) converts with ToNumber, as the reads do; an
// undefined index names a property the typed array cannot hold.
const rawIndex = lowerer.lowerExpr(target.argumentExpression);
const split = splitUndefinedIndex(
lowerer,
lowerer.lowerExpr(target.argumentExpression),
locOf(target.argumentExpression),
rawIndex,
target.argumentExpression,
locOf(target.argumentExpression),
);
const index =
split?.index ??
lowerOptionalNumber(
lowerer,
rawIndex,
locOf(target.argumentExpression),
target.argumentExpression,
);
if (index.type.kind === "dyn" && recv.type.kind === "bytes") {
return {
kind: "exprStmt",
@@ -1902,7 +1941,34 @@ export function lowerElementWrite(lowerer: Lowerer, expr: ts.BinaryExpression):
lowerer.unsupported("SC1090", target.argumentExpression, "indexing with non-number keys");
}
const value = lowerer.lowerExprExpecting(expr.right, F64);
return { kind: "bytesSet", arr: recv, index, value, loc: locOf(expr) };
if (split === null) return { kind: "bytesSet", arr: recv, index, value, loc: locOf(expr) };
const loc = locOf(expr);
const receiver = lowerer.declareHiddenLocal("%indexedBytes", recv.type);
const valueLocal = lowerer.declareHiddenLocal("%elementValue", F64);
return {
kind: "block",
body: [
{ kind: "varDecl", localId: receiver.id, init: recv, loc },
...split.stmts,
{ kind: "varDecl", localId: valueLocal.id, init: value, loc },
{
kind: "if",
cond: split.isUndefined,
then: [undefinedTypedArrayKeyFence(lowerer, target, loc)],
else_: [
{
kind: "bytesSet",
arr: varRef(receiver.id, recv.type, loc),
index,
value: varRef(valueLocal.id, F64, loc),
loc,
},
],
loc,
},
],
loc,
};
}
// Tuple element write `t[0] = v`: a positional-field write (recordSet)
// — literal indices only, like the read.
@@ -2197,7 +2263,7 @@ export function lowerElementWrite(lowerer: Lowerer, expr: ts.BinaryExpression):
"assignment through a possibly missing nested array receiver",
);
}
const index = lowerOptionalNumber(
const index = lowerOptionalIndex(
lowerer,
lowerer.lowerExpr(target.argumentExpression),
locOf(target.argumentExpression),
@@ -1,5 +1,10 @@
/* Increment, decrement and prefix unary operators, and compound field updates. */
import * as ts from "../../ts7/adapter.js";
import {
lowerOptionalIndex,
splitUndefinedIndex,
undefinedTypedArrayKeyFence,
} from "../undefined-index.js";
import { isStrictCode } from "../strict-mode.js";
import { isPrivateWriteReceiver } from "../private-brands.js";
import type { Lowerer } from "../lowerer.js";
@@ -311,12 +316,27 @@ export function lowerIncDec(
(raw.type.kind === "array" || raw.type.kind === "bytes")
) {
const receiver = save(raw, "%incrementArray");
const rawIndex = lowerOptionalNumber(
lowerer,
lowerer.lowerExpr(access.argumentExpression),
locOf(access.argumentExpression),
access.argumentExpression,
);
// An undefined index names the "undefined" property
// (undefined-index.ts), which a typed array cannot hold.
const loweredIndex = lowerer.lowerExpr(access.argumentExpression);
const split =
raw.type.kind === "bytes"
? splitUndefinedIndex(
lowerer,
loweredIndex,
access.argumentExpression,
locOf(access.argumentExpression),
)
: null;
if (split) stmts.push(...split.stmts);
const rawIndex =
split?.index ??
lowerOptionalIndex(
lowerer,
loweredIndex,
locOf(access.argumentExpression),
access.argumentExpression,
);
const index = save(
rawIndex.type.kind === "dyn" && isJsSourceFile(ts.getSourceFileOfNode(expr))
? { kind: "libCall", fn: "dyn.toNumberCoerce", args: [rawIndex], type: F64, loc }
@@ -340,7 +360,7 @@ export function lowerIncDec(
loc,
invalidNaN: true,
};
return finish(read, (value) =>
const store = (value: IrExpr): IrStmt =>
type.kind === "array"
? arrayValueStore(
lowerer,
@@ -356,8 +376,15 @@ export function lowerIncDec(
index,
value: lowerer.coerceInto(access, value, F64),
loc,
},
);
};
if (!split) return finish(read, store);
return finish(read, (value) => ({
kind: "if",
cond: split.isUndefined,
then: [undefinedTypedArrayKeyFence(lowerer, access, loc)],
else_: [store(value)],
loc,
}));
}
// A TS member statically typed number on a checked-dynamic receiver (a
// class-backed protocol view): the expanded form `o.v = o.v + 1`, its
@@ -25,6 +25,7 @@ import { InternalCompilerError } from "../../errors.js";
* flow (if/while/for/for-of/do, switch, try/catch, abrupt completions),
* explicit resource management, and blocked-binding poisoning. */
import * as ts from "../ts7/adapter.js";
import { lowerOptionalIndex } from "./undefined-index.js";
import { processDataMemberValue, programReadsExitCode } from "./builtins/process.js";
import { requireInitFlagStmt } from "./require-initialization.js";
import { isJsonRequireDecl } from "./json-require.js";
@@ -204,7 +205,6 @@ import {
lowerElementCompoundStatement,
lowerIncDec,
lowerIncDecTarget,
lowerOptionalNumber,
lowerGroupsProjection,
matchResultNamedGroupsOf,
runtimeOptionalGuardIds,
@@ -9363,7 +9363,7 @@ function lowerAssignTargetInto(
if (arr.type.kind === "array") {
const recv = lowerer.declareHiddenLocal("%dtRecv", arr.type);
out.push({ kind: "varDecl", localId: recv.id, init: arr, loc });
const index = lowerOptionalNumber(
const index = lowerOptionalIndex(
lowerer,
lowerer.lowerExpr(t.argumentExpression),
locOf(t.argumentExpression),
@@ -0,0 +1,101 @@
import * as ts from "../ts7/adapter.js";
import { BOOL, DYN, F64, UNDEFINED_T, type IrExpr, type IrStmt, type SrcLoc } from "../../ir/ir.js";
import { varRef } from "../../ir/build.js";
import type { Lowerer } from "./lowerer.js";
import { lowerOptionalNumber } from "./lower-exprs.js";
import { keyedHelperName } from "./stable-names.js";
/** An element index the checker types as a number can be undefined at run
* time (an element read from a holey array). JavaScript then names the
* property "undefined", not "NaN". */
/** The array element index `operand` (the lowered index of `node`) as a
* number. An undefined index is the runtime's "undefined" key
* (`array.undefinedKey`, a NaN the array's property table spells
* "undefined"); other values convert with ToNumber, as lowerOptionalNumber
* does. */
export function lowerOptionalIndex(
lowerer: Lowerer,
operand: IrExpr,
loc: SrcLoc,
node: ts.Expression,
): IrExpr {
const split = splitUndefinedIndex(lowerer, operand, node, loc);
if (split === null) return lowerOptionalNumber(lowerer, operand, loc, node);
return {
kind: "seqExpr",
stmts: split.stmts,
result: {
kind: "ternary",
cond: split.isUndefined,
then: { kind: "libCall", fn: "array.undefinedKey", args: [], type: F64, loc },
else_: split.index,
type: F64,
loc,
},
type: F64,
loc,
};
}
/** A typed-array element index that can be undefined: `stmts` evaluate it
* once, `isUndefined` tests it, and `index` is the number a defined index
* converts to. */
export interface SplitIndex {
stmts: IrStmt[];
isUndefined: IrExpr;
index: IrExpr;
}
/** Splits `raw`, the lowered index of `node`, when it is a number that can
* be undefined; null otherwise. */
export function splitUndefinedIndex(
lowerer: Lowerer,
raw: IrExpr,
node: ts.Expression,
loc: SrcLoc,
): SplitIndex | null {
if (raw.type.kind !== "union") return null;
const undefinedTag = lowerer.armTag(raw.type.unionId, UNDEFINED_T);
if (undefinedTag < 0) return null;
const local = lowerer.declareHiddenLocal("%elementIndex", raw.type);
const stable = varRef(local.id, raw.type, loc);
const index = lowerOptionalNumber(lowerer, stable, loc, node);
if (index.type.kind !== "f64") return null;
return {
stmts: [{ kind: "varDecl", localId: local.id, init: raw, loc }],
isUndefined: {
kind: "unionIsTag",
unionId: raw.type.unionId,
tag: undefinedTag,
negated: false,
value: stable,
type: BOOL,
loc,
},
index,
};
}
/** A typed array has no property named "undefined" to store into: the
* store throws the catchable SC1090 error when it runs. A call, so that it
* can sit among an expression's statements. */
export function undefinedTypedArrayKeyFence(lowerer: Lowerer, node: ts.Node, loc: SrcLoc): IrStmt {
const line = ts.getLineAndCharacterOfPosition(ts.getSourceFileOfNode(node), loc.start).line + 1;
const message = `typed array properties named 'undefined' (an element index that is undefined) are not supported yet [SC1090 at ${loc.file}:${line}]`;
const key = `index.undefinedFence:${message}`;
let name = lowerer.arrHofHelpers.get(key);
if (name === undefined) {
name = keyedHelperName(lowerer, "%index.undefinedFence", key);
lowerer.arrHofHelpers.set(key, name);
lowerer.liftedFns.push({
name,
params: [],
locals: [],
returnType: DYN,
body: [{ kind: "runtimeFence", code: "SC1090", message, loc }],
loc,
});
}
return { kind: "exprStmt", expr: { kind: "call", callee: name, args: [], type: DYN, loc }, loc };
}
@@ -3813,6 +3813,9 @@ export const LIB_FN_SIGS = defineLibFnSignatures({
// Whether the array (args[0]) still has the key (args[1]) from its
// namedKeys list. Borrowed; never throws.
"array.hasNamedKey": { argTypes: [null, STRING], result: BOOL },
// The key of an element access whose index is undefined (the property
// named "undefined"; frontend/lowering/undefined-index.ts).
"array.undefinedKey": { argTypes: [], result: F64 },
// node:events EventEmitter: receivers are emitter-hierarchy objects and
// the chaining forms (on/off/removeAll/setMax) return the receiver's
// own class — program-dependent object types, checked in the libCall
+3 -2
View File
@@ -2099,8 +2099,9 @@ export type IrStmt =
* and whose `code` carries the SC diagnostic code; unwinds exactly like
* `throw`.
* TypeScript sources produce it only as the tsc-unreachable fallthrough
* trap (appendImplicitUndefinedReturn's SC9002) — their construct fences
* stay compile errors. */
* trap (appendImplicitUndefinedReturn's SC9002) and for a typed-array
* store through an element index that is undefined at run time
* (undefined-index.ts); their construct fences stay compile errors. */
| { kind: "runtimeFence"; code: string; message: string; loc: SrcLoc }
/** Rethrow of a catch binding (`throw e` where e is the binding):
* re-raises the SAVED exception exactly — kind and payload preserved,
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/7540-undefined-element-index-keys.ts"
],
"diags": []
}
+20 -1
View File
@@ -176,7 +176,22 @@ static size_t scr_arr_prop_index(const ScrArr *a, const char *key,
return SIZE_MAX;
}
#define SCR_ARR_UNDEFINED_KEY_BITS UINT64_C(0x7ff8000000756e64)
double scr_arr_undefined_key(void) {
uint64_t bits = SCR_ARR_UNDEFINED_KEY_BITS;
double key;
memcpy(&key, &bits, sizeof key);
return key;
}
static size_t scr_arr_prop_key(double i, char *buf) {
uint64_t bits;
memcpy(&bits, &i, sizeof bits);
if (bits == SCR_ARR_UNDEFINED_KEY_BITS) {
memcpy(buf, "undefined", sizeof "undefined");
return sizeof "undefined" - 1;
}
return scr_f64_to_str(i, buf);
}
@@ -2012,7 +2027,7 @@ static uint64_t scr_arr_require_slot(ScrArr *a, double i) {
if (scr_arr_prop_get_state(a, i, &prop, &state)) {
if (state == SCR_ARR_UNDEFINED) {
char buf[32];
scr_f64_to_str(i, buf);
scr_arr_prop_key(i, buf);
scr_trap_fmt("scriptc: RangeError: numeric property %s is undefined\n", buf);
}
return prop;
@@ -5121,6 +5136,10 @@ ScrStr *scr_str_raw(ScrArr *raw, ScrArr *subs) {
bool scr_arr_numeric_key(const char *key, size_t len, double *out) {
char text[64];
if (len == sizeof "undefined" - 1 && memcmp(key, "undefined", len) == 0) {
*out = scr_arr_undefined_key();
return true;
}
if (len == 0 || len >= sizeof text) return false;
memcpy(text, key, len);
text[len] = '\0';
+8 -2
View File
@@ -457,9 +457,15 @@ void scr_arr_copy_metadata(ScrArr *a, struct ScrDyn *target);
* properties of `target`, so neither is lost when the storage is swapped. */
void scr_arr_adopt_view_properties(ScrArr *a, struct ScrDyn *view, ScrArr *target);
/* True when `key` is the string spelling of a number that is not an array
* index ("-1", "1.5", "NaN", "Infinity"), with the number in *out. Arrays
* keep such properties in their noncanonical property table. */
* index ("-1", "1.5", "NaN", "Infinity"), or "undefined", with the number in
* *out (scr_arr_undefined_key for "undefined"). Arrays keep such properties
* in their noncanonical property table. */
bool scr_arr_numeric_key(const char *key, size_t len, double *out);
/* The number compiled code passes as the key of an element access whose
* index is undefined at run time: a NaN with its own payload, which the
* property table spells "undefined" (JavaScript names that property, not
* "NaN"). */
double scr_arr_undefined_key(void);
/* Whether the array still has the named or noncanonical numeric property
* `key`: `for...in` skips a key deleted before its turn. Borrows both. */
bool scr_arr_has_named_key(ScrArr *a, ScrStr *key);
@@ -0,0 +1,53 @@
// An element index the checker types as a number can be undefined at run
// time (an element read from a holey array). JavaScript then names the
// array's "undefined" property, not "NaN": plain, compound, update and
// destructuring writes store it, a write used as a value yields the value,
// and reads (number, string, record and array elements) read it back.
const holey: number[] = [1];
holey[3] = 3;
const values: number[] = [0, 0, 0, 0];
values[NaN] = 10;
for (const i of holey) values[i] = 7;
console.log(values[NaN], values.join(","));
let total = 0;
for (const i of holey) total += values[i]!;
console.log(total);
const counts: number[] = [0, 0, 0, 0];
counts[NaN] = 10;
let trace = "";
for (const i of holey) trace += counts[i]++ + ",";
for (const i of holey) counts[i] += 2;
for (const i of holey) trace += --counts[i] + ";";
console.log(counts[NaN], counts.join(","), trace);
let last = 0;
for (const i of holey) last = values[i] = 5;
for (const i of holey) [values[i]] = [8];
console.log(last, values[NaN], values.join(","));
const names: string[] = ["a", "b", "c", "d"];
for (const i of holey) names[i] += "!";
const seen: (string | undefined)[] = [];
for (const i of holey) seen.push(names[i]);
console.log(names.join("|"), seen.join("|"));
interface Point {
x: number;
}
const points: Point[] = [{ x: 0 }, { x: 1 }];
const shared: Point = { x: 9 };
let same = "";
for (const i of holey) {
points[i] = shared;
same += String(points[i] === shared) + " ";
}
shared.x = 10;
for (const i of holey) same += String(points[i]?.x) + " ";
console.log(same);
const fresh: number[] = [1, 2];
let missing = "";
for (const i of holey) missing += String(fresh[i]) + " ";
console.log(missing);
@@ -0,0 +1 @@
{ "plain": 3700, "san": 5300 }
+20
View File
@@ -305,6 +305,26 @@ describe("checked catch-binding casts", () => {
);
});
test("a typed-array write through an undefined index is a named runtime fence", async () => {
// Node stores an ordinary property named "undefined" on the typed
// array, which a compiled typed array cannot hold; defined indexes
// before it store as usual.
const r = await compileAndRun(
"typed-array-undefined-index",
`const holey: number[] = [1];
holey[3] = 3;
const cells = new Float64Array(4);
for (const i of holey) cells[i] = 9;
console.log(cells.join(","));
`,
);
expect(r.exitCode).toBe(1);
expect(r.stdout).toBe("");
expect(r.stderr).toMatch(
/^Uncaught Error: typed array properties named 'undefined' \(an element index that is undefined\) are not supported yet \[SC1090 at .*typed-array-undefined-index\.ts:4\]\n$/,
);
});
test("an EFFECTFUL surplus argument is a named deferred fence (JS lane)", async () => {
// Effect-free surplus args drop at compile time, JS-exact (corpus
// 1760 — the test-string-decoder writeSequences shape). An effectful