Files
scriptc/tests/corpus/error-js-accessor-name-message.js
T
Malte UblandClaude Opus 5.5 d3bfa69323 Coerce the value passed to a JavaScript setter that overrides Error.name or message
A JavaScript class that extends Error and declares `set name(v)` or
`set message(v)` (quickjs-wasi's JSException) made the Error property
write dispatcher, which exists once any program writes `.name` or
`.message` on an Error, pass a string where the untyped setter takes a
dynamic value. IR validation failed with SC9001 "expected dyn, got
string". The dispatcher now coerces the value to the setter's parameter
type, which leaves TypeScript setters (string parameters) unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 15:19:37 -07:00

46 lines
1.2 KiB
JavaScript

// A JavaScript Error subclass that overrides name and message with accessor
// pairs, as quickjs-wasi's JSException does. Writing `.name` or `.message`
// on an ordinary Error builds the Error property dispatchers, whose branch
// for this class calls the JavaScript setters with an untyped value.
class GuestException extends Error {
#name;
#message;
constructor(name, message) {
super();
this.#name = name;
this.#message = message;
}
get name() {
return this.#name;
}
set name(v) {
this.#name = v;
}
get message() {
return this.#message;
}
set message(v) {
this.#message = `[${v}]`;
}
}
const guest = new GuestException("GuestError", "boom");
console.log(guest.name, guest.message, String(guest));
guest.name = "Renamed";
guest.message = "changed";
console.log(guest.name, guest.message, String(guest));
const plain = new Error("plain");
plain.name = "PlainName";
plain.message = "plain message";
console.log(plain.name, plain.message, String(plain));
/** @type {Error[]} */
const errors = [plain, guest, new TypeError("bad")];
for (const err of errors) console.log(String(err));
try {
throw guest;
} catch (caught) {
console.log(caught instanceof GuestException, caught instanceof Error, String(caught));
}