Skip to content

Commit 75a3526

Browse files
committed
Reject promise when child module throws
1 parent 4b3a556 commit 75a3526

File tree

3 files changed

+93
-13
lines changed

3 files changed

+93
-13
lines changed

lib/Runtime/Language/SourceTextModuleRecord.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -990,24 +990,31 @@ namespace Js
990990
Assert(this->errorObject == nullptr);
991991
SetWasEvaluated();
992992

993-
if (childrenModuleSet != nullptr)
993+
JavascriptExceptionObject *exception = nullptr;
994+
Var ret = nullptr;
995+
996+
try
994997
{
995-
childrenModuleSet->EachValue([=](SourceTextModuleRecord* childModuleRecord)
998+
if (childrenModuleSet != nullptr)
996999
{
997-
if (!childModuleRecord->WasEvaluated())
1000+
childrenModuleSet->EachValue([=](SourceTextModuleRecord* childModuleRecord)
9981001
{
999-
childModuleRecord->ModuleEvaluation();
1000-
}
1001-
});
1002-
}
1003-
CleanupBeforeExecution();
1002+
if (!childModuleRecord->WasEvaluated())
1003+
{
1004+
childModuleRecord->ModuleEvaluation();
1005+
}
1006+
// if child module was evaluated before and threw need to re-throw now
1007+
// if child module has been dynamically imported and has exception need to throw
1008+
if (childModuleRecord->GetErrorObject() != nullptr)
1009+
{
1010+
JavascriptExceptionOperators::Throw(childModuleRecord->GetErrorObject(), this->scriptContext);
1011+
}
1012+
});
1013+
}
1014+
CleanupBeforeExecution();
10041015

1005-
Arguments outArgs(CallInfo(CallFlags_Value, 0), nullptr);
1016+
Arguments outArgs(CallInfo(CallFlags_Value, 0), nullptr);
10061017

1007-
Var ret = nullptr;
1008-
JavascriptExceptionObject *exception = nullptr;
1009-
try
1010-
{
10111018
AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_JavascriptException));
10121019
ENTER_SCRIPT_IF(scriptContext, true, false, false, !scriptContext->GetThreadContext()->IsScriptActive(),
10131020
{
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
// Dynamic import should always resolve or reject a promise
7+
// and it should never throw an unhandled exception
8+
// https://github.com/Microsoft/ChakraCore/issues/5796
9+
10+
const promises = [];
11+
12+
function testDynamicImport(testCase, shouldThrow = false, errorType = URIError)
13+
{
14+
if (shouldThrow) {
15+
promises.push(testCase
16+
.then(() => print("Promise should be rejected"))
17+
.catch (e => {if (!(e instanceof errorType)) throw new Error("fail");})
18+
.catch (() => print("Wrong error type"))
19+
);
20+
} else {
21+
promises.push(testCase.then(() => true).catch(e => print ("Test case failed")));
22+
}
23+
}
24+
25+
// Invalid specifiers, these produce promises rejected with URIErros
26+
testDynamicImport(import(undefined), true);
27+
testDynamicImport(import(true), true);
28+
testDynamicImport(import(false), true);
29+
testDynamicImport(import({}), true);
30+
testDynamicImport(import(' '), true);
31+
32+
WScript.RegisterModuleSource("case1", 'this is a syntax error');
33+
WScript.RegisterModuleSource("case2", 'import "helper1";');
34+
WScript.RegisterModuleSource("helper1", 'this is a syntax error');
35+
WScript.RegisterModuleSource("case3", 'import "case1";');
36+
WScript.RegisterModuleSource("case4", 'throw new TypeError("error");');
37+
WScript.RegisterModuleSource("case5", 'import "case3";');
38+
WScript.RegisterModuleSource("case6", 'import "case4";');
39+
WScript.RegisterModuleSource("helper2", 'throw new TypeError("error");');
40+
WScript.RegisterModuleSource("case7", 'import "helper2";');
41+
WScript.RegisterModuleSource("passThrough", 'import "helper3"');
42+
WScript.RegisterModuleSource("helper3", 'throw new TypeError("error");');
43+
WScript.RegisterModuleSource("case8", 'import "passThrough";');
44+
WScript.RegisterModuleSource("case9", 'import "case8";');
45+
46+
// syntax error at first level
47+
testDynamicImport(import("case1"), true, SyntaxError);
48+
// syntax error at second level
49+
testDynamicImport(import("case2"), true, SyntaxError);
50+
// syntax error at second level from already imported module
51+
testDynamicImport(import("case3"), true, SyntaxError);
52+
// Type Error at run time at first level
53+
testDynamicImport(import("case4"), true, TypeError);
54+
// Syntax error at 3rd level
55+
testDynamicImport(import("case5"), true, SyntaxError);
56+
// Indirectly re-Import the module that threw the type error
57+
// Promise should be resolved as the child module won't be evaluated twice
58+
testDynamicImport(import("case6"), true, TypeError);
59+
// Type Error at run time at second level
60+
testDynamicImport(import("case7"), true, TypeError);
61+
// Type Error at run time at third level
62+
testDynamicImport(import("case8"), true, TypeError);
63+
// Type Error at run time in a child that has already thrown
64+
testDynamicImport(import("case9"), true, TypeError);
65+
66+
Promise.all(promises).then(() => print ("pass"));

test/es6module/rlexe.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@
6969
<tags>exclude_sanitize_address</tags>
7070
</default>
7171
</test>
72+
<test>
73+
<default>
74+
<files>dynamic_import_promises_5796.js</files>
75+
<compile-flags>-ESDynamicImport</compile-flags>
76+
<tags>exclude_jshost</tags>
77+
</default>
78+
</test>
7279
<test>
7380
<default>
7481
<files>module-syntax.js</files>

0 commit comments

Comments
 (0)