Skip to content
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

Merged
merged 1 commit into from
Nov 3, 2016

Conversation

tobie
Copy link
Collaborator

@tobie tobie commented Oct 25, 2016


<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
Copy link
Member

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|".

Copy link
Collaborator Author

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.

Copy link
Member

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.

Copy link
Collaborator Author

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

Copy link
Member

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.

Copy link
Member

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.

Copy link
Collaborator Author

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?

Copy link
Member

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.

Copy link
Collaborator Author

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?

Copy link
Member

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|.
Copy link
Member

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."

Copy link
Collaborator Author

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|

Copy link
Collaborator Author

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
Copy link
Member

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|.
Copy link
Collaborator

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?

Copy link
Member

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.

Copy link
Collaborator Author

@tobie tobie Oct 25, 2016

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).

Copy link
Member

@domenic domenic left a 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,
Copy link
Member

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|.
Copy link
Member

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.

Copy link
Collaborator Author

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?

Copy link
Member

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.

Copy link
Collaborator Author

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.

Copy link
Member

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.

Copy link
Collaborator Author

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.
Copy link
Member

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.

Copy link
Member

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.

Copy link
Collaborator Author

@tobie tobie Nov 3, 2016

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?

Copy link
Member

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.

Copy link
Collaborator Author

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?

Copy link
Member

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.

Copy link
Collaborator Author

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

Copy link
Collaborator

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.

@tobie tobie merged commit 001ba52 into whatwg:gh-pages Nov 3, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants