mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-04 08:04:37 +08:00
`using` and `await using` now accept object literals and other values typed Disposable, AsyncDisposable or unknown. The declaration reads the value's [Symbol.dispose] method ([Symbol.asyncDispose] first for `await using`) and throws Node's TypeErrors for values that are not objects and for missing or non-callable methods; null and undefined dispose nothing. Scope exit calls the method with the value as `this`, and `await using` awaits the result of an async method but not of the sync fallback. A class instance reached through such a value throws an SC2020 error, because its dynamic view has no methods. SuppressedError is its own error class: a failing disposal over a pending error throws one whose `error` is the disposal error and whose `suppressed` is the pending error, both non-enumerable as in Node. `new SuppressedError(error, suppressed, message?)` and `instanceof SuppressedError` compile, and `extends SuppressedError` is refused.
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
// SuppressedError: the error a 'using' disposal raises over a pending error,
|
|
// with its error and suppressed values, nested disposals, and the constructor.
|
|
// Node.js prints the same.
|
|
class Bad implements Disposable {
|
|
label: string;
|
|
constructor(label: string) {
|
|
this.label = label;
|
|
}
|
|
[Symbol.dispose](): void {
|
|
throw new Error("dispose " + this.label);
|
|
}
|
|
}
|
|
try {
|
|
using x = new Bad("x");
|
|
throw new Error("in body");
|
|
} catch (e) {
|
|
const se = e as SuppressedError;
|
|
console.log(se.name, se.message, e instanceof SuppressedError, e instanceof Error);
|
|
console.log((se.error as Error).message, (se.suppressed as Error).message);
|
|
console.log(String(se));
|
|
}
|
|
try {
|
|
using a = new Bad("a");
|
|
using b = new Bad("b");
|
|
throw new RangeError("body");
|
|
} catch (e) {
|
|
if (e instanceof SuppressedError) {
|
|
const inner = e.suppressed;
|
|
if (inner instanceof SuppressedError)
|
|
console.log((e.error as Error).message, inner.name, (inner.error as Error).message, (inner.suppressed as Error).name);
|
|
}
|
|
}
|
|
try {
|
|
using a = new Bad("only");
|
|
} catch (e) {
|
|
console.log(e instanceof SuppressedError, (e as Error).message);
|
|
}
|
|
const made = new SuppressedError(1, "two", "msg");
|
|
console.log(made.error, made.suppressed, made.message, made.name, made instanceof SuppressedError);
|
|
const bare = new SuppressedError(new TypeError("t"), undefined);
|
|
console.log(JSON.stringify(bare.message), (bare.error as Error).name, bare.suppressed);
|
|
try {
|
|
using v = { [Symbol.dispose]() { throw 42; } } as Disposable;
|
|
throw "body";
|
|
} catch (e) {
|
|
const se = e as SuppressedError;
|
|
console.log(se.error, se.suppressed);
|
|
}
|