Skip to content

Commit ac0cda4

Browse files
committed
Make sure to propagate a promise job's snapshot when handling abrupt completions
Closes tc39#35.
1 parent a9008a0 commit ac0cda4

File tree

1 file changed

+87
-2
lines changed

1 file changed

+87
-2
lines changed

spec.html

+87-2
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,94 @@ <h1>
318318
</emu-clause>
319319
</ins>
320320

321-
<ins class="block">
322321
<emu-clause id="sec-control-abstraction-objects">
323322
<h1>Control Abstraction Objects</h1>
323+
324+
<emu-clause id="sec-promise-objects">
325+
<h1>Promise Objects</h1>
326+
327+
<emu-clause id="sec-promise-jobs">
328+
<h1>Promise Jobs</h1>
329+
330+
<emu-clause id="sec-newpromisereactionjob" type="abstract operation" oldids="sec-promisereactionjob">
331+
<h1>
332+
NewPromiseReactionJob (
333+
_reaction_: a PromiseReaction Record,
334+
_argument_: an ECMAScript language value,
335+
): a Record with fields [[Job]] (a Job Abstract Closure) and [[Realm]] (a Realm Record or *null*)
336+
</h1>
337+
<dl class="header">
338+
<dt>description</dt>
339+
<dd>It returns a new Job Abstract Closure that applies the appropriate handler to the incoming value, and uses the handler's return value to resolve or reject the derived promise associated with that handler.</dd>
340+
</dl>
341+
<emu-alg>
342+
1. Let _job_ be a new Job Abstract Closure with no parameters that captures _reaction_ and _argument_ and performs the following steps when called:
343+
1. Let _promiseCapability_ be _reaction_.[[Capability]].
344+
1. Let _type_ be _reaction_.[[Type]].
345+
1. Let _handler_ be _reaction_.[[Handler]].
346+
1. If _handler_ is ~empty~, then
347+
1. If _type_ is ~Fulfill~, let _handlerResult_ be NormalCompletion(_argument_).
348+
1. Else,
349+
1. Assert: _type_ is ~Reject~.
350+
1. Let _handlerResult_ be ThrowCompletion(_argument_).
351+
1. Else, let _handlerResult_ be Completion(HostCallJobCallback(_handler_, *undefined*, « _argument_ »)).
352+
1. If _promiseCapability_ is *undefined*, then
353+
1. Assert: _handlerResult_ is not an abrupt completion.
354+
1. Return ~empty~.
355+
1. Assert: _promiseCapability_ is a PromiseCapability Record.
356+
1. If _handlerResult_ is an abrupt completion, then
357+
1. <del>Return ? Call(_promiseCapability_.[[Reject]], *undefined*, « _handlerResult_.[[Value]] »).</del>
358+
1. <ins>Let _previousContextMapping_ be AsyncContextSwap(_handler_.[[AsyncContextSnapshot]]).</ins>
359+
1. <ins>Let _rejectResult_ be Completion(Call(_promiseCapability_.[[Reject]], *undefined*, « _handlerResult_.[[Value]] »)).</ins>
360+
1. <ins>AsyncContextSwap(_previousContextMapping_).</ins>
361+
1. <ins>Return _rejectResult_.</ins>
362+
1. Else,
363+
1. Return ? Call(_promiseCapability_.[[Resolve]], *undefined*, « _handlerResult_.[[Value]] »).
364+
1. Let _handlerRealm_ be *null*.
365+
1. If _reaction_.[[Handler]] is not ~empty~, then
366+
1. Let _getHandlerRealmResult_ be Completion(GetFunctionRealm(_reaction_.[[Handler]].[[Callback]])).
367+
1. If _getHandlerRealmResult_ is a normal completion, set _handlerRealm_ to _getHandlerRealmResult_.[[Value]].
368+
1. Else, set _handlerRealm_ to the current Realm Record.
369+
1. NOTE: _handlerRealm_ is never *null* unless the handler is *undefined*. When the handler is a revoked Proxy and no ECMAScript code runs, _handlerRealm_ is used to create error objects.
370+
1. Return the Record { [[Job]]: _job_, [[Realm]]: _handlerRealm_ }.
371+
</emu-alg>
372+
</emu-clause>
373+
374+
<emu-clause id="sec-newpromiseresolvethenablejob" type="abstract operation" oldids="sec-promiseresolvethenablejob">
375+
<h1>
376+
NewPromiseResolveThenableJob (
377+
_promiseToResolve_: a Promise,
378+
_thenable_: an Object,
379+
_then_: a JobCallback Record,
380+
): a Record with fields [[Job]] (a Job Abstract Closure) and [[Realm]] (a Realm Record)
381+
</h1>
382+
<dl class="header">
383+
</dl>
384+
<emu-alg>
385+
1. Let _job_ be a new Job Abstract Closure with no parameters that captures _promiseToResolve_, _thenable_, and _then_ and performs the following steps when called:
386+
1. Let _resolvingFunctions_ be CreateResolvingFunctions(_promiseToResolve_).
387+
1. Let _thenCallResult_ be Completion(HostCallJobCallback(_then_, _thenable_, « _resolvingFunctions_.[[Resolve]], _resolvingFunctions_.[[Reject]] »)).
388+
1. If _thenCallResult_ is an abrupt completion, then
389+
1. <del>Return ? Call(_resolvingFunctions_.[[Reject]], *undefined*, « _thenCallResult_.[[Value]] »).</del>
390+
1. <ins>Let _previousContextMapping_ be AsyncContextSwap(_then_.[[AsyncContextSnapshot]]).</ins>
391+
1. <ins>Let _rejectResult_ be Completion(Call(_resolvingFunctions_.[[Reject]], *undefined*, « _thenCallResult_.[[Value]] »)).</ins>
392+
1. <ins>AsyncContextSwap(_previousContextMapping_).</ins>
393+
1. <ins>Return _rejectResult_.</ins>
394+
1. Return ? _thenCallResult_.
395+
1. Let _getThenRealmResult_ be Completion(GetFunctionRealm(_then_.[[Callback]])).
396+
1. If _getThenRealmResult_ is a normal completion, let _thenRealm_ be _getThenRealmResult_.[[Value]].
397+
1. Else, let _thenRealm_ be the current Realm Record.
398+
1. NOTE: _thenRealm_ is never *null*. When _then_.[[Callback]] is a revoked Proxy and no code runs, _thenRealm_ is used to create error objects.
399+
1. Return the Record { [[Job]]: _job_, [[Realm]]: _thenRealm_ }.
400+
</emu-alg>
401+
<emu-note>
402+
<p>This Job uses the supplied thenable and its `then` method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the `then` method occurs after evaluation of any surrounding code has completed.</p>
403+
</emu-note>
404+
</emu-clause>
405+
</emu-clause>
406+
</emu-clause>
407+
408+
<ins class="block">
324409
<emu-clause id="sec-asynccontext-objects">
325410
<h1>AsyncContext Objects</h1>
326411

@@ -500,6 +585,6 @@ <h1>Properties of AsyncContext Instances</h1>
500585
</emu-table>
501586
</emu-clause>
502587
</emu-clause>
588+
</ins>
503589
</emu-clause>
504-
</ins>
505590

0 commit comments

Comments
 (0)