archives

« Bugzilla Issues Index

#3684 — 9.2.3 [[Construct]], step 14: Handle explicit return with no value for derived constructor


If I follow the algorithms correctly, when the body of a derived constructor is terminated with a bare `return` (without value), a TypeError is thrown at step 14.c, instead of returning the this-binding.

A step should added before that step (imitating step 16):

14.c If kind is "derived" and result.[[value]] is undefined, return the result of calling the GetThisBinding concrete method of.envRec’s with no arguments.


(hum...)

... the GetThisBinding concrete method of envRec with no arguments.

(also to be corrected in step 16)


The proposed change and tail-call semantics may not play along nicely. If OrdinaryCallEvaluateBody returns from a tail-call, calleeContext is no longer the current execution context and any resource tied to calleeContext has been released (or reused) [14.6.3 PrepareForTailCall]. I'd say the environment record is a resource which is tied to an execution context and therefore it's not valid to access `envRec` in step 14.


(In reply to André Bargull from comment #2)
> The proposed change and tail-call semantics may not play along nicely.

Yes, you're right: it will break in case of:

return functionThatReturnsUndefined()

So, here is another solution I've thought of: It consists of redefining the semantics of:

ReturnStatement : return ;

(in section 13.9.1 The Return Statement / Runtime semantics), so that `return;` becomes equivalent to `return this;` when we are running a constructor.

Concretely, the runtime semantics of `return;` would be approximately modified as follows:

1. Let envRec be the environment record of the current execution context's VariableEnvironment (if any).
2. If envRec.[[NewTarget]] is not null,
a. Let result be envRec.GetThisBinding().
b. ReturnIfAbrupt(result).
c. Return Completion{[[type]]: return, [[value]]: result, [[target]]: empty}.
3. Return Completion{[[type]]: return, [[value]]: undefined, [[target]]: empty}.


I think what this really is pointing out is that you can't do a tail call from a [[Construct]] invocation because there is always constructor specific processing that needs to be done after returning from the call in the return statement.

This was true, even before the recent changes. The real bug is that the spec. was allowing such tail calls.


fixed in rev33 editor's draft

fixed the return undefined base for derived constructors

new and super() expressions are no longer tail calls.


fixed in rev33