tell closures about scope clones
In HHBC mode, traits are flattened into their classes. When that happens, closures need to know about all the classes that contain them so that when we find a ##$this## inside the closure, it can tell EVERY containing scope to please propogate ##$this## down to me.
Esse commit está contido em:
@@ -25,6 +25,7 @@
|
||||
#include <compiler/analysis/variable_table.h>
|
||||
#include <compiler/construct.h>
|
||||
#include <compiler/expression/class_constant_expression.h>
|
||||
#include <compiler/expression/closure_expression.h>
|
||||
#include <compiler/expression/constant_expression.h>
|
||||
#include <compiler/expression/scalar_expression.h>
|
||||
#include <compiler/expression/unary_op_expression.h>
|
||||
@@ -32,6 +33,7 @@
|
||||
#include <compiler/option.h>
|
||||
#include <compiler/parser/parser.h>
|
||||
#include <compiler/statement/interface_statement.h>
|
||||
#include <compiler/statement/function_statement.h>
|
||||
#include <compiler/statement/method_statement.h>
|
||||
#include <compiler/statement/statement_list.h>
|
||||
#include <runtime/base/builtin_functions.h>
|
||||
@@ -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<ClassScope>(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<ClosureExpression>(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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<FunctionScope>(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<FunctionScope>(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();
|
||||
|
||||
@@ -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<FunctionScopeRawPtr> m_clonedTraitOuterScope;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário