There's more to it than just having
[[ConstructorKind]]. There's also the need to emit one of 2 different constructors in accordance with that kind, the tracking of the association between
super and the parent constructor, etc... There's a lot of moving parts. However, if you look at 14.6.13 step 5 & 6.e, you see that there is always a need to track the parent constructor, even if it's specified
extends null, or not at all.
Given that, first eliminate the "not at all" case by re-spelling it as
extends Object explicitly when its not specified. This is almost identical to what is currently done except that the "not at all" case does something pointlessly special here by setting the
[[ConstructorKind]] to "base" and forcing the emission of a
super()-less constructor. This leaves
extends null as the only special case.
Since step 6.e.ii prescribes that for this last case, the constructorParent is
%FunctionPrototype%, there's always a function for
super() to call. The only problem is that
%FunctionPrototype% doesn't have a
[[Construct]]. This is where
super gets modified. If
super were instead an internal function with this kind of behavior, the problem would be solved for all cases.
- Let envRec be GetThisEnvironment().
- Assert: envRec is a function Environment Record.
- Let activeFunction be envRec.[[FunctionObject]].
- Assert: activeFunction is an ECMAScript function object.
- Let superConstructor be ! activeFunction.[[GetPrototypeOf]]().
- If superConstructor is %FunctionPrototype% then
a. Let retval be an new ECMAScript Object instance.
b. Let retval.[[Prototype]] be null.
c. Return retval.
- Else if IsConstructor(superConstructor) is false, throw a TypeError exception.
- Return ! superConstructor().
Notice that this is only a little more than what
GetSuperConstructor already does. The only thing left to tidy up is the pesky determination of whether or not
super() is required in user-defined constructors, but that's easy. Just check to see if
_superConstructor_ is not
_superConstructor_.prototype is an ECMAScript Object. If this is true, then require super, otherwise don't.
A bit wordy to be sure, but this get's rid of the null problem for classes and private fields, gets rid of the need to use
super even for explicit cases of
extends Object (which never made any sense anyway), reduces slot usage, and gets rid of the need to have 2 default constructors based on whether or not there is an
extends clause in the ClassHeritage.
What do you think?