-
Notifications
You must be signed in to change notification settings - Fork 107
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
Normative: Add initializer callback for side effects #165
Changes from all commits
9f6d669
5bba880
14b8919
9c3c148
77543ec
77e1922
9acf8f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -159,7 +159,7 @@ <h1>The ElementDescriptor Specification Type</h1> | |
<tr> <th>Field Name</th> <th>Value</th> </tr> | ||
</thead> | ||
<tbody> | ||
<tr> <td>[[Kind]]</td> <td>One of `"method"` or `"field"`</td> </tr> | ||
<tr> <td>[[Kind]]</td> <td>One of `"method"`, `"field"` or `"initializer"`</td> </tr> | ||
<tr> <td>[[Key]]</td> <td>A Property Key or %PrivateName% object</td> </tr> | ||
<tr> <td>[[Descriptor]]</td> <td>A Property Descriptor</td> </tr> | ||
<tr> <td>[[Placement]]</td> <td>One of `"static"`, `"prototype"`, or `"own"`</td> </tr> | ||
|
@@ -188,6 +188,15 @@ <h1>The ElementDescriptor Specification Type</h1> | |
<li>_element_.[[Descriptor]].[[Configurable]] is *false*.</li> | ||
</ul> | ||
</li> | ||
<li> | ||
If _element_.[[Kind]] is `"initializer", then | ||
<ul> | ||
<li>_element_.[[Key]] absent.</li> | ||
<li>_element_.[[Descriptor]] is absent.</li> | ||
<li>_element_.[[Initializer]] is present.</li> | ||
<li>_element_.[[Decorators]] is absent.</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</p> | ||
</emu-clause> | ||
|
@@ -408,6 +417,54 @@ <h1>CoalesceClassElements ( _elements_ )</h1> | |
<emu-note>In the case of public class elements, coalescing corresponds in semantics to ValidateAndApplyPropertyDescriptor. Note that this algorithm only coalesces method and accessor declarations, and it leaves field declarations as is.</emu-note> | ||
</emu-clause> | ||
|
||
<emu-clause id="initialize-public-instance-elements" aoid="InitializeInstanceFields"> | ||
<h1>InitializeInstanceElements ( _O_, _constructor_ )</h1> | ||
|
||
<emu-alg> | ||
1. Assert: Type ( _O_ ) is Object. | ||
1. Assert: Assert _constructor_ is an ECMAScript function object. | ||
1. Let _elements_ be the value of _F_'s [[Elements]] internal slot. | ||
1. For each item _element_ in order from _elements_, | ||
1. If _element_.[[Placement]] is `"own"` and _element_.[[Kind]] is `"method"`, | ||
1. Perform ? DefineClassElement(_O_, _element_). | ||
1. For each item _element_ in order from _elements_, | ||
1. If _element_.[[Placement]] is `"own"` and _element_.[[Kind]] is `"field"`, | ||
1. Assert: _element_.[[Descriptor]] does not have a [[Value]], [[Get]] or [[Set]] slot. | ||
1. Perform ? DefineClassElement(_O_, _element_). | ||
1. <ins>If _element_.[[Kind]] is `"initializer"` and _element_.[[Placement]] is `"own"`,</ins> | ||
1. <ins>Let _res_ be ? Call(_element_.[[Initializer]], _O_).</ins> | ||
1. <ins>If _res_ is not *undefined*, throw a *TypeError* exception.</ins> | ||
1. Return. | ||
</emu-alg> | ||
</emu-clause> | ||
|
||
<emu-clause id="initialize-class-elements" aoid="InitializeClassElements"> | ||
<h1>InitializeClassElements(_F_, _proto_)</h1> | ||
|
||
<emu-alg> | ||
1. Assert: Type(_F_) is Object and Type(_proto_) is Object. | ||
1. Assert: _F_ is an ECMAScript function object. | ||
1. Assert: _proto_ is ! Get(_F_, `"prototype"`). | ||
1. Let _elements_ be the value of _F_'s [[Elements]] internal slot. | ||
1. For each item _element_ in order from _elements_, | ||
1. Assert: If _element_.[[Placement]] is `"prototype"` <del>or `"static"`</del>, then _element_.[[Key]] is not a Private Name. | ||
1. If _element_.[[Kind]] is `"method"`, | ||
1. Let _receiver_ be _F_ if _element_.[[Placement]] is `"static"`, else let _receiver_ be _proto_. | ||
1. Perform ? DefineClassElement(_receiver_, _element_). | ||
1. For each item _element_ in order from _elements_, | ||
1. If _element_.[[Kind]] is `"field"` and _element_.[[Placement]] is `"static"` or `"prototype"`, | ||
1. Assert: _element_.[[Descriptor]] does not have a [[Value]], [[Get]] or [[Set]] slot. | ||
1. Let _receiver_ be _F_ if _element_.[[Placement]] is `"static"`, else let _receiver_ be _proto_. | ||
1. Perform ? DefineClassElement(_receiver_, _element_). | ||
1. <ins>If _element_.[[Placement]] is `"prototype"` or `"static"` and _element_.[[Kind]] is `"initializer"`,</ins> | ||
1. <ins>Let _receiver_ be _F_ if _element_.[[Placement]] is `"static"`, else let _receiver_ be _proto_.</ins> | ||
1. <ins>Let _res_ be ? Call(_element_.[[Initializer]], _receiver_).</ins> | ||
1. <ins>If _res_ is not *undefined*, throw a *TypeError* exception.</ins> | ||
1. Return. | ||
</emu-alg> | ||
<emu-note type=editor>Value properties are added before initializers so that all methods are visible from all initializers</emu-note> | ||
</emu-clause> | ||
|
||
</emu-clause> | ||
|
||
|
||
|
@@ -563,7 +620,7 @@ <h1>Element Descriptors</h1> | |
<p>An <dfn>element descriptor</dfn> describes an element of a class or object literal and has the following shape:</p> | ||
<pre><code class=typescript> | ||
interface ElementDescriptor { | ||
kind: "method" or "field" | ||
kind: "method", "initializer", or "field" | ||
key: String, Symbol or Private Name, | ||
placement: "static", "prototype", or "own" | ||
descriptor: PropertyDescriptor, | ||
|
@@ -689,7 +746,12 @@ <h1>DecorateConstructor ( _elements_, _decorators_ )</h1> | |
1. Append _elementsAndFinisher_.[[Finisher]] to _finishers_. | ||
1. If _elementsAndFinisher_.[[Elements]] is not *undefined*, | ||
1. Set _elements_ to the concatenation of _elementsAndFinisher_.[[Elements]] and _privateElements_. | ||
1. If there are two class elements _a_ and _b_ in _elements_ such that _a_.[[Key]] is _b_.[[Key]] and _a_.[[Placement]] is _b_.[[Placement]], throw a *TypeError* exception. | ||
1. If there are two class elements _a_ and _b_ in _elements_ such that all of the following are true: | ||
1. _a_.[[Kind]] is not `"initializer"` | ||
1. _b_.[[Kind]] is not `"initializer"` | ||
1. _a_.[[Key]] is _b_.[[Key]] | ||
1. _a_.[[Placement]] is _b_.[[Placement]] | ||
1. Then, throw a *TypeError* exception. | ||
1. Return the Record { [[Elements]]: _elements_, [[Finishers]]: _finishers_ }. | ||
</emu-alg> | ||
</emu-clause> | ||
|
@@ -744,12 +806,14 @@ <h1>FromElementDescriptor ( _element_ )</h1> | |
1. Let _desc_ be PropertyDescriptor{ [[Value]]: `"Descriptor"`, [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }. | ||
1. Perform ! DefinePropertyOrThrow(_obj_, @@toStringTag, _desc_). | ||
1. Perform ! CreateDataPropertyOrThrow(_obj_, `"kind"`, _element_.[[Kind]]). | ||
1. Let _key_ be _element_.[[Key]]. | ||
1. If _key_ is a Private Name, set _key_ to ? PrivateNameObject(_key_). | ||
1. Perform ! CreateDataPropertyOrThrow(_obj_, `"key"`, _key_). | ||
1. If _element_.[[Kind]] is `"method"` or `"field"`, | ||
1. Let _key_ be _element_.[[Key]]. | ||
1. If _key_ is a Private Name, set _key_ to ? PrivateNameObject(_key_). | ||
1. Perform ! CreateDataPropertyOrThrow(_obj_, `"key"`, _key_). | ||
1. Perform ! CreateDataPropertyOrThrow(_obj_, `"placement"`, _element_.[[Placement]]). | ||
1. Perform ! CreateDataPropertyOrThrow(_obj_, `"descriptor"`, ! FromPropertyDescriptor(_element_.[[Descriptor]])). | ||
1. If _element_.[[Kind]] is `"field"`, | ||
1. If _element_.[[Kind]] is `"method"` or `"field"`, | ||
1. Perform ! CreateDataPropertyOrThrow(_obj_, `"descriptor"`, ! FromPropertyDescriptor(_element_.[[Descriptor]])). | ||
1. If _element_.[[Kind]] is `"field"` or `"initializer"`, | ||
1. Let _initializer_ be _element_.[[Initializer]]. | ||
1. If _initializer_ is ~empty~, set _initializer_ to *undefined*. | ||
1. Perform ! CreateDataPropertyOrThrow(_obj_, `"initializer"`, _initializer_). | ||
|
@@ -781,26 +845,38 @@ <h1>ToElementDescriptor ( _elementObject_ )</h1> | |
<emu-alg> | ||
1. Assert: _elementObject_ is an ECMAScript language value. | ||
1. Let _kind_ be ? ToString(? Get(_elementObject_, `"kind"`)). | ||
1. If _kind_ is not one of `"method"` or `"field"`, throw a *TypeError* exception. | ||
1. If _kind_ is not one of `"initializer"`, `"method"`, or `"field"`, throw a *TypeError* exception. | ||
1. Let _key_ be ? Get(_elementObject_, `"key"`). | ||
1. If _kind_ is `"initializer"`, | ||
1. If _key_ is not *undefined*, throw a *TypeError* exception. | ||
littledan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. If _key_ has a [[PrivateName]] internal slot, set _key_ to _key_.[[PrivateName]]. | ||
1. Otherwise, set _key_ to ? ToPropertyKey(_key_). | ||
1. Let _placement_ be ? ToString(? Get(_elementObject_, `"placement"`)). | ||
1. If _placement_ is not one of `"static"`, `"prototype"`, or `"own"`, throw a *TypeError* exception. | ||
1. Let _descriptor_ be ? ToPropertyDescriptor(? Get(_elementObject_, `"descriptor"`)). | ||
1. Let _initializer_ be ? Get(_elementObject_, `"initializer"`). | ||
1. Let _elements_ be ? Get(_elementObject_, `"elements"`). | ||
1. If _elements_ is not *undefined*, throw a *TypeError* exception. | ||
1. If _kind_ not `"field"`, | ||
1. If _initializer_ is not *undefined*, throw a *TypeError* exception. | ||
1. Let _descriptor_ be ? Get(_elementObject_, `"descriptor"`) | ||
1. If _kind_ is `"initializer"`, | ||
1. If _descriptor_ is not *undefined*, throw a *TypeError* exception. | ||
1. Otherwise, | ||
1. Set _descriptor_ to ? ToPropertyDescriptor(_descriptor_). | ||
1. If _key_ is a Private Name, | ||
1. If _descriptor_.[[Enumerable]] is *true*, throw a *TypeError* exception. | ||
1. If _descriptor_.[[Configurable]] is *true*, throw a *TypeError* exception. | ||
1. If _placement_ is `"prototype"`, throw a *TypeError* exception. | ||
1. If _kind_ is `"field"`, | ||
1. If _descriptor_ has a [[Get]], [[Set]] or [[Value]] internal slot, throw a *TypeError* exception. | ||
1. Let _element_ be the ElementDescriptor { [[Kind]]: _kind_, [[Key]]: _key_, [[Placement]]: _placement_, [[Descriptor]]: _descriptor_ }. | ||
1. If _kind_ is `"field"`, set _element_.[[Initializer]] to _initializer_. | ||
1. Let _initializer_ be ? Get(_elementObject_, `"initializer"`). | ||
1. If _kind_ is `"initializer"`, | ||
1. If _initializer_ is *undefined*, throw a *TypeError* exception | ||
1. If _kind_ is `"method"`, | ||
1. If _initializer_ is not *undefined*, throw a *TypeError* exception. | ||
1. Let _elements_ be ? Get(_elementObject_, `"elements"`). | ||
1. If _elements_ is not *undefined*, throw a *TypeError* exception. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this use a HasProperty, instead of a Get, since it’s just checking existence? Or is the intention to allow an explicit undefined property - and if so, that seems like it’d be an error, so why allow it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Get matches the use of Get when actually using the elements in a class decorator, per POLS. |
||
1. Let _element_ be the ElementDescriptor { [[Kind]]: _kind_, [[Placement]]: _placement_ }. | ||
1. If _kind_ is `"method"` or `"field", | ||
1. Set _element_.[[Key]] to _key_. | ||
1. Set _element_.[[Descriptor]] to _descriptor_. | ||
1. If _kind_ is `"field"` or `"initializer"`, | ||
1. Set _element_.[[Initializer]] to _initializer_. | ||
1. Return _element_. | ||
</emu-alg> | ||
</emu-clause> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reads a bit awkwardly; maybe it should be in an abstract operation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is following @nicolo-ribaudo 's suggestion above. I think the factoring might be awkward too; let's work out these editorial issues during Stage 3.