-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create a 'report an exception' algorithm per #958 #10404
base: main
Are you sure you want to change the base?
Conversation
This algorithm directly includes the error propagation and fallback behavior, and requires callers to supply the global scope to be used, rather than magically inferring it. Call sites within HTML are replaced, but there is more work yet to be done.
@domenic @annevk When you have a chance, would you mind an early review to make sure this aligns with what you had in mind as the first step of #958? There's probably a couple things that deserve a little extra attention before this is totally mergeable (see checkmarks above and class="XXX" added in this PR, some of which might be resolvable before merge), but want to make sure this is at least mostly correct. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Back from vacation! Thanks so much for tackling this.
I got halfway through the review. Then I had an epiphany. (Maybe some parts of the review are still useful.)
A lot of complexity and XXX boxes here and coming from passing the script around, and trying to determine which script to use. But Looking at the Chromium code, muting is not really done by passing a script around. It bottoms out in IsSharedCrossOrigin(), which is a method of v8::Message
. In other words, it is derived from the JS engine's representation of the thrown exception, in the same way that we are already hand-waving about for line number, column number, and URL.
Given that we have no interop on muting, and are pretty sure the current spec doesn't match our ideal (per long discussions in #958 and a few other issues like #3149) why are we trying to preserve the framework of it being derived from the script?
My suggestion is that we change the spec hand-wave on the muting. We can have it mention that the user agent will probably want to use, for classic scripts, the "muted errors" boolean. (And that for module scripts, there is no need to mute errors.) But we don't need to find a way to thread through the "right" script.
We can then change the algorithm to only take an exception and a global.
source
Outdated
<span>report an exception</span> with an <span>implementation-defined</span> value for | ||
<var>element</var>'s <span>relevant global object</span> and the <span>running | ||
script</span>.</p> <p class="XXX">Is this actually reported to that global in browsers? Or | ||
does it care about what realm/script called this.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, good catch, this seems worth removing IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
should be added.</p> | ||
|
||
<p>When the user agent is required to <dfn>report an exception</dfn> <var>exception</var>, which | ||
may be a JavaScript value or an <span>implementation-defined</span> value, for a particular |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allowing an implementation-defined value here that is somehow not a JavaScript object seems bad. I'll review the call sites where that escape hatch is used to see if we can get rid of it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cases are:
- non-parseable event handler strings (we just check whether they can be parsed, without actually throwing a real exception)
- multiple constraint validation failures (above, which is quite hand-wavy generally and I haven't yet tried to rig up a test page to see what browsers do in practice)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should remove multiple constraint validation failures, per https://software.hixie.ch/utilities/js/live-dom-viewer/?saved=12866 and https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/forms/listed_element.cc;l=557;drc=7b232da0f22e8cdf555d43c52b6491baeb87f729
For non-parseable event handler strings, I think based on http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=12864 what happens is that people invoke the parser and get an actual SyntaxError
object back. So I'd tweak it to something like
Attempt to parse body as a FunctionBody. If parsing fails or detects an early error, let error be a
SyntaxError
object representing that error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, slight correction on the constraint validation failures -- it's not that there are multiple, it's that the input isn't rendered. It seems that Chrome and Firefox do not log to the developer console in this case, but Safari does (though I haven't managed to get Safari to actually fire an error
event in this case, so it might not be going through the full reporting steps). It says: "An invalid form control with name='' is not focusable." (because these steps are used to display validity to the user, which of course isn't possible.
https://software.hixie.ch/utilities/js/live-dom-viewer/?saved=12883
Still, not having managed to find a case where an error
event is fired for constraint validation failure, we can probably remove that. I've just removed it altogether (since UAs can generally report whatever developer console messages they find appropriate), but we could amend it to discuss reporting an error to the developer console only if you'd like to keep it in some form.
may be a JavaScript value or an <span>implementation-defined</span> value, for a particular | ||
<span>global object</span> <var>global</var>, optional <span | ||
data-x="concept-script">script</span> <var>script</var>, and optional boolean | ||
<var>exposeError</var> (default true), it must run these steps:</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Booleans should default to false, per https://infra.spec.whatwg.org/#algorithm-params .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
<p class="note">Returning true in an event handler cancels the event per <span>the event handler | ||
processing algorithm</span>.</p> | ||
<p class="note">The actual <code data-x="">Error</code> will not be available in the owner |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<p class="note">The actual <code data-x="">Error</code> will not be available in the owner | |
<p class="note">The actual <var>exception</var> value will not be available in the owner |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
source
Outdated
|
||
<p w-nodev>The <span>task source</span> for the task mentioned above is the <span>DOM manipulation | ||
task source</span>.</p> | ||
<span w-dev>will</span> <span data-x="report an exception">report</span> it for the worker's |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can now become "will" for both editions, since the report algorithm takes care of the normative requirements.
Similarly, the last sentence is probably redundant with the normative requirements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, done. With those changes, this entire h4 section is infomative.
@@ -105462,6 +105475,9 @@ new PaymentRequest(…); // Allowed to use | |||
object">the environment settings object's global object</dfn>.</p></li> | |||
</ul> | |||
|
|||
<p>A <span>global object</span> has an <dfn for="global object">in error reporting mode</dfn> | |||
boolean, which is initially false.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the past we've avoided adding too many things to all global objects, instead putting them on #environment-settings-object
. (Like "outstanding rejected promises weak set".) I'm not sure that was a great decision though, so maybe what you've done here is reasonable too...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It felt more natural to have it here because you'd suggested the algorithm take the global object, not the environment settings object. But I don't feel strongly at all, so happy to do whatever makes editors happy.
source
Outdated
<li><p><span>Report an exception</span> given by <var>evaluationStatus</var>.[[Value]] for | ||
<var>script</var>'s <span data-x="concept-script-settings-object">settings object</span>'s | ||
<span data-x="concept-settings-object-global">global object</span> and <var>script</var>. | ||
</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No whitespace after .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the output of https://domenic.github.io/rewrapper/, and I'm not sure how to avoid it. Should <var>script</var>.
all wrap to the next line? Not wrapping at all puts this over the character limit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should
<var>script</var>.
all wrap to the next line?
Yep, that's the idea. If you collapse away the whitespace all into one line, that's what the rewrapper outputs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
source
Outdated
<li><p><span>Report an exception</span> given by <var>evaluationStatus</var>.[[Value]] for | ||
<var>script</var>'s <span data-x="concept-script-settings-object">settings object</span>'s | ||
<span data-x="concept-settings-object-global">global object</span> and <var>script</var>. | ||
</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It occurs to me that whenever you do have a script, you'll almost certainly want to use its global object. Maybe we should make the global object optional, and assert that either the global object or the script are provided?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure whether that's true, mostly because I'm not entirely sure where these script objects are being summoned from.
may be a JavaScript value or an <span>implementation-defined</span> value, for a particular | ||
<span>global object</span> <var>global</var>, optional <span | ||
data-x="concept-script">script</span> <var>script</var>, and optional boolean | ||
<var>exposeError</var> (default true), it must run these steps:</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use named parameter style for exposeError (and maybe the other two, especially if we go the route of making them both optional). You can see some examples of how to do that in HTML markup by searching for the following fragment:
<p>To <dfn>fire a traverse <code data-x="event-navigate">navigate</code> event</dfn> at a
<code>Navigation</code> <var>navigation</var> given a <span>session history entry</span> <dfn
data-x="fire-navigate-traverse-destinationSHE"><var>destinationSHE</var></dfn> and an optional
<span>user navigation involvement</span> <dfn
data-x="fire-navigate-traverse-userInvolvement"><var>userInvolvement</var></dfn> (default "<code
data-x="uni-none">none</code>"):</p>
and its call sites
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done for exposeError (now redactError).
source
Outdated
<span>associated realm</span>'s <span data-x="concept-realm-global">global object</span>.</p> | ||
|
||
<p w-nodev class="note">This global object not necessarily the same as <span>this</span>, if | ||
<var>callback</var> comes from another <span>realm</span>.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How did you determine which choice of global to use here? If you're sure you're right, then can we have a tracking issue to write web platform tests to confirm? If you're not sure, we might want to leave this as an XXX box.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lovely test page https://excited-jealous-saturn.glitch.me/ (and a few more pages under that glitch for other cases, like finalization registries and import maps).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
responded to most comments; will address editorial comments later
@@ -93696,7 +93709,7 @@ const p2 = navigation.navigate(url2).finished;</code></pre> | |||
data-x="dom-ErrorEvent-lineno">lineno</code>, and <code | |||
data-x="dom-ErrorEvent-colno">colno</code> initialized to <span class="XXX">appropriate values | |||
that can be extracted from <var>error</var> and the current JavaScript stack in the same | |||
underspecified way that the <span>report the exception</span> algorithm does</span>.</p> | |||
underspecified way that the <span>report an exception</span> algorithm does</span>.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, though as long as it's a total handwave is it helpful to do so? I'm kinda loathe to try to figure out what the inputs to the handwave are, which making an algorithm, even one that just says "implementation-defined 🤷", would seem to require.
@@ -105462,6 +105475,9 @@ new PaymentRequest(…); // Allowed to use | |||
object">the environment settings object's global object</dfn>.</p></li> | |||
</ul> | |||
|
|||
<p>A <span>global object</span> has an <dfn for="global object">in error reporting mode</dfn> | |||
boolean, which is initially false.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It felt more natural to have it here because you'd suggested the algorithm take the global object, not the environment settings object. But I don't feel strongly at all, so happy to do whatever makes editors happy.
source
Outdated
<li><p><span>Report an exception</span> given by <var>evaluationStatus</var>.[[Value]] for | ||
<var>script</var>'s <span data-x="concept-script-settings-object">settings object</span>'s | ||
<span data-x="concept-settings-object-global">global object</span> and <var>script</var>. | ||
</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the output of https://domenic.github.io/rewrapper/, and I'm not sure how to avoid it. Should <var>script</var>.
all wrap to the next line? Not wrapping at all puts this over the character limit.
exception">report</span> it for the associated <span | ||
data-x="concept-script">script</span>'s <span | ||
data-x="concept-script-settings-object">settings object</span>'s <span | ||
data-x="concept-settings-object-global">global object</span> and the associated <span |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was my instinct too, but I couldn't convince myself this was always equivalent (depending on what "the associated script", a term not defined, is). For example, the reaction callback could be from another realm, and that realm's global object might be what's used.
I checked several other sites to see what's used in practice, but I had not gotten to this one yet. I now have in Chrome and Firefox at least (Safari I'd have to go home or otherwise find a Mac, I think) -- they both seem to report, in practice, in the callback's realm, for callback reactions at least (see this test page), which is not element's relevant global object.
For upgrade reactions (test page), Chrome and Firefox diverge (and again, haven't checked Safari):
- if an exception is thrown during the ctor, Chrome fires the ctor's global's onerror but Firefox runs it on the script that we entered (the root, in the test page)
- the same is true of exceptions the spec requires the UA to throw (e.g., for returning an object other than the element being constructed from the ctor)
In no case is it necessarily element's relevant global object, at least as currently implemented in those browsers. Of course, probably nobody relies on this extreme fringe case in the field.
source
Outdated
<li><p><span>Report an exception</span> given by <var>evaluationStatus</var>.[[Value]] for | ||
<var>script</var>'s <span data-x="concept-script-settings-object">settings object</span>'s | ||
<span data-x="concept-settings-object-global">global object</span> and <var>script</var>. | ||
</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure whether that's true, mostly because I'm not entirely sure where these script objects are being summoned from.
should be added.</p> | ||
|
||
<p>When the user agent is required to <dfn>report an exception</dfn> <var>exception</var>, which | ||
may be a JavaScript value or an <span>implementation-defined</span> value, for a particular |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cases are:
- non-parseable event handler strings (we just check whether they can be parsed, without actually throwing a real exception)
- multiple constraint validation failures (above, which is quite hand-wavy generally and I haven't yet tried to rig up a test page to see what browsers do in practice)
source
Outdated
<span>associated realm</span>'s <span data-x="concept-realm-global">global object</span>.</p> | ||
|
||
<p w-nodev class="note">This global object not necessarily the same as <span>this</span>, if | ||
<var>callback</var> comes from another <span>realm</span>.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lovely test page https://excited-jealous-saturn.glitch.me/ (and a few more pages under that glitch for other cases, like finalization registries and import maps).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for working on this. Great to see some progress on this issue. I wanted to note that "report the exception" has many callers that we cannot break: https://dontcallmedom.github.io/webdex/r.html#report%20the%20exception%40%40html%25%25dfn
Continuing to export the term is probably the bare minimum we need to do. Follow-up issues/downstream PRs might also be needed?
source
Outdated
for <var>settings object</var>'s <span data-x="concept-settings-object-global">global object | ||
</span> and the appropriate <span data-x="concept-script">script</span>. The value reported |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
</span>
cannot have preceding whitespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
<span>report the exception</span>.</p></li> | ||
<span data-x="report an exception">report</span> it for <var>handler</var>'s | ||
corresponding JavaScript object's <span>associated realm</span>'s | ||
<span data-x="concept-realm-global">global object</span>.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I would expect <span
on the previous line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
I agree. Tracking followup PRs in the original issue makes sense to me once this PR is in a shape you are happy with. I had the task of doing that as an XXX in the original PR because I wasn't sure what the right wattsi syntax is. I'm still not sure I got it right, but |
Maintaining incoming ID references is no longer enough now HTML participates in Bikeshed's cross-referencing system. Once you drop a |
My plan was to break all of those so that they would notice and update to the new algorithm, which will have new inputs and possibly be used quite differently (e.g. if we do the automatic handling of Web IDL callbacks). That feels a bit better than having them call the new algorithm with the wrong arguments silently... |
Hmm. It's usually pretty frustrating when a build is broken, especially when fixing it is tricky, but also just because it might block landing other PRs. (Although I understand that outside the WHATWG folks typically don't have fatal builds, that's more of a problem worth fixing than something we should rely on I think.) |
This reverts commit 86beb6d.
The alternative might be to expose "stub" dfns, rewrite the uses indexed by webdex, and then convert them into mere anchors? |
Right yeah, I'm not opposed to that at all. I'd just like to avoid build time errors for people trying to fix something else in their specification unrelated to this. |
This algorithm directly includes the error propagation and fallback behavior, and requires callers to supply the global scope to be used, rather than magically inferring it.
Call sites within HTML are replaced, but there is more work yet to be done.
(See WHATWG Working Mode: Changes for more details.)
The following call sites are changed (unchecked ones merit some extra attention):
error
events in this case, though Safari does log to the developer console.reportError()
: The global it's called on is used, contrary to that not being plumbed in previously but aligned with what one would expect.type="importmap"
script can be synchronously added by other script ought to be reported to that global but is still reported to the relevant global of the script element and its document, which is the same one the register algorithm is being run for.finalizationRegistry.[[CleanupCallback]].[[Callback]].[[Realm]]
doesn't seem to be used in either Chrome or Firefox (contrary to how timers work), and this can differ fromfinalizationRegistry.[[Realm]]
if the function passed was created in a different realm than the registry itself.setTimeout
andsetInterval
, it's always going to be the global scope that it was called on, since that's where it's evaluated.I also need to:
/custom-elements.html ( diff )
/form-control-infrastructure.html ( diff )
/imagebitmap-and-animations.html ( diff )
/infrastructure.html ( diff )
/nav-history-apis.html ( diff )
/parsing.html ( diff )
/timers-and-user-prompts.html ( diff )
/webappapis.html ( diff )
/workers.html ( diff )