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

Can [[Call]] return an abrupt completion with [[Type]] = continue|break|return? #1537

Closed
jmdyck opened this issue May 13, 2019 · 7 comments · Fixed by #1539
Closed

Can [[Call]] return an abrupt completion with [[Type]] = continue|break|return? #1537

jmdyck opened this issue May 13, 2019 · 7 comments · Fixed by #1539
Labels

Comments

@jmdyck
Copy link
Collaborator

jmdyck commented May 13, 2019

Is it allowed for the [[Call]] internal method of a function object to return an abrupt completion whose [[Type]] is continue, break, or return? (I'm pretty sure that no [[Call]] algorithm defined in the spec has this behavior, so it would have to be an implementation-defined function.)

Allowing it would mean that a function-call could have the same effect as a continue, break, or return statement, which seems undesirable.

However, I can't find anywhere that it's disallowed. In fact, both 6.1.7.2 Object Internal Methods and Internal Slots and 6.1.7.3 Invariants of the Essential Internal Methods are remarkably quiet about the possibility of any internal method returning an abrupt completion (even though it's clear elsewhere that they all can).

@ljharb
Copy link
Member

ljharb commented May 13, 2019

https://tc39.github.io/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist seems to indicate that the result type can either be "return", which produces a NormalCompletion, "abrupt", in which case the abrupt completion is produced, or else the completion record's [[Value]] is extracted and wrapped in a NormalCompletion.

So, even if break or continue completion types were allowed, the result would either be abrupt or normal.


Separately, it also kind of seems like the various EvaluateBody steps:

@jmdyck
Copy link
Collaborator Author

jmdyck commented May 13, 2019

[9.2.1] seems to indicate that the result type can either be "return", which produces a NormalCompletion, "abrupt", in which case the abrupt completion is produced, or else the completion record's [[Value]] is extracted and wrapped in a NormalCompletion.

So, even if break or continue completion types were allowed, the result would either be abrupt or normal.

Not sure what you're saying. break and continue are abrupt, so if _result_ managed to be a completion with [[Type]] = break or continue, that's what [[Call]] would return.

Separately, it also kind of seems like the various EvaluateBody steps:
[...]
all explicitly indicate a type of "return" or "abrupt"?

[[Type]] = return is abrupt, so saying "return or abrupt" doesn't make sense. And (as above) abrupt includes break and continue, so it's not clear to me if you're saying that they are allowed or aren't.

I think, as long as you only deal with ordinary objects (and spec-defined exotics), the only abrupt completions that any internal method can return are throw completions. But once you add implementation-defined exotics to the mix, all bets appear to be off, as there's no restriction on what abrupt completions they can return.

@ljharb
Copy link
Member

ljharb commented May 13, 2019

cc @allenwb for background.

It seems reasonable to explicitly restrict that, unless there’s a reason not to.

@allenwb
Copy link
Member

allenwb commented May 13, 2019

break and continue statements are the only things in the specification that generate [[Type]]=break|continue completion records. Early error restrictions prevent them from syntactically occurring in any context where their completion values could be returned from a function call.

See, for example:
https://tc39.github.io/ecma262/#sec-continue-statement-static-semantics-early-errors
https://tc39.github.io/ecma262/#sec-break-statement-static-semantics-early-errors
https://tc39.github.io/ecma262/#sec-function-definitions-static-semantics-early-errors
(early errors for FunctionBody : FunctionStatementList)
https://tc39.github.io/ecma262/#sec-scripts-static-semantics-early-errors
(early errors for ScriptBody : StatementList)
https://tc39.github.io/ecma262/#sec-module-semantics-static-semantics-early-errors

Because of these early errors, a break or continue abrupt completion can never reach https://tc39.github.io/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist so it doesn't have to deal with it.

Remember that this document is only a specification, not an implementation of an extensible virtual machine. As a specification it must be internally consistent but only needs to deal with what is actually allowed by other parts of the specification. Adding normative steps to deal with things that are not otherwise specified would just complicate the specification and place unnecessary normative requirements on implementations.

Note that if a new feature (eg, do expressions) was added that allowed break/continue statements to used in new context then the specification of that feature would also need to either provide additional early error rules or runtime errors to ensure that break/continue abrupt completions did not escape from function bodies. Or they would need to define the full semantics of break/continue propagation across function calls (this is non-trivial. It's sometime I extensively explored for the "Block Lambda" proposals. Based upon that I don't recommend every adding it to the language).

Regarding, implementation defined exotic functions. The spec. does not defined an general extension point for them other than https://tc39.github.io/ecma262/#sec-built-in-function-objects-call-thisargument-argumentslist which is only mandatory for implementation defined exotic functions that correspond to a "built function" . Step 10 of 9.3.1 should probably be elaborated to state that the evaluation of F must not be a break/continue/return abrupt completion. To cover the more general issue of implementation defined exotic functions we might add an similar essential invariant for [[Call]] in https://tc39.github.io/ecma262/#sec-invariants-of-the-essential-internal-methods

@ljharb
Copy link
Member

ljharb commented May 13, 2019

Perhaps a non normative note that break/continue can’t be produced from a function call?

@allenwb
Copy link
Member

allenwb commented May 13, 2019

Yes, almost suggested that. But it isn't clear where you would put that note. Really applies to the early errors for FunctionBody, ScriptBody, and ModuleBody rather than BreakStatement and ContinueStatement.

For those who are concerned about exotic implementation defined functions I think adding the [[Call]] invariant is what we should do.

@jmdyck
Copy link
Collaborator Author

jmdyck commented May 13, 2019

As a specification it must be internally consistent but only needs to deal with what is actually allowed by other parts of the specification.

Indeed. This is a question about what's allowed.

Adding normative steps to deal with things that are not otherwise specified would just complicate the specification and place unnecessary normative requirements on implementations.

Not quite sure what you're responding to there: I don't think anyone was proposing to add normative steps.

Regarding, implementation defined exotic functions. The spec. does not defined an general extension point for them other than [9.3.1] which is only mandatory for implementation defined exotic functions that correspond to a "built function" .

Right, so it doesn't apply to implementation-defined exotic functions that aren't built-ins.

Step 10 of 9.3.1 should probably be elaborated to state that the evaluation of F must not be a break/continue/return abrupt completion.

On the other hand, if we add the invariant, we don't have to elaborate, since the evaluation of F goes to result, which is what gets returned by the algorithm, which would thus be subject to the invarant.

To cover the more general issue of implementation defined exotic functions we might add an similar essential invariant for [[Call]] in https://tc39.github.io/ecma262/#sec-invariants-of-the-essential-internal-methods

Okay, so it sounds like the answer to my original question is that, while it's disallowed 'by construction' in the common cases, it's not currently disallowed in general, but should be.

For those who are concerned about exotic implementation defined functions I think adding the [[Call]] invariant is what we should do.

I'll propose some text.

jmdyck added a commit to jmdyck/ecma262 that referenced this issue May 13, 2019
I.e., disallow internal methods from returning abrupt completions
with [[Type]] = continue or break or return.

Somewhat casually in 6.1.7.2, and then more formally in 6.1.7.3.

Resolves tc39#1537.
ljharb pushed a commit to jmdyck/ecma262 that referenced this issue Aug 7, 2019
…c39#1539)

I.e., disallow internal methods from returning abrupt completions with [[Type]] = continue or break or return.

Somewhat casually in 6.1.7.2, and then more formally in 6.1.7.3.

Resolves tc39#1537.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants