mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-05 08:13:06 +08:00
Read spread tuple fields before later rest arguments run
The packing path for `(T | undefined)[]` rest parameters saved plain arguments to temporaries but read tuple fields only when it built the pack, after every later argument had run. A later argument that wrote the tuple changed values already spread into the call. Each tuple field is now saved where its spread appears, in argument order.
This commit is contained in:
@@ -421,12 +421,16 @@ export function completeArgs(
|
||||
) {
|
||||
const stmts: IrStmt[] = [];
|
||||
const values = restNodes.map((a): IrExpr => {
|
||||
// A tuple field is read where its spread appears: a later
|
||||
// argument may write the tuple.
|
||||
let value: IrExpr;
|
||||
if (isIr(a)) {
|
||||
if (a.ir.kind !== "seqExpr") return a.ir;
|
||||
stmts.push(...a.ir.stmts);
|
||||
return a.ir.result;
|
||||
}
|
||||
const value = lowerer.lowerExpr(a as ts.Expression);
|
||||
value = a.ir;
|
||||
if (value.kind === "seqExpr") {
|
||||
stmts.push(...value.stmts);
|
||||
value = value.result;
|
||||
}
|
||||
} else value = lowerer.lowerExpr(a as ts.Expression);
|
||||
const saved = lowerer.declareHiddenLocal("%callArg", value.type);
|
||||
stmts.push({ kind: "varDecl", localId: saved.id, init: value, loc: value.loc });
|
||||
return { kind: "varRef", localId: saved.id, type: value.type, loc: value.loc };
|
||||
|
||||
@@ -33,6 +33,22 @@ function label(first: string, ...rest: (string | undefined)[]): string {
|
||||
}
|
||||
const words: [string, string | undefined, string | undefined] = ["a", undefined, "c"];
|
||||
console.log(label(...words), label("b", undefined));
|
||||
// Spread tuple fields are read before later arguments run.
|
||||
const changing: [boolean, boolean | undefined] = [true, undefined];
|
||||
function flip(pair: [boolean, boolean | undefined], second: boolean | undefined): boolean {
|
||||
pair[0] = !pair[0];
|
||||
pair[1] = second;
|
||||
return pair[0];
|
||||
}
|
||||
console.log(flags(...changing, flip(changing, true)));
|
||||
console.log(flags(...changing, flip(changing, undefined), ...changing));
|
||||
const swapped: [string, string | undefined] = ["x", "y"];
|
||||
function swap(pair: [string, string | undefined]): string {
|
||||
pair[0] = "w";
|
||||
pair[1] = undefined;
|
||||
return "v";
|
||||
}
|
||||
console.log(label("z", ...swapped, swap(swapped), ...swapped));
|
||||
|
||||
function pick(start: (number | undefined)[] | string[], other: (number | undefined)[] | string[]): string {
|
||||
let a = start;
|
||||
|
||||
Reference in New Issue
Block a user