Skip to content

Commit

Permalink
Fix inaccuracies in custom element construction stack management
Browse files Browse the repository at this point in the history
Fixes #1238. Usually, the popped stack entry is not the element, but
instead an already-constructed marker. This makes the stack-popping
generic, and also adds a note explaining exactly what could be going on
here.

Also clarifies the cases in which the already constructed marker
matters. In addition to calling super() multiple times, this error case
can be triggered by creating another instance of the class being
constructed. This adds examples of both possibilities.

Finally, fixes a typo in the HTMLElement() constructor which used the
variable names "instance" and "element" interchangeably, and fixes a
broken cross-reference to "upgrade an element".
  • Loading branch information
domenic committed May 27, 2016
1 parent 98895af commit b371307
Showing 1 changed file with 63 additions and 11 deletions.
74 changes: 63 additions & 11 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -9677,16 +9677,51 @@ interface <dfn>HTMLUnknownElement</dfn> : <span>HTMLElement</span> { };</pre>
via <code data-x="">new MyCustomElement()</code>.</p>
</li>

<li><p>Let <var>instance</var> be the last entry in <var>definition</var>'s <span
<li><p>Let <var>element</var> be the last entry in <var>definition</var>'s <span
data-x="concept-custom-element-definition-construction-stack">construction stack</span>.</li>

<li>
<p>If <var>instance</var> is an <span data-x="concept-already-constructed-marker"><i>already
<p>If <var>element</var> is an <span data-x="concept-already-constructed-marker"><i>already
constructed</i> marker</span>, then throw an <span>"<code>InvalidStateError</code>"</span>
<code>DOMException</code> and abort these steps.</p>

<p class="note">This can occur when the author code inside the <span>custom element
constructor</span> invokes <code data-x="">super()</code> multiple times.</p>
<div class="example">
<p>This can occur when the author code inside the <span>custom element
constructor</span> <a href="#custom-element-conformance">non-conformantly</a> creates another
instance of the class being constructed, before calling <code
data-x="">super()</code>:</p>

<pre>let doSillyThing = false;

class DontDoThis extends HTMLElement {
constructor() {
if (doSillyThing) {
doSillyThing = false;
new DontDoThis();
// Now the construction stack will contain an <i>already constructed</i> marker.
}

// This will then fail with an "InvalidStateError" DOMException:
super();
}
}</pre>
</div>

<div class="example">
<p>This can also occur when author code inside the <span>custom element constructor</span> <a
href="#custom-element-conformance">non-conformantly</a> calls <code data-x="">super()</code>
twice, since per the JavaScript specification, this actually executes the superclass
constructor (i.e. this algorithm) twice, before throwing an error:

<pre>class DontDoThisEither extends HTMLElement {
constructor() {
super();

// This will throw, but not until it has already called into the HTMLElement constructor
super();
}
}</pre>
</div>
</li>

<li><p>Perform <var>element</var>.[[SetPrototypeOf]](<var>prototype</var>). Rethrow any
Expand All @@ -9698,7 +9733,7 @@ interface <dfn>HTMLUnknownElement</dfn> : <span>HTMLElement</span> { };</pre>
marker</span>.</p></li>

<li>
<p>Return <var>instance</var>.</p>
<p>Return <var>element</var>.</p>

<p class="note">This step is normally reached when <span
data-x="custom-element-upgrades">upgrading</span> a custom element; the existing element is
Expand Down Expand Up @@ -66074,10 +66109,11 @@ console.log(plasticButton2.getAttribute("is")); // will output "plastic-button"<

<dt>A <dfn data-x="concept-custom-element-definition-construction-stack">construction
stack</dfn></dt>
<dd>A list, initially empty, that is manipulated by the <span>upgrade an element</span> algorithm
and the <span data-x="dom-HTMLElement"><code>HTMLElement</code> constructor</span>. Each entry in
the list will be either an element or an <dfn
data-x="concept-already-constructed-marker"><i>already constructed</i> marker</dfn>.</dd>
<dd>A list, initially empty, that is manipulated by the <span
data-x="concept-upgrade-an-element">upgrade an element</span> algorithm and the <span
data-x="dom-HTMLElement"><code>HTMLElement</code> constructor</span>. Each entry in the list will
be either an element or an <dfn data-x="concept-already-constructed-marker"><i>already
constructed</i> marker</dfn>.</dd>
</dl>

<p>To <dfn data-export="">look up a custom element definition</dfn>, given a <var>document</var>,
Expand Down Expand Up @@ -66388,8 +66424,24 @@ fetch(articleURL)

<li><p>Let <var>constructResult</var> be <span>Construct</span>(<var>C</var>).</p></li>

<li><p>Remove <var>element</var> from the end of <var>definition</var>'s <span
data-x="concept-custom-element-definition-construction-stack">construction stack</span>.</p></li>
<li>
<p>Remove the last entry from the end of <var>definition</var>'s <span
data-x="concept-custom-element-definition-construction-stack">construction stack</span>.</p>

<div class="note">
<p>Assuming <var>C</var> calls <code data-x="">super()</code> (as it <a
href="#custom-element-conformance">should</a>), and that the call succeeds, this will be the
<span data-x="concept-already-constructed-marker"><i>already
constructed</i> marker</span> that replaced the <var>element</var> we pushed at the beginning
of this algorithm. (The <span data-x="dom-HTMLElement"><code>HTMLElement</code>
constructor</span> carries out this replacement.)</p>

<p>If <var>C</var> does not call <code data-x="">super()</code> (i.e. it is not <a
href="#custom-element-conformance">conformant</a>), or if any step in the <span
data-x="dom-HTMLElement"><code>HTMLElement</code> constructor</span> throws, then this entry
will still be <var>element</var>.</p>
</div>
</li>

<li><p>If <var>constructResult</var> is an abrupt completion, then return
<var>constructResult</var> (i.e., rethrow the exception).</p></li>
Expand Down

0 comments on commit b371307

Please sign in to comment.