From 51e28c71cea1c73e3f22a007a058ebbf5ebc06aa Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 8 Sep 2021 15:17:26 -0700 Subject: [PATCH] Normative: add class `static` initialization blocks (#2440) --- spec.html | 234 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 213 insertions(+), 21 deletions(-) diff --git a/spec.html b/spec.html index 0aeafd9b38..c012dc5efd 100644 --- a/spec.html +++ b/spec.html @@ -4569,6 +4569,40 @@

The ClassFieldDefinition Record Specification Type

Private Names

The Private Name specification type is used to describe a globally unique value (one which differs from any other Private Name, even if they are otherwise indistinguishable) which represents the key of a private class element (field, method, or accessor). Each Private Name has an associated immutable [[Description]] which is a String value. A Private Name may be installed on any ECMAScript object with PrivateFieldAdd or PrivateMethodOrAccessorAdd, and then read or written using PrivateGet and PrivateSet.

+ + +

The ClassStaticBlockDefinition Record Specification Type

+

A ClassStaticBlockDefinition Record is a Record value used to encapsulate the executable code for a class static initialization block.

+

ClassStaticBlockDefinition Records have the fields listed in .

+ + + + + + + + + + + + + + +
+ Field Name + + Value + + Meaning +
+ [[BodyFunction]] + + An function object. + + The function object to be called during static initialization of a class. +
+
+
@@ -7339,6 +7373,14 @@

Static Semantics: LexicallyDeclaredNames

1. Return TopLevelLexicallyDeclaredNames of |StatementList|. + ClassStaticBlockStatementList : [empty] + + 1. Return a new empty List. + + ClassStaticBlockStatementList : StatementList + + 1. Return the TopLevelLexicallyDeclaredNames of |StatementList|. + ConciseBody : ExpressionBody 1. Return a new empty List. @@ -7449,6 +7491,14 @@

Static Semantics: LexicallyScopedDeclarations

1. Return the TopLevelLexicallyScopedDeclarations of |StatementList|. + ClassStaticBlockStatementList : [empty] + + 1. Return a new empty List. + + ClassStaticBlockStatementList : StatementList + + 1. Return the TopLevelLexicallyScopedDeclarations of |StatementList|. + ConciseBody : ExpressionBody 1. Return a new empty List. @@ -7671,6 +7721,14 @@

Static Semantics: VarDeclaredNames

1. Return TopLevelVarDeclaredNames of |StatementList|. + ClassStaticBlockStatementList : [empty] + + 1. Return a new empty List. + + ClassStaticBlockStatementList : StatementList + + 1. Return the TopLevelVarDeclaredNames of |StatementList|. + ConciseBody : ExpressionBody 1. Return a new empty List. @@ -7878,6 +7936,14 @@

Static Semantics: VarScopedDeclarations

1. Return the TopLevelVarScopedDeclarations of |StatementList|. + ClassStaticBlockStatementList : [empty] + + 1. Return a new empty List. + + ClassStaticBlockStatementList : StatementList + + 1. Return the TopLevelVarScopedDeclarations of |StatementList|. + ConciseBody : ExpressionBody 1. Return a new empty List. @@ -8197,6 +8263,10 @@

Static Semantics: ContainsDuplicateLabels

1. Return *false*. + ClassStaticBlockStatementList : [empty] + + 1. Return *false*. + ModuleItemList : ModuleItemList ModuleItem 1. Let _hasDuplicates_ be ContainsDuplicateLabels of |ModuleItemList| with argument _labelSet_. @@ -8365,6 +8435,10 @@

Static Semantics: ContainsUndefinedBreakTarget

1. Return *false*. + ClassStaticBlockStatementList : [empty] + + 1. Return *false*. + ModuleItemList : ModuleItemList ModuleItem 1. Let _hasUndefinedLabels_ be ContainsUndefinedBreakTarget of |ModuleItemList| with argument _labelSet_. @@ -8538,6 +8612,10 @@

Static Semantics: ContainsUndefinedContinueTarget

1. Return *false*. + ClassStaticBlockStatementList : [empty] + + 1. Return *false*. + ModuleItemList : ModuleItemList ModuleItem 1. Let _hasUndefinedLabels_ be ContainsUndefinedContinueTarget of |ModuleItemList| with arguments _iterationSet_ and « ». @@ -8925,6 +9003,13 @@

Static Semantics: Contains

Static semantic rules that depend upon substructure generally do not look into class bodies except for |PropertyName|s.

+ ClassStaticBlock : `static` `{` ClassStaticBlockBody `}` + + 1. Return *false*. + + +

Static semantic rules that depend upon substructure generally do not look into `static` initialization blocks.

+
ArrowFunction : ArrowParameters `=>` ConciseBody 1. If _symbol_ is not one of |NewTarget|, |SuperProperty|, |SuperCall|, `super` or `this`, return *false*. @@ -9028,6 +9113,10 @@

Static Semantics: ComputedPropertyContains

1. If _inList_ is *true*, return *true*. 1. Return the result of ComputedPropertyContains for |ClassElement| with argument _symbol_.
+ ClassElement : ClassStaticBlock + + 1. Return *false*. + ClassElement : `;` 1. Return *false*. @@ -9538,6 +9627,10 @@

Static Semantics: PropName

1. Return PropName of |ClassElementName|. + ClassElement : ClassStaticBlock + + 1. Return ~empty~. + ClassElement : `;` 1. Return ~empty~. @@ -12960,6 +13053,13 @@

Runtime Semantics: EvaluateBody

Even though field initializers constitute a function boundary, calling FunctionDeclarationInstantiation does not have any observable effect and so is omitted.

+ + ClassStaticBlockBody : ClassStaticBlockStatementList + + + 1. Assert: _argumentsList_ is empty. + 1. Return ? EvaluateClassStaticBlockBody of |ClassStaticBlockBody| with argument _functionObject_. + @@ -21775,7 +21875,7 @@

Static Semantics: Early Errors

  • - It is a Syntax Error if this |ContinueStatement| is not nested, directly or indirectly (but not crossing function boundaries), within an |IterationStatement|. + It is a Syntax Error if this |ContinueStatement| is not nested, directly or indirectly (but not crossing function or `static` initialization block boundaries), within an |IterationStatement|.
@@ -21808,7 +21908,7 @@

Static Semantics: Early Errors

BreakStatement : `break` `;`
  • - It is a Syntax Error if this |BreakStatement| is not nested, directly or indirectly (but not crossing function boundaries), within an |IterationStatement| or a |SwitchStatement|. + It is a Syntax Error if this |BreakStatement| is not nested, directly or indirectly (but not crossing function or `static` initialization block boundaries), within an |IterationStatement| or a |SwitchStatement|.
@@ -23528,6 +23628,7 @@

Syntax

`static` MethodDefinition[?Yield, ?Await] FieldDefinition[?Yield, ?Await] `;` `static` FieldDefinition[?Yield, ?Await] `;` + ClassStaticBlock `;` FieldDefinition[Yield, Await] : @@ -23536,6 +23637,15 @@

Syntax

ClassElementName[Yield, Await] : PropertyName[?Yield, ?Await] PrivateIdentifier + + ClassStaticBlock : + `static` `{` ClassStaticBlockBody `}` + + ClassStaticBlockBody : + ClassStaticBlockStatementList + + ClassStaticBlockStatementList : + StatementList[~Yield, +Await, ~Return]?

A class definition is always strict mode code.

@@ -23607,6 +23717,34 @@

Static Semantics: Early Errors

  • It is a Syntax Error if StringValue of |PrivateIdentifier| is *"#constructor"*.
+ + ClassStaticBlockBody : ClassStaticBlockStatementList +
    +
  • + It is a Syntax Error if the LexicallyDeclaredNames of |ClassStaticBlockStatementList| contains any duplicate entries. +
  • +
  • + It is a Syntax Error if any element of the LexicallyDeclaredNames of |ClassStaticBlockStatementList| also occurs in the VarDeclaredNames of |ClassStaticBlockStatementList|. +
  • +
  • + It is a Syntax Error if ContainsDuplicateLabels of |ClassStaticBlockStatementList| with argument « » is *true*. +
  • +
  • + It is a Syntax Error if ContainsUndefinedBreakTarget of |ClassStaticBlockStatementList| with argument « » is *true*. +
  • +
  • + It is a Syntax Error if ContainsUndefinedContinueTarget of |ClassStaticBlockStatementList| with arguments « » and « » is *true*. +
  • +
  • + It is a Syntax Error if ContainsArguments of |ClassStaticBlockStatementList| is *true*. +
  • +
  • + It is a Syntax Error if |ClassStaticBlockStatementList| Contains |SuperCall| is *true*. +
  • +
  • + It is a Syntax Error if |ClassStaticBlockStatementList| Contains `await` is *true*. +
  • +
@@ -23625,6 +23763,10 @@

Static Semantics: ClassElementKind

1. Return ~NonConstructorMethod~. + ClassElement : ClassStaticBlock + + 1. Return ~NonConstructorMethod~. + ClassElement : `;` 1. Return ~empty~. @@ -23668,6 +23810,10 @@

Static Semantics: IsStatic

1. Return *true*. + ClassElement : ClassStaticBlock + + 1. Return *true*. + ClassElement : `;` 1. Return *false*. @@ -23782,6 +23928,8 @@

Static Semantics: PrivateBoundIdentifiers

ClassElementName : PropertyName + ClassElement : ClassStaticBlock + ClassElement : `;` @@ -23924,6 +24072,32 @@

Runtime Semantics: ClassFieldDefinitionEvaluation

+ +

Runtime Semantics: ClassStaticBlockDefinitionEvaluation

+

With parameter _homeObject_.

+ ClassStaticBlock : `static` `{` ClassStaticBlockBody `}` + + 1. Let _lex_ be the running execution context's LexicalEnvironment. + 1. Let _privateScope_ be the running execution context's PrivateEnvironment. + 1. Let _sourceText_ be the empty sequence of Unicode code points. + 1. Let _formalParameters_ be an instance of the production FormalParameters : [empty]. + 1. Let _bodyFunction_ be OrdinaryFunctionCreate(%Function.prototype%, _sourceText_, _formalParameters_, |ClassStaticBlockBody|, ~non-lexical-this~, _lex_, _privateScope_). + 1. Perform MakeMethod(_bodyFunction_, _homeObject_). + 1. Return the ClassStaticBlockDefinition Record { [[BodyFunction]]: _bodyFunction_ }. + + The function _bodyFunction_ is never directly accessible to ECMAScript code. +
+ + +

Runtime Semantics: EvaluateClassStaticBlockBody

+

With parameter _functionObject_.

+ ClassStaticBlockBody : ClassStaticBlockStatementList + + 1. Perform ? FunctionDeclarationInstantiation(_functionObject_, « »). + 1. Return the result of evaluating |ClassStaticBlockStatementList|. + +
+

Runtime Semantics: ClassElementEvaluation

With parameter _object_.

@@ -23946,6 +24120,11 @@

Runtime Semantics: ClassElementEvaluation

1. Return MethodDefinitionEvaluation of |MethodDefinition| with arguments _object_ and *false*.
+ ClassElement : ClassStaticBlock + + 1. Return ClassStaticBlockDefinitionEvaluation of |ClassStaticBlock| with argument _object_. + + ClassElement : `;` @@ -24026,34 +24205,36 @@

Runtime Semantics: ClassDefinitionEvaluation

1. Let _instancePrivateMethods_ be a new empty List. 1. Let _staticPrivateMethods_ be a new empty List. 1. Let _instanceFields_ be a new empty List. - 1. Let _staticFields_ be a new empty List. + 1. Let _staticElements_ be a new empty List. 1. For each |ClassElement| _e_ of _elements_, do 1. If IsStatic of _e_ is *false*, then - 1. Let _field_ be ClassElementEvaluation of _e_ with argument _proto_. + 1. Let _element_ be ClassElementEvaluation of _e_ with argument _proto_. 1. Else, - 1. Let _field_ be ClassElementEvaluation of _e_ with argument _F_. - 1. If _field_ is an abrupt completion, then + 1. Let _element_ be ClassElementEvaluation of _e_ with argument _F_. + 1. If _element_ is an abrupt completion, then 1. Set the running execution context's LexicalEnvironment to _env_. 1. Set the running execution context's PrivateEnvironment to _outerPrivateEnvironment_. - 1. Return Completion(_field_). - 1. Set _field_ to _field_.[[Value]]. - 1. If _field_ is a PrivateElement, then - 1. Assert: _field_.[[Kind]] is either ~method~ or ~accessor~. + 1. Return Completion(_element_). + 1. Set _element_ to _element_.[[Value]]. + 1. If _element_ is a PrivateElement, then + 1. Assert: _element_.[[Kind]] is either ~method~ or ~accessor~. 1. If IsStatic of _e_ is *false*, let _container_ be _instancePrivateMethods_. 1. Else, let _container_ be _staticPrivateMethods_. - 1. If _container_ contains a PrivateElement whose [[Key]] is _field_.[[Key]], then + 1. If _container_ contains a PrivateElement whose [[Key]] is _element_.[[Key]], then 1. Let _existing_ be that PrivateElement. - 1. Assert: _field_.[[Kind]] and _existing_.[[Kind]] are both ~accessor~. - 1. If _field_.[[Get]] is *undefined*, then - 1. Let _combined_ be PrivateElement { [[Key]]: _field_.[[Key]], [[Kind]]: ~accessor~, [[Get]]: _existing_.[[Get]], [[Set]]: _field_.[[Set]] }. + 1. Assert: _element_.[[Kind]] and _existing_.[[Kind]] are both ~accessor~. + 1. If _element_.[[Get]] is *undefined*, then + 1. Let _combined_ be PrivateElement { [[Key]]: _element_.[[Key]], [[Kind]]: ~accessor~, [[Get]]: _existing_.[[Get]], [[Set]]: _element_.[[Set]] }. 1. Else, - 1. Let _combined_ be PrivateElement { [[Key]]: _field_.[[Key]], [[Kind]]: ~accessor~, [[Get]]: _field_.[[Get]], [[Set]]: _existing_.[[Set]] }. + 1. Let _combined_ be PrivateElement { [[Key]]: _element_.[[Key]], [[Kind]]: ~accessor~, [[Get]]: _element_.[[Get]], [[Set]]: _existing_.[[Set]] }. 1. Replace _existing_ in _container_ with _combined_. 1. Else, - 1. Append _field_ to _container_. - 1. Else if _field_ is a ClassFieldDefinition Record, then - 1. If IsStatic of _e_ is *false*, append _field_ to _instanceFields_. - 1. Else, append _field_ to _staticFields_. + 1. Append _element_ to _container_. + 1. Else if _element_ is a ClassFieldDefinition Record, then + 1. If IsStatic of _e_ is *false*, append _element_ to _instanceFields_. + 1. Else, append _element_ to _staticElements_. + 1. Else if _element_ is a ClassStaticBlockDefinition Record, then + 1. Append _element_ to _staticElements_. 1. Set the running execution context's LexicalEnvironment to _env_. 1. If _classBinding_ is not *undefined*, then 1. Perform _classScope_.InitializeBinding(_classBinding_, _F_). @@ -24061,8 +24242,12 @@

Runtime Semantics: ClassDefinitionEvaluation

1. Set _F_.[[Fields]] to _instanceFields_. 1. For each PrivateElement _method_ of _staticPrivateMethods_, do 1. Perform ! PrivateMethodOrAccessorAdd(_method_, _F_). - 1. For each element _fieldRecord_ of _staticFields_, do - 1. Let _result_ be DefineField(_F_, _fieldRecord_). + 1. For each element _elementRecord_ of _staticElements_, do + 1. If _elementRecord_ is a ClassFieldDefinition Record, then + 1. Let _result_ be DefineField(_F_, _elementRecord_). + 1. Else, + 1. Assert: _elementRecord_ is a ClassStaticBlockDefinition Record. + 1. Let _result_ be ? Call(_elementRecord_.[[BodyFunction]], _F_). 1. If _result_ is an abrupt completion, then 1. Set the running execution context's PrivateEnvironment to _outerPrivateEnvironment_. 1. Return _result_. @@ -24125,6 +24310,10 @@

Runtime Semantics: Evaluation

1. Let _privateName_ be the Private Name in _names_ whose [[Description]] is _privateIdentifier_. 1. Return _privateName_.
+ ClassStaticBlockStatementList : [empty] + + 1. Return NormalCompletion(*undefined*). + @@ -45832,6 +46021,9 @@

Functions and Classes

+ + +