Skip to content
This repository was archived by the owner on Jan 25, 2022. It is now read-only.

Commit 11a92e5

Browse files
committed
Normative: Support inherited private static methods
- Spec supports static public fields, static private fields and static private methods. - Static private methods can be called with subclasses as the receiver. This logic is based on copying all private methods and accessors from the superclass to the subclass, as documented in the explainer.
1 parent 2cd1e68 commit 11a92e5

File tree

1 file changed

+51
-68
lines changed

1 file changed

+51
-68
lines changed

spec.html

+51-68
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
<emu-intro id=sec-intro>
1212
<h1>Introduction</h1>
1313
<p>This document specifies parts of the class features proposals which were split off in the November 2017 TC39 meeting from <a href="https://github.com/tc39/proposal-class-fields">class fields</a> and <a href="https://github.com/tc39/proposal-private-methods">private methods</a> proposals, for further consideration and advancement. In that meeting, static public fields, static private fields and static private methods were split off from the earlier "Stage 3" proposal and demoted to "Stage 2".</p>
14-
<p>This proposal defines only static public fields. Static private fields and static private methods are omitted, with rationale documented <a href="https://github.com/tc39/proposal-static-class-features/issues/1">in this bug</a>. This specification text maintains the previously proposed semantics that each static public field is created just once, on the class it is defined, and not additional times for each subclass, as motivated <a href="https://github.com/tc39/proposal-static-class-features/issues/2">in this bug</a>. For further context and motivation, see <a href="https://github.com/tc39/proposal-static-class-features">the explainer document</a> for this proposal.</p>
14+
<p>This proposal defines static public fields, static private fields, and static private methods. Compared to past proposals, the semantics of private static methods have changed to allow the receiver of a private static method to be a subclass. For further context and motivation, see <a href="https://github.com/tc39/proposal-static-class-features">the explainer document</a>.</p>
15+
<p>This specification is phrased as a diff against the combination of the private methods and class fields proposals.</p>
1516
</emu-intro>
1617

1718
<emu-clause id=sec-syntax>
@@ -28,73 +29,61 @@ <h1>Syntax</h1>
2829

2930
<emu-clause id="sec-static-semantics-early-errors">
3031
<h1>Static Semantics: Early Errors</h1>
31-
<emu-grammar>ClassElement : `static` FieldDefinition `;`</emu-grammar>
32+
<emu-grammar><ins>ClassElement : `static` FieldDefinition `;`</ins></emu-grammar>
3233
<ul>
3334
<li>
34-
It is a Syntax Error if PropName of |FieldDefinition| is `"prototype"` or `"constructor"`.
35+
<ins>It is a Syntax Error if PropName of |FieldDefinition| is `"prototype"` or `"constructor"`.</ins>
3536
</li>
3637
</ul>
38+
39+
<emu-grammar>
40+
<del>ClassElement : `static` MethodDefinition</del>
41+
</emu-grammar>
42+
<ul>
43+
<li><del>It is a Syntax Error if PrivateBoundNames of |MethodDefinition| is non-empty.</del></li>
44+
</ul>
3745
</emu-clause>
3846

3947
</emu-clause>
4048

4149
<emu-clause id=sec-algorithms>
4250
<h1>Algorithms</h1>
4351

44-
<h1>Runtime Semantics: ClassElementEvaluation</h1>
45-
<p>With parameters _object_ and _enumerable_.</p>
46-
47-
<emu-grammar><ins>ClassElement : `static` FieldDefinition `;`</ins></emu-grammar>
48-
<emu-alg>
49-
<ins>1. Return ClassFieldDefinitionEvaluation of |FieldDefinition| with parameter *true* and _object_.</ins>
50-
</emu-alg>
51-
52-
<emu-grammar>ClassElement : FieldDefinition `;`</emu-grammar>
53-
<emu-alg>
54-
1. Return ClassFieldDefinitionEvaluation of |FieldDefinition| with parameter <ins>*false* and</ins> _object_.
55-
</emu-alg>
56-
57-
<emu-clause id="runtime-semantics-class-field-definition-evaluation">
58-
<h1>Runtime Semantics: ClassFieldDefinitionEvaluation</h1>
52+
<emu-clause id="initialize-class-elements" aoid="InitializeClassElements">
53+
<h1>InitializeClassElements(_F_, _proto_)</h1>
5954

60-
<p>With parameters <ins>_isStatic_ and</ins> _homeObject_.</p>
61-
62-
<emu-grammar>
63-
FieldDefinition : ClassElementName Initializer?
64-
</emu-grammar>
6555
<emu-alg>
66-
1. Let _fieldName_ be the result of evaluating |ClassElementName|.
67-
1. ReturnIfAbrupt(_fieldName_).
68-
1. If |Initializer_opt| is present,
69-
1. Let _lex_ be the Lexical Environment of the running execution context.
70-
1. Let _formalParameterList_ be an instance of the production <emu-grammar>FormalParameters : [empty]</emu-grammar>.
71-
1. Let _initializer_ be FunctionCreate(~Method~, _formalParameterList_, |Initializer|, _lex_, *true*).
72-
1. Perform MakeMethod(_initializer_, _homeObject_).
73-
1. Let _isAnonymousFunctionDefinition_ be IsAnonymousFunctionDefinition(|Initializer|).
74-
1. Else,
75-
1. Let _initializer_ be ~empty~.
76-
1. Let _isAnonymousFunctionDeclaration_ be *false*.
77-
1. Return a List containing Record {
78-
[[Name]]: _fieldName_,
79-
[[Initializer]]: _initializer_,
80-
<ins>[[Static]]: _isStatic_,</ins>
81-
[[IsAnonymousFunctionDefinition]]: _isAnonymousFunctionDefinition_
82-
}.
56+
1. Assert: Type(_F_) is Object and Type(_proto_) is Object.
57+
1. Assert: _F_ is an ECMAScript function object.
58+
1. Assert: _proto_ is ! Get(_C_, `"prototype"`).
59+
1. Let _elements_ be the value of _F_'s [[Elements]] internal slot.
60+
1. For each item _element_ in order from _elements_,
61+
1. Assert: If _element_.[[Placement]] is `"prototype"` <del>or `"static"`</del>, then _element_.[[Key]] is not a Private Name.
62+
1. If _element_.[[Kind]] is `"method"`,
63+
1. Let _receiver_ be _F_ if _element_.[[Placement]] is `"static"`, else let _receiver_ be _proto_.
64+
1. Perform ? DefineClassElement(_receiver_, _element_).
65+
1. For each item _element_ in order from _elements_,
66+
1. If _element_.[[Kind]] is `"field"` and _element_.[[Placement]] is `"static"` or `"prototype"`,
67+
1. Assert: _element_.[[Descriptor]] does not have a [[Value]], [[Get]] or [[Set]] slot.
68+
1. Let _receiver_ be _F_ if _element_.[[Placement]] is `"static"`, else let _receiver_ be _proto_.
69+
1. Perform ? DefineClassElement(_receiver_, _element_).
70+
1. Return.
8371
</emu-alg>
72+
<emu-note type=editor>Value properties are added before initializers so that all methods are visible from all initializers</emu-note>
8473
</emu-clause>
8574

86-
<emu-clause id="initialize-public-static-fields">
87-
<h1>InitializeStaticFields(_F_)</h1>
75+
<emu-clause id="copy-immutable-private-elements" aoid=CopyImmutablePrivateElements>
76+
<h1>CopyImmutablePrivateElements ( _F_, _constructorProto_ )</h1>
8877

8978
<emu-alg>
90-
1. Assert: Type(_F_) is Object.
91-
1. Assert: _F_ is an ECMAScript function object.
92-
1. Let _fieldRecords_ be the value of _F_'s [[Fields]] internal slot.
93-
1. For each item _fieldRecord_ in order from _fieldRecords_,
94-
1. If _fieldRecord_.[[Static]] is *true*, then
95-
1. Perform ? DefineField(_F_, _fieldRecord_).
96-
1. Return.
79+
1. For _entry_ in _constructorProto_.[[PrivateFieldDescriptors]],
80+
1. Let _name_ be _entry_.[[PrivateName]].
81+
1. Let _descriptor_ be _entry_.[[PrivateFieldDescriptor]].
82+
1. If IsAccessorDescriptor(_descriptor_) or _descriptor_.[[Writable]] is *false*,
83+
1. Perform ! PrivateFieldDefine(_name_, _F_, _descriptor_).
9784
</emu-alg>
85+
86+
<emu-note>In this specification, the only elements which will be copied by this algorithm are static private methods and accessors.</emu-note>
9887
</emu-clause>
9988

10089
<emu-clause id="initialize-public-instance-fields">
@@ -140,7 +129,6 @@ <h1>Runtime Semantics: ClassDefinitionEvaluation</h1>
140129
1. Let _constructorParent_ be the intrinsic object %FunctionPrototype%.
141130
1. Else,
142131
1. Set the running execution context's LexicalEnvironment to _classScope_.
143-
1. NOTE: The running execution context's PrivateNameEnvironment is _outerPrivateEnvironment_ when evaluating |ClassHeritage|.
144132
1. Let _superclass_ be the result of evaluating |ClassHeritage|.
145133
1. Set the running execution context's LexicalEnvironment to _lex_.
146134
1. ReturnIfAbrupt(_superclass_).
@@ -173,32 +161,27 @@ <h1>Runtime Semantics: ClassDefinitionEvaluation</h1>
173161
1. Perform MakeConstructor(_F_, *false*, _proto_).
174162
1. Perform MakeClassConstructor(_F_).
175163
1. Perform CreateMethodProperty(_proto_, `"constructor"`, _F_).
176-
1. If |ClassBody_opt| is not present, let _methods_ be a new empty List.
177-
1. Else, let _elements_ be NonConstructorMethodDefinitions of |ClassBody|.
178-
1. Let _fieldRecords_ be a new empty List.
179-
1. For each |ClassElement| _e_ in order from _elements_
180-
1. If IsStatic of _e_ is *false*, then
181-
1. Let _fields_ be the result of performing ClassElementEvaluation for _e_ with arguments _proto_ and *false*.
182-
1. Else,
183-
1. Let _fields_ be the result of performing ClassElementEvaluation for _e_ with arguments _F_ and *false*.
184-
1. If _fields_ is an abrupt completion, then
164+
1. If |ClassBody_opt| is not present, let _elements_ be a new empty List.
165+
1. Else, let _definitions_ be NonConstructorElementDefinitions of |ClassBody|. NOTE: Simply renaming this internal algorithm will be enough; it includes fields.
166+
1. Let _elements_ be a new empty List.
167+
1. For each |ClassElement| _d_ in order from _definitions_,
168+
1. Let _newElements_ be the result of performing ClassElementEvaluation for _d_ with arguments _F_, *false*, and ~empty~.
169+
1. If _newElements_ is an abrupt completion, then
185170
1. Set the running execution context's LexicalEnvironment to _lex_.
186171
1. Set the running execution context's PrivateNameEnvironment to _outerPrivateEnvironment_.
187172
1. Return Completion(_status_).
188-
1. Append to _fieldRecords_ the elements of _fields_.
173+
1. Append _newElements_ to _elements_
174+
1. Let _elements_ be CoalescePrivateAccessors(_elements_).
189175
1. Set the running execution context's LexicalEnvironment to _lex_.
176+
1. Set the running execution context's PrivateNameEnvironment to _outerPrivateEnvironment_.
190177
1. If _className_ is not *undefined*, then
191178
1. Perform _classScopeEnvRec_.InitializeBinding(_className_, _F_).
192-
1. Set the value of _F_'s [[Fields]] internal slot to _fieldRecords_.
193-
1. Set the running execution context's LexicalEnvironment to _classScope_.
194-
1. Set the running execution context's PrivateNameEnvironment to _outerPrivateEnvironment_.
195-
1. <ins>Let _result_ be InitializeStaticFields(_F_).</ins>
196-
1. <ins>If _result_ is an abrupt completion, then</ins>
197-
1. <ins>Set the running execution context's LexicalEnvironment to _lex_.</ins>
198-
1. <ins>Return Completion(_result_).</ins>
199-
1. Set the running execution context's LexicalEnvironment to _lex_.
179+
1. Set the value of _F_'s [[Elements]] internal slot to _elements_.
180+
1. <ins>Perform ! CopyImmutablePrivateElements(_F_, _constructorParent_).</ins>
181+
1. Perform ? InitializeClassElements(_F_, _proto_).
200182
1. Return _F_.
201183
</emu-alg>
202184
</emu-clause>
203185

186+
204187
</emu-clause>

0 commit comments

Comments
 (0)