Ver código fonte

Fixing the case when caller property points to a generator function

While calling another function from a generator function, the caller
property of that function should point to the generator function.
Currently we were walking the stack and returning the inner virtual function
which is not equivalent to the generator function.
Aneesh Divakarakurup 9 anos atrás
pai
commit
ad75aa9baf

+ 5 - 0
lib/Runtime/Library/JavascriptFunction.cpp

@@ -2622,6 +2622,11 @@ LABEL1:
                 // Caller of this function expects nullValue from the requestContext.
                 funcCaller = nullValue;
             }
+            if (ScriptFunction::Is(funcCaller))
+            {
+                // Is this is the internal function of a generator function then return the original generator function
+                funcCaller = ScriptFunction::FromVar(funcCaller)->GetRealFunctionObject();
+            }
         }
 
         return StackScriptFunction::EnsureBoxed(BOX_PARAM(funcCaller, nullptr, _u("caller")));

+ 17 - 0
test/es6/generators-functionality.js

@@ -1766,6 +1766,23 @@ var tests = [
             );
         }
     },
+    {
+        name: "generator function returned through caller property",
+        body: function () {
+            var func = function () {
+                return func.caller;
+            }
+            function* gf(flag, value) {
+                if (!flag) {
+                    yield func();
+                }
+                yield value * value;
+            }
+            var callergf = gf().next().value;
+            assert.areEqual(gf, callergf, "Generator function returned through the caller property should be the same as the original generator function");
+            assert.areEqual(100, callergf(true, 10).next().value, "Generator returned through the caller property should behave the same as the original generator function");
+        }
+    }
     // TODO: Test yield in expression positions of control flow constructs, e.g. initializer, condition, and increment of a for loop
 ];
 

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

@@ -33,6 +33,7 @@ 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
 Executing test #30 - Async and arguments.callee
+Executing test #31 - Async and arguments.caller
 
 Completion Results:
 Test #1 - Success lambda expression with no argument called with result = 'true'
@@ -89,10 +90,12 @@ 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 #31 - Success async function returned through caller property is the same as the original async function
 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 #31 - Success async function returned through caller property behaves the same way as the original async function
 Test #10 - Success %AsyncFunction% created async function #2 called with result = '6'
 Test #26 - Success Multiple awaits in the inner function completed

+ 39 - 0
test/es7/asyncawait-functionality.js

@@ -934,6 +934,45 @@ var tests = [
                 echo(`Test #${index} - Error async function and arguments.callee called with err = ${err}`);
             });
         }
+    },
+    {
+        name: "Async and arguments.caller",
+        body: function (index) {
+            var func = function () {
+                return func.caller;
+            }
+            async function asyncMethod(flag, value) {
+                if (!flag) {
+                    return await func();
+                }
+                return value * value;
+            }
+
+            asyncMethod().then(
+                result => {
+                    if (result === asyncMethod) {
+                        echo(`Test #${index} - Success async function returned through caller property is the same as the original async function`);
+                    } else {
+                        echo(`Test #${index} - Failed async function returned through the caller property is not the same as the original async function = ${result}`);
+                    }
+                    result(true, 10).then(
+                        r => {
+                            if (r === 100) {
+                                echo(`Test #${index} - Success async function returned through caller property behaves the same way as the original async function`);
+                            } else {
+                                echo(`Test #${index} - Failed async function returned through caller property behaves different from the original async function with value = ${r}`);
+                            }
+                        },
+                        e => {
+                            echo(`Test #${index} - Failed while trying to execute the async function returned through caller property with err = ${e}`);
+                        }
+                    );
+                },
+                error => {
+                    echo(`Test #${index} - Failed while trying to retrieve the async function through caller property with err = ${error}`);
+                }
+            )
+        }
     }
 ];