Lower a discarded undefined catch handler

`Promise<void>.catch(() => undefined)` tripped the IR validator's
bare-unitLit rule: the handler body lowered as a bare expression, and
`undefined` has no standalone IR value. The handler's value is
discarded, so lower the body as a statement — the same rule a
discarded `undefined;` statement already follows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Malte Ubl
2026-10-28 05:37:49 -07:00
co-authored by Claude Opus 5.5
parent ed90c10fce
commit 279d42e562
2 changed files with 35 additions and 1 deletions
@@ -6908,7 +6908,10 @@ export function lowerPromiseMethodCall(
if (ts.isBlock(hb)) {
catchBody = lowerer.lowerStmts(hb.statements.nodes);
} else if (R.kind === "void") {
catchBody = [{ kind: "exprStmt", expr: lowerer.lowerExpr(hb), loc: locOf(hb) }];
// The handler's value is discarded, so the body lowers as a
// statement: `() => undefined` is a pure no-op (a bare unit
// literal has no IR value), not an expression to evaluate.
catchBody = [lowerer.lowerExprStatement(hb)];
} else {
// Bare-expression handler: `(e) => v` (promise results flatten
// through the async-return path, like any `return v`).
@@ -0,0 +1,31 @@
// `Promise<void>.catch(() => undefined)` — the handler's value is
// discarded and the recovered promise settles as void. The handler runs
// exactly once, and the chain continues on the next turn whether the
// receiver fulfilled or rejected.
const ok: Promise<void> = Promise.resolve();
const bad: Promise<void> = Promise.reject(new Error("boom"));
ok.catch(() => undefined).then(() => console.log("fulfilled recovered"));
bad
.catch(() => {
console.log("rejected recovered");
})
.then(() => console.log("rejected continued"));
let runs = 0;
function recover(): Promise<void> {
runs++;
return runs % 2 === 1 ? Promise.reject(new Error("odd")) : Promise.resolve();
}
async function run(): Promise<void> {
await recover().catch(() => undefined);
console.log("awaited recover", runs);
await recover().catch(() => undefined);
console.log("awaited recover", runs);
}
void run().then(() => console.log("done"));