Kaynağa Gözat

Fixes this, arguments, and super in async functions

Makes the inner generator function of an async function a lambda so that
it captures this, arguments, and super from its parent.

Generator lambdas are not supported by the language syntax but we can
create one internally without restriction.
Ian Halliday 10 yıl önce
ebeveyn
işleme
c70cd6cf9d

+ 5 - 0
lib/Parser/Parse.cpp

@@ -7259,6 +7259,10 @@ void Parser::TransformAsyncFncDeclAST(ParseNodePtr *pnodeBody, bool fLambda)
     {
         GetCurrentFunctionNode()->sxFnc.SetStrictMode();
     }
+    if (pnodeFncGenerator->sxFnc.UsesArguments())
+    {
+        GetCurrentFunctionNode()->sxFnc.SetUsesArguments();
+    }
     lastNodeRef = NULL;
 }
 
@@ -7277,6 +7281,7 @@ ParseNodePtr Parser::CreateAsyncSpawnGenerator()
     pnodeFncGenerator->sxFnc.SetStrictMode(IsStrictMode());
 
     pnodeFncGenerator->sxFnc.SetIsGenerator();
+    pnodeFncGenerator->sxFnc.SetIsLambda();
     pnodeFncGenerator->sxFnc.scope = nullptr;
 
     AppendFunctionToScopeList(false, pnodeFncGenerator);

+ 7 - 0
test/es7/asyncawait-functionality.baseline

@@ -14,6 +14,9 @@ Executing test #8 - Async function with default arguments's value
 Executing test #9 - Promise in an Async function
 Executing test #10 - %AsyncFunction% constructor creates async functions analogous to Function constructor
 Executing test #11 - local variables with same names as formal parameters have proper redeclaration semantics (non-error cases, var and function)
+Executing test #12 - this value in async functions behaves like it does in normal functions
+Executing test #13 - arguments value in async functions behaves like it does in normal functions
+Executing test #14 - super value in async methods behaves like it does in normal methods
 
 Completion Results:
 Test #1 - Success lambda expression with no argument called with result = 'true'
@@ -41,6 +44,10 @@ Test #8 - Success async function with default arguments's value has been rejecte
 Test #8 - Success async function with default arguments's value #3 called with result = 'true'
 Test #11 - Success inner var x overwrote formal parameter x only after the declaration statement
 Test #11 - Success inner function x() overwrote formal parameter x
+Test #12 - Success this value set to 5
+Test #12 - Success this value set to { af: af, b: "abc" }
+Test #13 - Success result is 'ab' from arguments 'a' + 'b'
+Test #14 - Success result is 'base derived' from derived method call
 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'

+ 89 - 2
test/es7/asyncawait-functionality.js

@@ -505,7 +505,7 @@ var tests = [
                 if (result === 'ab') {
                     echo(`Test #${index} - Success inner var x overwrote formal parameter x only after the declaration statement`);
                 } else {
-                    echo(`Test #${index} - Failure x appears to have an unexpected value x = ${x}`);
+                    echo(`Test #${index} - Failure x appears to have an unexpected value x = '${result}'`);
                 }
             }, err => {
                 echo(`Test #${index} - Error var redeclaration with err = ${err}`);
@@ -519,7 +519,94 @@ var tests = [
                 if (result === 'afx') {
                     echo(`Test #${index} - Success inner function x() overwrote formal parameter x`);
                 } else {
-                    echo(`Test #${index} - Failure x appears not assigned with inner function x(), x = ${x}`);
+                    echo(`Test #${index} - Failure x appears not assigned with inner function x(), x = '${result}'`);
+                }
+            }, err => {
+                echo(`Test #${index} - Error err = ${err}`);
+            }).catch(err => {
+                echo(`Test #${index} - Catch err = ${err}`);
+            });
+        }
+    },
+    {
+        name: "this value in async functions behaves like it does in normal functions",
+        body: function (index) {
+            async function af() {
+                return this;
+            }
+
+            af.call(5).then(result => {
+                if (result == 5) {
+                    echo(`Test #${index} - Success this value set to 5`);
+                } else {
+                    echo(`Test #${index} - Failure this value is not 5, this = '${result}'`);
+                }
+            }, err => {
+                echo(`Test #${index} - Error err = ${err}`);
+            }).catch(err => {
+                echo(`Test #${index} - Catch err = ${err}`);
+            });
+
+            var o = {
+                af: af,
+                b: "abc"
+            };
+
+            o.af().then(result => {
+                if (result.af === af && result.b === "abc") {
+                    echo(`Test #${index} - Success this value set to { af: af, b: "abc" }`);
+                } else {
+                    echo(`Test #${index} - Failure this value set to something else, this = '${result}'`);
+                }
+            }, err => {
+                echo(`Test #${index} - Error err = ${err}`);
+            }).catch(err => {
+                echo(`Test #${index} - Catch err = ${err}`);
+            });
+        }
+    },
+    {
+        name: "arguments value in async functions behaves like it does in normal functions",
+        body: function (index) {
+            async function af() {
+                return arguments[0] + arguments[1];
+            }
+
+            af('a', 'b').then(result => {
+                if (result === 'ab') {
+                    echo(`Test #${index} - Success result is 'ab' from arguments 'a' + 'b'`);
+                } else {
+                    echo(`Test #${index} - Failure result is not 'ab', result = '${result}'`);
+                }
+            }, err => {
+                echo(`Test #${index} - Error err = ${err}`);
+            }).catch(err => {
+                echo(`Test #${index} - Catch err = ${err}`);
+            });
+        }
+    },
+    {
+        name: "super value in async methods behaves like it does in normal methods",
+        body: function (index) {
+            class B {
+                af() {
+                    return "base";
+                }
+            }
+
+            class C extends B {
+                async af() {
+                    return super.af() + " derived";
+                }
+            }
+
+            var c = new C();
+
+            c.af().then(result => {
+                if (result === 'base derived') {
+                    echo(`Test #${index} - Success result is 'base derived' from derived method call`);
+                } else {
+                    echo(`Test #${index} - Failure result is not 'base derived', result = '${result}'`);
                 }
             }, err => {
                 echo(`Test #${index} - Error err = ${err}`);