浏览代码

Use correct deferred stubs for functions declared in parameter scope of function expression

We failed to shift the deferred stubs down to those belonging to the child function when parsing the argument list of a function expression.
Taylor Woll 7 年之前
父节点
当前提交
7a4826fa2c
共有 3 个文件被更改,包括 39 次插入7 次删除
  1. 27 6
      lib/Parser/Parse.cpp
  2. 1 0
      lib/Parser/Parse.h
  3. 11 1
      test/Bugs/deferredStubBugs.js

+ 27 - 6
lib/Parser/Parse.cpp

@@ -5463,8 +5463,15 @@ void Parser::ParseFncDeclHelper(ParseNodeFnc * pnodeFnc, LPCOLESTR pNameHint, us
                 m_reparsingLambdaParams = true;
             }
 
+            uint savedStubCount = m_currDeferredStubCount;
+            DeferredFunctionStub* savedStub = m_currDeferredStub;
+            ShiftCurrDeferredStubToChildFunction(pnodeFnc, pnodeFncParent);
+
             this->ParseFncFormals<buildAST>(pnodeFnc, pnodeFncParent, flags, isTopLevelDeferredFunc);
 
+            m_currDeferredStub = savedStub;
+            m_currDeferredStubCount = savedStubCount;
+
             m_reparsingLambdaParams = fLambdaParamsSave;
         }
 
@@ -5637,13 +5644,10 @@ void Parser::ParseFncDeclHelper(ParseNodeFnc * pnodeFnc, LPCOLESTR pNameHint, us
                 }
                 uint savedStubCount = m_currDeferredStubCount;
                 DeferredFunctionStub* savedStub = m_currDeferredStub;
-                if (pnodeFnc->IsNested() && pnodeFncSave != nullptr && m_currDeferredStub != nullptr && pnodeFncSave->ichMin != pnodeFnc->ichMin)
-                {
-                    DeferredFunctionStub* childStub = m_currDeferredStub + (pnodeFncSave->nestedCount - 1);
-                    m_currDeferredStubCount = childStub->nestedCount;
-                    m_currDeferredStub = childStub->deferredStubs;
-                }
+                ShiftCurrDeferredStubToChildFunction(pnodeFnc, pnodeFncSave);
+
                 this->FinishFncDecl(pnodeFnc, pNameHint, fLambda, skipFormals, fAllowIn);
+
                 m_currDeferredStub = savedStub;
                 m_currDeferredStubCount = savedStubCount;
             }
@@ -14021,6 +14025,23 @@ bool Parser::IsCreatingStateCache()
         && CONFIG_FLAG(ParserStateCache));
 }
 
+void Parser::ShiftCurrDeferredStubToChildFunction(ParseNodeFnc* pnodeFnc, ParseNodeFnc* pnodeFncParent)
+{
+    // Goal here is to shift the current deferred stub to point to the stubs for pnodeFnc
+    // so we may continue parsing pnodeFnc using the correct set of stubs instead of the
+    // stubs for pnodeFncParent.
+    // This function assumes we are in the middle of parsing pnodeFnc which is a child
+    // nested in pnodeFncParent.
+    if (pnodeFnc->IsNested() && pnodeFncParent != nullptr && m_currDeferredStub != nullptr && pnodeFncParent->ichMin != pnodeFnc->ichMin)
+    {
+        AssertOrFailFast(pnodeFncParent->nestedCount > 0);
+
+        DeferredFunctionStub* childStub = m_currDeferredStub + (pnodeFncParent->nestedCount - 1);
+        m_currDeferredStubCount = childStub->nestedCount;
+        m_currDeferredStub = childStub->deferredStubs;
+    }
+}
+
 uint Parser::BuildDeferredStubTreeHelper(ParseNodeBlock* pnodeBlock, DeferredFunctionStub* deferredStubs, uint currentStubIndex, uint deferredStubCount, Recycler *recycler)
 {
     Assert(pnodeBlock != nullptr

+ 1 - 0
lib/Parser/Parse.h

@@ -273,6 +273,7 @@ public:
 
 protected:
     static uint BuildDeferredStubTreeHelper(ParseNodeBlock* pnodeBlock, DeferredFunctionStub* deferredStubs, uint currentStubIndex, uint deferredStubCount, Recycler *recycler);
+    void ShiftCurrDeferredStubToChildFunction(ParseNodeFnc* pnodeFnc, ParseNodeFnc* pnodeFncParent);
 
     HRESULT ParseSourceInternal(
         __out ParseNodeProg ** parseTree, LPCUTF8 pszSrc, size_t offsetInBytes,

+ 11 - 1
test/Bugs/deferredStubBugs.js

@@ -26,7 +26,7 @@ var func5 = (a = 123) => (function v6() {
 })()
 func5();
 
-function func6(a = v => { console.log('pass'); }, b = v => { return a; }) {
+function func6(a = v => { console.log(pass); }, b = v => { return a; }) {
     function c() {
         return b();
     }
@@ -84,3 +84,13 @@ function func18(a = class A { meth() { return fail } static meth2() { return fai
     return c();
 }
 console.log(func18());
+
+function func19() {
+  return (function(a = { b() {} }){ return pass; })();
+}
+console.log(func19());
+
+function func20() {
+  return (function(a = { b() {} }, c = function() { return pass; }){ return c(); })();
+}
+console.log(func20());