-
Notifications
You must be signed in to change notification settings - Fork 158
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
Throw when not calling interfaces as constructors #205
Conversation
|
||
<ol class="algorithm"> | ||
1. If |I| was not declared with a [{{Constructor}}] | ||
[=extended attribute=], then | ||
<a lt="es throw">throw a <emu-val>TypeError</emu-val></a>. | ||
1. If |newTarget| is <emu-val>undefined</emu-val>, then |
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.
ES notation is just "NewTarget", not "|newTarget|".
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.
Well, it gets passed to the algorithm, no? So that's just its local name.
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. I guess just remove that "and |newTarget| as the NewTarget value" to conform to ES functions.
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.
Wouldn't that just turn NewTarget into a free variable though?
Seems the ES spec treats it as a local variable in some place, e.g.: https://tc39.github.io/ecma262/#sec-construct
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 don't understand the advice from @domenic. It seems ES also always introduces it as a variable of an operation in the prose preceding the steps.
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.
Inside built-in function definitions (which this is one of), NewTarget is an ambient value, like "this value" is.
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.
Oh, indeed, in section 17:
In the description of a particular function, the terms “this value” and “NewTarget” have the meanings given in 9.3.
Should we maybe link the term to section 9.3?
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.
Personally I've been holding out for tc39/ecma262#529, but it wouldn't hurt I guess to link to that section for now.
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 tc39/ecma262#529 (comment), @allenwb writes:
"NewTarget" and "this value" should only be used in the top-level algorithms that defined built-ins. They should not be used in other abstract operations (because paragraph 3 of 9.3 doesn't generally apply to abstract operations). If an abstract operation that is used to factor the definition of one or more built-ins need to access those values they should be explicitly passed as parameters to the abstract operation (for example see https://tc39.github.io/ecma262/#sec-regexpalloc).
Aren't we in the case described by that last sentence, here?
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. This is a top-level algorithm defining a built-in (namely, the built-in constructor for all platform objects).
returns normally, then it must | ||
return an object that implements interface |I|. | ||
If evaluating the [=function object=] |F| returns normally, | ||
then it must return an object that implements interface |I|. |
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.
Hmm. This requirement is a little strange, both before and after. I think what it is trying to say is instead "If the actions listed in the description of constructor return normally, then they must return an object that implements interface I."
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.
Oh! Are you saying the before-last step of the above algorithm should be something like this:
1. Assert |R| is an object that implements |I|
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.
Added that as an Assert:
statement, which might be totally dumb. LMK.
|arg|<sub>0..|n|−1</sub> is the list | ||
of argument values passed to the constructor, and |I| | ||
is the [=interface=]: | ||
Interfaces that do not have a constructor will throw |
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.
Maybe "interfaces that are not declared with a [Constructor] extended attribute will throw when called, both as a function and as a constructor."
This object also must be | ||
associated with the ECMAScript global environment associated | ||
with the interface object. | ||
with |I|. |
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 isn't right. I
is an interface. It has no global environment associated with it. Do you mean the global environment associated with F
?
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 guess maybe just fix #206 at the same time.
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.
Bundled that up as an Assert:
statement. You might have had something completely different in mind—LMK.
Also unsure if said assert should operate on |R|
or on the result of converting |R|
to ES (last step of the algo).
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 like the asserts. Just minor things left.
|arg|<sub>0..|n|−1</sub> is the list | ||
of argument values passed to the constructor, and |I| | ||
is the [=interface=]: | ||
Interfaces that are not declared with a [Constructor] extended attribute will throw when called, |
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.
Link [{{Constructor}}]
@@ -10361,19 +10363,12 @@ is the [=interface=]: | |||
[=overload resolution algorithm=]. | |||
1. Let |R| be the result of performing the actions listed in the description of | |||
|constructor| with |values| as the argument values. | |||
1. Assert: |R| is an object that implements |I|. |
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.
Hmm. I think at this point |R| is a completion value, so this doesn't quite work. You'll want to add a step before the asserts that simply says "ReturnIfAbrupt(R)."
For further clarity, maybe add ", as a [=completion value=]" to the "Let R be the result..." step.
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.
There's something I don't quite understand here. If |R| is a completion value, then |R|.[[Value]] is an ECMAScript language value. If so, why do we "convert |R| to an ECMAScript interface type value |I|" in the the last step of the algorithm?
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.
R is something that's not concretely defined since we don't have requirements for what IDL-prose can and cannot be. I agree that it cannot really be a completion value, but I also agree with @domenic that it can have thrown an exception (constructors do this) and we do need to handle that somehow.
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 guess we just need to handle this in prose, then.
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.
Good point, yeah. Instead maybe let's add "Rethrow any exceptions." to the previous step.
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.
Reorganized some of these last steps. LMK if it makes sense.
@@ -10316,18 +10318,14 @@ an exception when called as a function. | |||
[=overload resolution algorithm=]. | |||
1. Let |R| be the result of performing the actions listed in the description of | |||
|constructor| with |values| as the argument values. | |||
1. Return the result of [=converted to an ECMAScript value|converting=] | |||
1. Rethrow any [=exception=] thrown in the previous step. |
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 don't think this is a Web IDL exception, so the linking here seems bad.
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.
Also, I think we should inline this into the previous step. It's a single atomic operation; we're just stating explicitly what to do if any exceptions occur.
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.
Can't constructors throw IDL errors like SecurityError
?
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, but they can also throw anything else.
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.
Don't simple exceptions englobe all of the ES errors that can be thrown at runtime?
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.
You can throw anything. E.g., throw 2
. Not sure if a constructor ever does that, but it might with custom elements I suppose.
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 have no words. o_O
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.
Not sure if a constructor ever does that
It doesn't even have to be the constructor itself. For example, step 4 (invoking the overload resolution algorithm) can trigger arbitrary page-provided code which can throw whatever the page wants. In general, so can step 5, if the constructor takes an object
argument and pokes at it in any way.
Fixes #62.
Fixes https://www.w3.org/Bugs/Public/show_bug.cgi?id=22808.
Preview | Diff w/ current ED | Diff w/ base