Open bathos opened 2 years ago
cc @evilpie @shvaikalesh @yuki3
I don't think this is really intentional. It's just a historical artifact of how DOMException has custom bindings, and nobody ever implemented this. See https://github.com/whatwg/webidl/pull/378 and in particular the second comment there.
IMO we should change this and it shouldn't be risky.
I think changing this should be relatively easy for Gecko.
I think that we can ask V8 team to expose the v8::FunctionTemplate of Error
and we can accommodate the right inheritance. No objection.
Summary of work to be done here:
DOMException
, then constructorProto should be set to realm.[[Intrinsics]].[[%Error%]].
The custom bindings for DOMException specify that DOMException.prototype.[[Prototype]] is %Error.prototype%. However it doesn’t also set DOMException.[[Prototype]] to %Error%, so instead it ends up with %Function.prototype%, which is what would occur for a “base” constructor.
This seems to make DOMException a pretty peculiar outlier. Among ECMAScript intrinsics, there are no cases where F.prototype.[[Prototype]] and F.[[Prototype]].prototype both exist yet point at different values. In Web IDL, this does also occur with
[LegacyFactoryFunction]
but in these cases, F.prototype.constructor isn’t actually F (and F does exhibit the normal pattern), so it’s relatively tough to run into the difference. In any case, scanning for it among globals suggests that DOMException’s constructor-prototype relationship is likely a true one-off:(code from image)
```js let i = 0; for (let key of Object.getOwnPropertyNames(globalThis).sort()) { let { value } = Object.getOwnPropertyDescriptor(globalThis, key); if (typeof value === "function" && value.prototype) { let cp = Object.getPrototypeOf(value); let pp = Object.getPrototypeOf(value.prototype); let isDerived = pp && pp !== Object.prototype; if (isDerived && value.prototype.constructor !== value) { console.warn(`${ key } is weird, but in a [LegacyFactoryFunction] way`); } else if (isDerived && cp !== pp.constructor) { console.error(`${ key } is (uniquely) weird!`); } else { i++; } } } console.log(`[${ i } other objects looked like normal constructors]`); // In Firefox, this printed: // Audio is weird, but in a [LegacyFactoryFunction] way // DOMException is (uniquely) weird! // Image is weird, but in a [LegacyFactoryFunction] way // Option is weird, but in a [LegacyFactoryFunction] way // [595 other objects looked like normal constructors] ```Among other quirks, this means
Error[@@hasInstance]
andError.isPrototypeOf
tell unexpectedly different stories about the relationship between Error and DOMException.Is DOMException’s departure from the typical prototype inheritance pattern intentional? It seems like the sort of thing that could plausibly have been necessitated by a web compat issue, but I didn’t turn up any history on it, and it also seems plausible that it was an oversight and actually should be specified to inherit from %Error%.