Save the receiver and key locals of a literal-union keyed write

This commit is contained in:
Chris Tate
2026-10-29 21:18:04 -05:00
parent 2cbdc9207f
commit 43c72a8e9b
2 changed files with 22 additions and 2 deletions
@@ -2610,14 +2610,14 @@ export function lowerElementWrite(lowerer: Lowerer, expr: ts.BinaryExpression):
// A key whose literal type names only declared fields of one type
// writes the field it names. JavaScript evaluates the receiver, then
// the key, then the value; the dispatch reads the saved receiver and
// key once per named field.
// key once per named field. Locals are saved too, because the key or
// the value can reassign them.
const named =
litKey === null ? sameTypedFieldKeys(lowerer, shape, target.argumentExpression) : null;
if (named && !shape.fields.every((f) => typeEquals(f.type, named.fieldType))) {
const loc = locOf(expr);
const body: IrStmt[] = [];
const save = (value: IrExpr, name: string): IrExpr => {
if (value.kind === "varRef") return value;
const temp = lowerer.declareHiddenLocal(name, value.type);
body.push({ kind: "varDecl", localId: temp.id, init: value, loc });
return varRef(temp.id, temp.type, loc);
+20
View File
@@ -76,3 +76,23 @@ function only(s: Stats, key: "bytes"): number {
return s[key];
}
console.log(only(stats[3]!, "bytes"));
// A key or value that reassigns the receiver or key local: the write goes
// to the receiver and key evaluated before them.
let target = stats[0]!;
let slot: Counter = "hits";
target[slot] = ((slot = "misses"), 500);
console.log(stats[0]!.hits, stats[0]!.misses, slot);
target[slot] = ((target = stats[2]!), 600);
console.log(stats[0]!.misses, stats[2]!.misses, target === stats[2]);
function retarget(): Counter {
target = stats[3]!;
return "bytes";
}
target = stats[1]!;
target[retarget()] = 700;
console.log(stats[1]!.bytes, stats[3]!.bytes === 700);
target = stats[0]!;
slot = "hits";
target[slot] += ((slot = "bytes"), (target = stats[1]!), 1);
console.log(stats[0]!.hits, stats[0]!.bytes, stats[1]!.hits);