diff --git a/hphp/compiler/analysis/class_scope.cpp b/hphp/compiler/analysis/class_scope.cpp index fe16f82b2..60653196c 100644 --- a/hphp/compiler/analysis/class_scope.cpp +++ b/hphp/compiler/analysis/class_scope.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -445,6 +447,7 @@ ClassScope::importTraitMethod(const TraitMethod& traitMethod, cloneMeth->getModifiers())); cloneMeth->resetScope(cloneFuncScope, true); cloneFuncScope->setOuterScope(shared_from_this()); + informClosuresAboutScopeClone(cloneMeth, cloneFuncScope, ar); cloneMeth->addTraitMethodToScope(ar, dynamic_pointer_cast(shared_from_this())); @@ -452,6 +455,34 @@ ClassScope::importTraitMethod(const TraitMethod& traitMethod, return cloneMeth; } +void ClassScope::informClosuresAboutScopeClone( + ConstructPtr root, + FunctionScopePtr outerScope, + AnalysisResultPtr ar) { + + if (!root) { + return; + } + + for (int i = 0; i < root->getKidCount(); i++) { + ConstructPtr cons = root->getNthKid(i); + ClosureExpressionPtr closure = + dynamic_pointer_cast(cons); + + if (!closure) { + informClosuresAboutScopeClone(cons, outerScope, ar); + continue; + } + + FunctionStatementPtr func = closure->getClosureFunction(); + HPHP::FunctionScopePtr funcScope = func->getFunctionScope(); + assert(funcScope->isClosure()); + funcScope->addClonedTraitOuterScope(outerScope); + // Don't need to recurse + } +} + + void ClassScope::addImportTraitMethod(const TraitMethod &traitMethod, const string &methName) { m_importMethToTraitMap[methName].push_back(traitMethod); diff --git a/hphp/compiler/analysis/class_scope.h b/hphp/compiler/analysis/class_scope.h index 1d432f733..7448615dd 100644 --- a/hphp/compiler/analysis/class_scope.h +++ b/hphp/compiler/analysis/class_scope.h @@ -437,6 +437,9 @@ private: void addImportTraitMethod(const TraitMethod &traitMethod, const std::string &methName); + void informClosuresAboutScopeClone(ConstructPtr root, + FunctionScopePtr outerScope, + AnalysisResultPtr ar); void setImportTraitMethodModifiers(const std::string &methName, ClassScopePtr traitCls, diff --git a/hphp/compiler/analysis/function_scope.cpp b/hphp/compiler/analysis/function_scope.cpp index afcedf19c..0f4f8ef50 100644 --- a/hphp/compiler/analysis/function_scope.cpp +++ b/hphp/compiler/analysis/function_scope.cpp @@ -410,6 +410,46 @@ bool FunctionScope::containsReference() const { return m_attribute & FileScope::ContainsReference; } +void FunctionScope::setContainsThis(bool f /* = true */) { + m_containsThis = f; + + BlockScopePtr bs(this->getOuterScope()); + while (bs && bs->is(BlockScope::FunctionScope)) { + FunctionScopePtr fs = static_pointer_cast(bs); + if (!fs->isClosure()) { + break; + } + fs->setContainsThis(f); + bs = bs->getOuterScope(); + } + + for (auto it = m_clonedTraitOuterScope.begin(); it != m_clonedTraitOuterScope.end(); it++) { + (*it)->setContainsThis(f); + } +} + +void FunctionScope::setContainsBareThis(bool f, bool ref /* = false */) { + if (f) { + m_containsBareThis |= ref ? 2 : 1; + } else { + m_containsBareThis = 0; + } + + BlockScopePtr bs(this->getOuterScope()); + while (bs && bs->is(BlockScope::FunctionScope)) { + FunctionScopePtr fs = static_pointer_cast(bs); + if (!fs->isClosure()) { + break; + } + fs->setContainsBareThis(f, ref); + bs = bs->getOuterScope(); + } + + for (auto it = m_clonedTraitOuterScope.begin(); it != m_clonedTraitOuterScope.end(); it++) { + (*it)->setContainsBareThis(f, ref); + } +} + bool FunctionScope::hasImpl() const { if (!isUserFunction()) { return !isAbstract(); diff --git a/hphp/compiler/analysis/function_scope.h b/hphp/compiler/analysis/function_scope.h index d9ce017f3..e4b6609ea 100644 --- a/hphp/compiler/analysis/function_scope.h +++ b/hphp/compiler/analysis/function_scope.h @@ -176,6 +176,13 @@ public: m_volatile = false; } + /** + * Tell this function about another outer scope that contains it. + */ + void addClonedTraitOuterScope(FunctionScopePtr scope) { + m_clonedTraitOuterScope.push_back(scope); + } + /** * Get/set original name of the function, without case being lowered. */ @@ -237,16 +244,10 @@ public: * Whether this function contains a usage of $this */ bool containsThis() const { return m_containsThis;} - void setContainsThis(bool f=true) { m_containsThis = f;} + void setContainsThis(bool f = true); bool containsBareThis() const { return m_containsBareThis; } bool containsRefThis() const { return m_containsBareThis & 2; } - void setContainsBareThis(bool f, bool ref = false) { - if (f) { - m_containsBareThis |= ref ? 2 : 1; - } else { - m_containsBareThis = 0; - } - } + void setContainsBareThis(bool f, bool ref = false); /** * How many parameters a caller should provide. */ @@ -492,6 +493,7 @@ private: ExpressionListPtr m_closureValues; ReadWriteMutex m_inlineMutex; unsigned m_nextID; // used when cloning generators for traits + std::list m_clonedTraitOuterScope; }; ///////////////////////////////////////////////////////////////////////////////