Skip to content

Commit e02a390

Browse files
nicolo-ribaudojonco3
authored andcommitted
Bug 1992103 - Align async modules rejection order with fulfillment order r=jonco
This patch inverts the order in which we reject promises in AsyncModuleExecutionRejected to match AsyncModuleExecutionFulfilled: first the promise corresponding to the leaf module (the one that throws) is rejected, and then its ancestors. This change was discussed at the July 2025 TC39 meeting. Spec PR: tc39/ecma262#3695 test262: tc39/test262#4591 Differential Revision: https://phabricator.services.mozilla.com/D267210
1 parent 577c80a commit e02a390

File tree

1 file changed

+18
-17
lines changed

1 file changed

+18
-17
lines changed

js/src/vm/Modules.cpp

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2507,10 +2507,10 @@ void js::AsyncModuleExecutionRejected(JSContext* cx,
25072507
// Step 2. Assert: module.[[Status]] is evaluating-async.
25082508
MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync);
25092509

2510-
// Step 3. Assert: module.[[AsyncEvaluation]] is true.
2510+
// Step 3. Assert: module.[[AsyncEvaluationOrder]] is an integer.
25112511
MOZ_ASSERT(module->isAsyncEvaluating());
25122512

2513-
// Step 4. 4. Assert: module.[[EvaluationError]] is empty.
2513+
// Step 4. Assert: module.[[EvaluationError]] is empty.
25142514
MOZ_ASSERT(!module->hadEvaluationError());
25152515

25162516
ModuleObject::onTopLevelEvaluationFinished(module);
@@ -2521,33 +2521,34 @@ void js::AsyncModuleExecutionRejected(JSContext* cx,
25212521
// Step 6. Set module.[[Status]] to evaluated.
25222522
MOZ_ASSERT(module->status() == ModuleStatus::Evaluated);
25232523

2524+
// Step 7. Set module.[[AsyncEvaluationOrder]] to done.
25242525
module->clearAsyncEvaluatingPostOrder();
25252526

2526-
// Step 7. For each Cyclic Module Record m of module.[[AsyncParentModules]],
2527-
// do:
2528-
Rooted<ListObject*> parents(cx, module->asyncParentModules());
2529-
Rooted<ModuleObject*> parent(cx);
2530-
for (uint32_t i = 0; i < parents->length(); i++) {
2531-
parent = &parents->get(i).toObject().as<ModuleObject>();
2532-
2533-
// Step 7.a. Perform AsyncModuleExecutionRejected(m, error).
2534-
AsyncModuleExecutionRejected(cx, parent, error);
2535-
}
2536-
2537-
// Step 8. If module.[[TopLevelCapability]] is not empty, then:
2527+
// Step 9. If module.[[TopLevelCapability]] is not empty, then:
25382528
if (module->hasTopLevelCapability()) {
2539-
// Step 8.a. Assert: module.[[CycleRoot]] is module.
2529+
// Step 9.a. Assert: module.[[CycleRoot]] is module.
25402530
MOZ_ASSERT(module->getCycleRoot() == module);
25412531

2542-
// Step 8.b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]],
2532+
// Step 9.b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]],
25432533
// undefined, error).
25442534
if (!ModuleObject::topLevelCapabilityReject(cx, module, error)) {
25452535
// If Reject fails, there's nothing more we can do here.
25462536
cx->clearPendingException();
25472537
}
25482538
}
25492539

2550-
// Step 9. Return unused.
2540+
// Step 10. For each Cyclic Module Record m of module.[[AsyncParentModules]],
2541+
// do:
2542+
Rooted<ListObject*> parents(cx, module->asyncParentModules());
2543+
Rooted<ModuleObject*> parent(cx);
2544+
for (uint32_t i = 0; i < parents->length(); i++) {
2545+
parent = &parents->get(i).toObject().as<ModuleObject>();
2546+
2547+
// Step 10.a. Perform AsyncModuleExecutionRejected(m, error).
2548+
AsyncModuleExecutionRejected(cx, parent, error);
2549+
}
2550+
2551+
// Step 11. Return unused.
25512552
}
25522553

25532554
// https://tc39.es/proposal-import-attributes/#sec-evaluate-import-call

0 commit comments

Comments
 (0)