diff --git a/lib/Runtime/Base/FunctionBody.cpp b/lib/Runtime/Base/FunctionBody.cpp index 06e2259c473..8166b1e41f8 100644 --- a/lib/Runtime/Base/FunctionBody.cpp +++ b/lib/Runtime/Base/FunctionBody.cpp @@ -5401,7 +5401,7 @@ namespace Js bool FunctionBody::CanFunctionObjectHaveInlineCaches() { - if (this->DoStackNestedFunc() || this->IsGenerator()) + if (this->DoStackNestedFunc() || this->IsCoroutine()) { return false; } @@ -6712,7 +6712,7 @@ namespace Js !this->IsInDebugMode() && DoInterpreterProfile() && (!IsNewSimpleJit() || DoInterpreterAutoProfile()) && - !IsGenerator(); // Generator JIT requires bailout which SimpleJit cannot do since it skips GlobOpt + !IsCoroutine(); // Generator JIT requires bailout which SimpleJit cannot do since it skips GlobOpt } bool FunctionBody::DoSimpleJitWithLock() const @@ -6723,7 +6723,7 @@ namespace Js !this->IsInDebugMode() && DoInterpreterProfileWithLock() && (!IsNewSimpleJit() || DoInterpreterAutoProfile()) && - !IsGenerator(); // Generator JIT requires bailout which SimpleJit cannot do since it skips GlobOpt + !IsCoroutine(); // Generator JIT requires bailout which SimpleJit cannot do since it skips GlobOpt } bool FunctionBody::DoSimpleJitDynamicProfile() const diff --git a/lib/Runtime/Base/FunctionBody.h b/lib/Runtime/Base/FunctionBody.h index 3c373e3630c..720c5bddc88 100644 --- a/lib/Runtime/Base/FunctionBody.h +++ b/lib/Runtime/Base/FunctionBody.h @@ -1346,7 +1346,7 @@ namespace Js bool IsJitLoopBodyPhaseEnabled() const { // Consider: Allow JitLoopBody in generator functions for loops that do not yield. - return !PHASE_OFF(JITLoopBodyPhase, this) && DoFullJit() && !this->IsGenerator(); + return !PHASE_OFF(JITLoopBodyPhase, this) && DoFullJit() && !this->IsCoroutine(); } bool IsJitLoopBodyPhaseForced() const diff --git a/lib/Runtime/ByteCode/ByteCodeGenerator.cpp b/lib/Runtime/ByteCode/ByteCodeGenerator.cpp index d6ca1a01aef..8de08848a1f 100644 --- a/lib/Runtime/ByteCode/ByteCodeGenerator.cpp +++ b/lib/Runtime/ByteCode/ByteCodeGenerator.cpp @@ -4163,7 +4163,7 @@ void Bind(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator) // VisitFunctionsInScope has already done binding within the declared function. Here, just record the fact // that the parent function has a local/global declaration in it. BindFuncSymbol(pnode, byteCodeGenerator); - if (pnode->sxFnc.IsGenerator()) + if (pnode->sxFnc.IsCoroutine()) { // Always assume generator functions escape since tracking them requires tracking // the resulting generators in addition to the function. @@ -4675,7 +4675,7 @@ void AssignRegisters(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator) case knopFncDecl: if (!byteCodeGenerator->TopFuncInfo()->IsGlobalFunction()) { - if (pnode->sxFnc.IsGenerator()) + if (pnode->sxFnc.IsCoroutine()) { // Assume generators always escape; otherwise need to analyze if // the return value of calls to generator function, the generator diff --git a/lib/Runtime/Language/AsmJs.cpp b/lib/Runtime/Language/AsmJs.cpp index 6963b5e76c9..9ad417bb686 100644 --- a/lib/Runtime/Language/AsmJs.cpp +++ b/lib/Runtime/Language/AsmJs.cpp @@ -59,10 +59,12 @@ namespace Js AsmJSCompiler::CheckFunctionHead(AsmJsModuleCompiler &m, ParseNode *fn, bool isGlobal /*= true*/) { PnFnc fnc = fn->sxFnc; + if (fnc.HasNonSimpleParameterList()) { return m.Fail(fn, _u("default & rest args not allowed")); } + if (fnc.IsStaticMember()) { return m.Fail(fn, _u("static functions are not allowed")); @@ -73,6 +75,11 @@ namespace Js return m.Fail(fn, _u("generator functions are not allowed")); } + if (fnc.IsAsync()) + { + return m.Fail(fn, _u("async functions are not allowed")); + } + if (fnc.IsLambda()) { return m.Fail(fn, _u("lambda functions are not allowed")); @@ -83,11 +90,6 @@ namespace Js return m.Fail(fn, _u("closure functions are not allowed")); } - if (fnc.HasDefaultArguments()) - { - return m.Fail(fn, _u("default arguments not allowed")); - } - return true; } diff --git a/lib/Runtime/Language/JavascriptStackWalker.cpp b/lib/Runtime/Language/JavascriptStackWalker.cpp index bd62d5bb24d..f0b6b925444 100644 --- a/lib/Runtime/Language/JavascriptStackWalker.cpp +++ b/lib/Runtime/Language/JavascriptStackWalker.cpp @@ -269,7 +269,7 @@ namespace Js } else #endif - if (this->GetCurrentFunction()->GetFunctionInfo()->IsGenerator()) + if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine()) { JavascriptGenerator* gen = JavascriptGenerator::FromVar(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]); return gen->GetArguments().Values; @@ -1016,7 +1016,7 @@ namespace Js // hidden frame display here? return (CallInfo const *)&inlinedFrameCallInfo; } - else if (this->GetCurrentFunction()->GetFunctionInfo()->IsGenerator()) + else if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine()) { JavascriptGenerator* gen = JavascriptGenerator::FromVar(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]); return &gen->GetArguments().Info; @@ -1042,7 +1042,7 @@ namespace Js Assert(!inlinedFramesBeingWalked); Assert(this->IsJavascriptFrame()); - if (this->GetCurrentFunction()->GetFunctionInfo()->IsGenerator()) + if (this->GetCurrentFunction()->GetFunctionInfo()->IsCoroutine()) { JavascriptGenerator* gen = JavascriptGenerator::FromVar(this->GetCurrentArgv()[JavascriptFunctionArgIndex_This]); return gen->GetArguments()[0]; diff --git a/lib/Runtime/Library/GlobalObject.cpp b/lib/Runtime/Library/GlobalObject.cpp index 1ea106fe29e..d15c4646503 100644 --- a/lib/Runtime/Library/GlobalObject.cpp +++ b/lib/Runtime/Library/GlobalObject.cpp @@ -995,7 +995,7 @@ namespace Js funcBody = funcBody->GetParseableFunctionInfo(); // RegisterFunction may parse and update function body } - ScriptFunction* pfuncScript = funcBody->IsGenerator() ? + ScriptFunction* pfuncScript = funcBody->IsCoroutine() ? scriptContext->GetLibrary()->CreateGeneratorVirtualScriptFunction(funcBody) : scriptContext->GetLibrary()->CreateScriptFunction(funcBody); diff --git a/lib/Runtime/Library/JavascriptFunction.cpp b/lib/Runtime/Library/JavascriptFunction.cpp index b507e8ee060..d3a7362d8d3 100644 --- a/lib/Runtime/Library/JavascriptFunction.cpp +++ b/lib/Runtime/Library/JavascriptFunction.cpp @@ -243,7 +243,7 @@ namespace Js { // Get the latest proxy FunctionProxy * proxy = pfuncBodyCache->GetFunctionProxy(); - if (proxy->IsGenerator()) + if (proxy->IsCoroutine()) { pfuncScript = scriptContext->GetLibrary()->CreateGeneratorVirtualScriptFunction(proxy); } diff --git a/test/es7/asyncawait-functionality.baseline b/test/es7/asyncawait-functionality.baseline index 48ac820d05e..5776e2e00a5 100644 --- a/test/es7/asyncawait-functionality.baseline +++ b/test/es7/asyncawait-functionality.baseline @@ -23,6 +23,15 @@ Executing test #17 - Async function with formal captured in eval Executing test #18 - Async function with formal capturing in param scope Executing test #19 - Async function with formal capturing in param scope with eval in the body Executing test #20 - Async function with duplicate variable decalration in the body with eval +Executing test #21 - Async function with duplicate variable decalration in the body with child having eval +Executing test #22 - Async function with more than one await +Executing test #23 - Async function with more than one await with branching +Executing test #24 - Async function with an exception in an await expression +Executing test #25 - Async functions throws on an await +Executing test #26 - Awaiting a function with multiple awaits +Executing test #27 - Async function with nested try-catch in the body +Executing test #28 - Async function with try-catch and try-finally in the body +Executing test #29 - Async function and with Completion Results: Test #1 - Success lambda expression with no argument called with result = 'true' @@ -61,6 +70,11 @@ Test #18 - Success function defined in the param scope captures the param scope Test #19 - Success inner function decalration captures the body variable with eval in the body Test #19 - Success function defined in the param scope captures the param scope variable with eval in the body Test #20 - Success inner variable decalration shadows the formal +Test #21 - Success inner variable decalration shadows the formal with eval in child function +Test #27 - Success Caught the expected exception inside the inner catch in async body +Test #27 - Success Caught the expected exception inside catch in async body +Test #28 - Success Caught the expected exception inside the inner catch in async body +Test #28 - Success finally block is executed in async body Test #6 - Success await in an async function #1 called with result = '-4' Test #6 - Success await in an async function #2 called with result = '2' Test #6 - Success await in an async function catch a rejected Promise in 'err'. Error = 'Error: My Error' @@ -69,7 +83,14 @@ Test #7 - Success await keyword with a lambda expressions #1 called with result Test #7 - Success await keyword with a lambda expressions #1 called with result = '60' Test #9 - Success resolved promise in an async function #2 called with result = 'resolved' Test #10 - Success %AsyncFunction% created async function #1 called with result = '0' +Test #23 - Success functions completes the first await call +Test #23 - Success functions completes the second await call +Test #24 - Success caught the expected exception +Test #25 - Success caught the expected exception Test #8 - Success async function with default arguments's value has been rejected as expected by 'err' #2 called with err = 'expected error' Test #9 - Success resolved promise in an async function #1 called with result = 'resolved' Test #9 - Success promise in an async function has been rejected as expected by 'err' #3 called with err = 'rejected' +Test #22 - Success functions completes both await calls +Test #29 - Success functions call inside with returns the right this object Test #10 - Success %AsyncFunction% created async function #2 called with result = '6' +Test #26 - Success Multiple awaits in the inner function completed diff --git a/test/es7/asyncawait-functionality.js b/test/es7/asyncawait-functionality.js index 0f958977293..a4e1ce3e81d 100644 --- a/test/es7/asyncawait-functionality.js +++ b/test/es7/asyncawait-functionality.js @@ -22,16 +22,12 @@ var tests = [ echo(`Test #${index} - Success lambda expression with no argument called with result = '${result}'`); }, err => { echo(`Test #${index} - Error lambda expression with no argument called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch lambda expression with no argument called with err = ${err}`); }); lambdaArgs(10, 20, 30).then(result => { echo(`Test #${index} - Success lambda expression with several arguments called with result = '${result}'`); }, err => { echo(`Test #${index} - Error lambda expression with several arguments called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch lambda expression with several arguments called with err = ${err}`); }); } }, @@ -46,16 +42,12 @@ var tests = [ echo(`Test #${index} - Success lambda expression with single argument and no paren called with result = '${result}'`); }, err => { echo(`Test #${index} - Error lambda expression with single argument and no paren called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch lambda expression with single argument and no paren called with err = ${err}`); }); lambdaSingleArg(x).then(result => { echo(`Test #${index} - Success lambda expression with a single argument a called with result = '${result}'`); }, err => { echo(`Test #${index} - Error lambda expression with a single argument called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch lambda expression with a single argument called with err = ${err}`); }); } }, @@ -74,16 +66,12 @@ var tests = [ echo(`Test #${index} - Success function #2 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error function #2 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch function #2 called with err = ${err}`); }); async(10, 20).then(result => { echo(`Test #${index} - Success function #3 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error function #3 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch function #3 called with err = ${err}`); }); } { @@ -93,8 +81,6 @@ var tests = [ echo(`Test #${index} - Success function #4 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error function #4 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch function #4 called with err = ${err}`); }); } { @@ -127,8 +113,6 @@ var tests = [ echo(`Test #${index} - Success function in a object #1 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error function in a object #1 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch function in a object #1 called with err = ${err}`); }); var result = object2.async(); @@ -138,32 +122,24 @@ var tests = [ echo(`Test #${index} - Success function in a object #3 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error function in a object #3 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch function in a object #3 called with err = ${err}`); }); object3['0']().then(result => { echo(`Test #${index} - Success function in a object #4 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error function in a object #4 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch function in a object #4 called with err = ${err}`); }); object3['3.14']().then(result => { echo(`Test #${index} - Success function in a object #5 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error function in a object #5 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch function in a object #5 called with err = ${err}`); }); object3.else().then(result => { echo(`Test #${index} - Success function in a object #6 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error function in a object #6 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch function in a object #6 called with err = ${err}`); }); } }, @@ -201,56 +177,42 @@ var tests = [ echo(`Test #${index} - Success async in a class #1 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error async in a class #1 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch async in a class #1 called with err = ${err}`); }); myClassInstance.async(10).then(result => { echo(`Test #${index} - Success async in a class #2 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error async in a class #2 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch async in a class #2 called with err = ${err}`); }); myClassInstance.a().then(result => { echo(`Test #${index} - Success async in a class #3 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error async in a class #3 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch async in a class #3 called with err = ${err}`); }); myClassInstance['0']().then(result => { echo(`Test #${index} - Success async in a class #4 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error async in a class #4 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch async in a class #4 called with err = ${err}`); }); myClassInstance['3.14']().then(result => { echo(`Test #${index} - Success async in a class #5 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error async in a class #5 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch async in a class #5 called with err = ${err}`); }); myClassInstance.else().then(result => { echo(`Test #${index} - Success async in a class #6 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error async in a class #6 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch async in a class #6 called with err = ${err}`); }); MyClass.staticAsyncMethod(10).then(result => { echo(`Test #${index} - Success async in a class #7 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error async in a class #7 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch async in a class #7 called with err = ${err}`); }); var result = mySecondClassInstance.async(10); @@ -263,8 +225,6 @@ var tests = [ echo(`Test #${index} - Success async in a class #10 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error async in a class #10 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch async in a class #10 called with err = ${err}`); }); } }, @@ -308,32 +268,24 @@ var tests = [ echo(`Test #${index} - Success await in an async function #1 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error await in an async function #1 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch await in an async function #1 called with err = ${err}`); }); secondAsyncMethod(2).then(result => { echo(`Test #${index} - Success await in an async function #2 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error await in an async function #2 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch await in an async function #2 called with err = ${err}`); }); rejectAwaitMethod(2).then(result => { echo(`Test #${index} - Failed await in an async function doesn't catch a rejected Promise. Result = '${result}'`); }, err => { echo(`Test #${index} - Success await in an async function catch a rejected Promise in 'err'. Error = '${err}'`); - }).catch(err => { - echo(`Test #${index} - Success await in an async function catch a rejected Promise in 'catch'. Error = '${err}'`); }); throwAwaitMethod(2).then(result => { echo(`Test #${index} - Failed await in an async function doesn't catch an error. Result = '${result}'`); }, err => { echo(`Test #${index} - Success await in an async function catch an error in 'err'. Error = '${err}'`); - }).catch(err => { - echo(`Test #${index} - Success await in an async function catch an error in 'catch'. Error = '${err}'`); }); } }, @@ -351,8 +303,6 @@ var tests = [ echo(`Test #${index} - Success await keyword with a lambda expressions #1 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error await keyword with a lambda expressions #1 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch await keyword with a lambda expressions #1 called with err = ${err}`); }); }; { @@ -364,8 +314,6 @@ var tests = [ echo(`Test #${index} - Success await keyword with a lambda expressions #1 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error await keyword with a lambda expressions #1 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch await keyword with a lambda expressions #1 called with err = ${err}`); }); }; } @@ -390,8 +338,6 @@ var tests = [ echo(`Test #${index} - Success async function with default arguments's value overwritten #1 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error async function with default arguments's value overwritten #1 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch async function with default arguments's value overwritten #1 called with err = ${err}`); }); // TODO:[aneeshd] Need to fix the default parameter evaluation order for both async functions and generators @@ -399,16 +345,12 @@ var tests = [ echo(`Test #${index} - Failed async function with default arguments's value has not been rejected as expected #2 called with result = '${result}'`); }, err => { echo(`Test #${index} - Success async function with default arguments's value has been rejected as expected by 'err' #2 called with err = '${err}'`); - }).catch(err => { - echo(`Test #${index} - Success async function with default arguments's value has been rejected as expected by 'catch' #2 called with err = '${err}'`); }); secondAsyncMethod().then(result => { echo(`Test #${index} - Success async function with default arguments's value #3 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error async function with default arguments's value #3 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch async function with default arguments's value #3 called with err = ${err}`); }); }; } @@ -449,24 +391,18 @@ var tests = [ echo(`Test #${index} - Success resolved promise in an async function #1 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error resolved promise in an async function #1 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch resolved promise in an async function #1 called with err = ${err}`); }); asyncMethodResolvedWithAwait().then(result => { echo(`Test #${index} - Success resolved promise in an async function #2 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error resolved promise in an async function #2 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch resolved promise in an async function #2 called with err = ${err}`); }); asyncMethodRejected().then(result => { echo(`Test #${index} - Failed promise in an async function has not been rejected as expected #3 called with result = '${result}'`); }, err => { echo(`Test #${index} - Success promise in an async function has been rejected as expected by 'err' #3 called with err = '${err}'`); - }).catch(err => { - echo(`Test #${index} - Success promise in an async function has been rejected as expected by 'catch' #3 called with err = '${err}'`); }); }; } @@ -482,8 +418,6 @@ var tests = [ echo(`Test #${index} - Success %AsyncFunction% created async function #1 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error %AsyncFunction% created async function #1 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch %AsyncFunction% created async function #1 called with err = ${err}`); }); af = new AsyncFunction('a', 'b', 'c', 'a = await a; b = await b; c = await c; return a + b + c;'); @@ -492,8 +426,6 @@ var tests = [ echo(`Test #${index} - Success %AsyncFunction% created async function #2 called with result = '${result}'`); }, err => { echo(`Test #${index} - Error %AsyncFunction% created async function #2 called with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch %AsyncFunction% created async function #2 called with err = ${err}`); }); } }, @@ -510,8 +442,6 @@ var tests = [ } }, err => { echo(`Test #${index} - Error var redeclaration with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch var redeclaration with err = ${err}`); }); async function af2(x) { var xx = x(); function x() { return 'afx'; } return xx; } @@ -524,8 +454,6 @@ var tests = [ } }, err => { echo(`Test #${index} - Error err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch err = ${err}`); }); } }, @@ -544,8 +472,6 @@ var tests = [ } }, err => { echo(`Test #${index} - Error err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch err = ${err}`); }); var o = { @@ -561,8 +487,6 @@ var tests = [ } }, err => { echo(`Test #${index} - Error err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch err = ${err}`); }); } }, @@ -581,8 +505,6 @@ var tests = [ } }, err => { echo(`Test #${index} - Error err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch err = ${err}`); }); } }, @@ -611,8 +533,6 @@ var tests = [ } }, err => { echo(`Test #${index} - Error err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch err = ${err}`); }); } }, @@ -631,8 +551,6 @@ var tests = [ } }, err => { print(`Test #${index} - Error err = ${err}`); - }).catch(err => { - print(`Test #${index} - Catch err = ${err}`); }); } }, @@ -651,8 +569,6 @@ var tests = [ } }, err => { print(`Test #${index} - Error err = ${err}`); - }).catch(err => { - print(`Test #${index} - Catch err = ${err}`); }); } }, @@ -671,8 +587,6 @@ var tests = [ } }, err => { print(`Test #${index} - Error err = ${err}`); - }).catch(err => { - print(`Test #${index} - Catch err = ${err}`); }); } }, @@ -700,8 +614,6 @@ var tests = [ } }, err => { echo(`Test #${index} - Error in split scope with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch in split scope with err = ${err}`); }); } }, @@ -729,8 +641,6 @@ var tests = [ } }, err => { echo(`Test #${index} - Error in split scope with eval in the body with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch in split scope with eval in the body with err = ${err}`); }); } }, @@ -750,8 +660,261 @@ var tests = [ } }, err => { echo(`Test #${index} - Error in variable redeclaration with eval with err = ${err}`); - }).catch(err => { - echo(`Test #${index} - Catch in variable redeclaration with eval with err = ${err}`); + }); + } + }, + { + name: "Async function with duplicate variable decalration in the body with child having eval", + body: function (index) { + async function af1(a, b) { + var a = 10; + return function () { return eval("a + b"); }; + } + + af1(1, 2).then(result => { + if (result() === 12) { + echo(`Test #${index} - Success inner variable decalration shadows the formal with eval in child function`); + } else { + echo(`Test #${index} - Failure sum appears to have an unexpected value sum = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error in variable redeclaration with eval with err = ${err}`); + }); + } + }, + { + name: "Async function with more than one await", + body: function (index) { + async function af1() { + return 1; + } + + async function af2() { + return 2; + } + + async function af3() { + return await af1() + await af2(); + } + af3().then(result => { + if (result === 3) { + echo(`Test #${index} - Success functions completes both await calls`); + } else { + echo(`Test #${index} - Failed function failed to complete both await calls and returned ${result}`); + } + }, err => { + echo(`Test #${index} - Error in multiple awaits in a function err = ${err}`); + }); + } + }, + { + name: "Async function with more than one await with branching", + body: function (index) { + async function af1() { + return 1; + } + + async function af2() { + return 2; + } + + async function af3(a) { + return a ? await af1() : await af2(); + } + + af3(1).then(result => { + if (result === 1) { + echo(`Test #${index} - Success functions completes the first await call`); + } else { + echo(`Test #${index} - Failed function failed to complete the first await call and returned ${result}`); + } + }, err => { + echo(`Test #${index} - Error in multiple awaits with branching in a function err = ${err}`); + }); + + af3().then(result => { + if (result === 2) { + echo(`Test #${index} - Success functions completes the second await call`); + } else { + echo(`Test #${index} - Failed function failed to complete the second await call and returned ${result}`); + } + }, err => { + echo(`Test #${index} - Error in multiple awaits with branching in a function err = ${err}`); + }); + } + }, + { + name: "Async function with an exception in an await expression", + body: function (index) { + var obj = { x : 1 }; + async function af1() { + throw obj; + } + + async function af2() { + echo(`Failed : This function was not expected to be executed`); + } + + async function af3() { + return await af1() + await af2(); + } + af3().then(result => { + echo(`Test #${index} - Error an expected exception does not seem to be thrown`); + }, err => { + if (err === obj) { + echo(`Test #${index} - Success caught the expected exception`); + } else { + echo(`Test #${index} - Error an unexpected exception was thrown = ${err}`); + } + }); + } + }, + { + name: "Async functions throws on an await", + body: function (index) { + var obj = { x : 1 }; + async function af1() { + throw obj; + } + + async function af2() { + echo(`Test #${index} Failed This function was not expected to be executed`); + } + + async function af3() { + return await af1() + await af2(); + } + + af3().then(result => { + print(`Test #${index} Failed an expected exception does not seem to be thrown`); + }, err => { + if (err === obj) { + print(`Test #${index} - Success caught the expected exception`); + } else { + print(`Test #${index} - Failed an unexpected exception was thrown = ${err}`); + } + }); + } + }, + { + name: "Awaiting a function with multiple awaits", + body: function (index) { + async function af1(a, b) { + return await af2(); + + async function af2() { + a = await a * a; + b = await b * b; + + return a + b; + } + } + + af1(1, 2).then(result => { + if (result === 5) { + echo(`Test #${index} - Success Multiple awaits in the inner function completed`); + } else { + echo(`Test #${index} - Failed function failed to complete the multiple awaits in the inner function ${result}`); + } + }, err => { + echo(`Test #${index} - Error in multiple awaits in an inner function err = ${err}`); + }); + } + }, + { + name: "Async function with nested try-catch in the body", + body: function (index) { + async function af1() { + throw 42; + } + + async function af2() { + try { + try { + await af1(); + } catch (e) { + echo(`Test #${index} - Success Caught the expected exception inside the inner catch in async body`); + throw e; + } + } catch (e) { + echo(`Test #${index} - Success Caught the expected exception inside catch in async body`); + throw e; + } + echo(`Test #${index} - Failed Didn't throw an expected exception`); + } + + af2().then(result => { + echo(`Test #${index} - Failed an the expected was not thrown`); + }, err => { + if (err.x === obj.x) { + echo(`Test #${index} - Success Caught the expected exception in the promise`); + } else { + echo(`Test #${index} - Failed Caught an unexpected exception in the promise ${error}`); + } + }); + } + }, + { + name: "Async function with try-catch and try-finally in the body", + body: function (index) { + async function af1() { + throw 42; + } + + async function af2() { + try { + try { + await af1(); + } catch (e) { + echo(`Test #${index} - Success Caught the expected exception inside the inner catch in async body`); + throw e; + } + } finally { + echo(`Test #${index} - Success finally block is executed in async body`); + } + echo(`Test #${index} - Failed Didn't throw an expected exception`); + } + + af2().then(result => { + echo(`Test #${index} - Failed an the expected was not thrown`); + }, err => { + if (err.x === obj.x) { + echo(`Test #${index} - Success Caught the expected exception in the promise`); + } else { + echo(`Test #${index} - Failed Caught an unexpected exception in the promise ${error}`); + } + }); + } + }, + { + name: "Async function and with", + body: function (index) { + var obj = { + async af() { + this.b = await this.a + 10; + return this; + }, + a : 1, + b : 0 + }; + + async function af(x) { + var x = 0; + with (obj) { + x = await af(); + } + + return x; + } + + af().then(result => { + if (result.a === 1 && result.b === 11) { + echo(`Test #${index} - Success functions call inside with returns the right this object`); + } else { + echo(`Test #${index} - Failed function failed to execute with inside an async function got ${result}`); + } + }, err => { + echo(`Test #${index} - Error in with construct inside an async method err = ${err}`); }); } },