2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/compiler/expression/simple_variable.h"
18 #include "hphp/compiler/analysis/function_scope.h"
19 #include "hphp/compiler/analysis/variable_table.h"
20 #include "hphp/compiler/analysis/class_scope.h"
21 #include "hphp/compiler/option.h"
22 #include "hphp/compiler/builtin_symbols.h"
23 #include "hphp/compiler/expression/scalar_expression.h"
24 #include "hphp/util/parser/hphp.tab.hpp"
25 #include "hphp/util/parser/parser.h"
29 ///////////////////////////////////////////////////////////////////////////////
30 // constructors/destructors
32 SimpleVariable::SimpleVariable
33 (EXPRESSION_CONSTRUCTOR_PARAMETERS
,
34 const std::string
&name
,
35 const std::string
&docComment
/* = "" */)
36 : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(SimpleVariable
)),
37 m_name(name
), m_docComment(docComment
),
38 m_sym(nullptr), m_originalSym(nullptr),
39 m_this(false), m_globals(false),
40 m_superGlobal(false), m_alwaysStash(false) {
41 setContext(Expression::NoLValueWrapper
);
44 ExpressionPtr
SimpleVariable::clone() {
45 SimpleVariablePtr
exp(new SimpleVariable(*this));
46 Expression::deepCopy(exp
);
50 ///////////////////////////////////////////////////////////////////////////////
53 ///////////////////////////////////////////////////////////////////////////////
54 // static analysis functions
56 void SimpleVariable::setContext(Context context
) {
59 bool ref
= context
& (RefValue
| RefAssignmentLHS
);
60 bool unset
= ((context
& Expression::UnsetContext
) &&
61 (context
& Expression::LValue
));
63 if (FunctionScopePtr func
= getFunctionScope()) {
64 func
->setContainsBareThis(true, true);
70 int SimpleVariable::getLocalEffects() const {
71 if (m_context
== Declaration
&&
72 m_sym
&& m_sym
->isShrinkWrapped()) {
78 void SimpleVariable::updateSymbol(SimpleVariablePtr src
) {
79 m_sym
= getScope()->getVariables()->addSymbol(m_name
);
80 if (src
&& src
->m_sym
) {
81 m_sym
->update(src
->m_sym
);
85 bool SimpleVariable::couldBeAliased() const {
86 if (m_globals
|| m_superGlobal
) return true;
88 if (m_sym
->isGlobal() || m_sym
->isStatic()) return true;
89 if (getScope()->inPseudoMain() && !m_sym
->isHidden()) return true;
90 if (isReferencedValid()) return isReferenced();
91 return m_sym
->isReferenced();
94 bool SimpleVariable::isHidden() const {
95 return m_sym
&& m_sym
->isHidden();
98 void SimpleVariable::coalesce(SimpleVariablePtr other
) {
100 always_assert(other
->m_sym
);
101 if (!m_originalSym
) m_originalSym
= m_sym
;
103 m_sym
->clearNeeded();
104 m_sym
= other
->m_sym
;
105 m_name
= m_sym
->getName();
108 string
SimpleVariable::getNamePrefix() const {
109 bool needsCont
= getFunctionScope()->isGenerator();
110 bool isHidden
= m_sym
&& m_sym
->isHidden();
112 m_name
!= CONTINUATION_OBJECT_NAME
&&
114 string(TYPED_CONTINUATION_OBJECT_NAME
) + "->" : string("");
118 This simple variable is about to go out of scope.
119 Is it ok to kill the last assignment?
120 What if its a reference assignment (or an unset)?
122 bool SimpleVariable::canKill(bool isref
) const {
123 if (m_globals
|| m_superGlobal
) return false;
124 always_assert(m_sym
);
125 if (m_sym
->isGlobal() || m_sym
->isStatic()) {
126 return isref
&& !getScope()->inPseudoMain();
130 (isref
&& (m_sym
->isHidden() || !getScope()->inPseudoMain())) ||
131 (isReferencedValid() ? !isReferenced() : !m_sym
->isReferenced());
134 void SimpleVariable::analyzeProgram(AnalysisResultPtr ar
) {
135 m_superGlobal
= BuiltinSymbols::IsSuperGlobal(m_name
);
136 m_superGlobalType
= BuiltinSymbols::GetSuperGlobalType(m_name
);
138 VariableTablePtr variables
= getScope()->getVariables();
140 variables
->setAttribute(VariableTable::NeedGlobalPointer
);
141 } else if (m_name
== "GLOBALS") {
144 m_sym
= variables
->addDeclaredSymbol(m_name
, shared_from_this());
147 if (ar
->getPhase() == AnalysisResult::AnalyzeAll
) {
148 if (FunctionScopePtr func
= getFunctionScope()) {
149 if (m_name
== "this" && func
->mayContainThis()) {
150 func
->setContainsThis();
152 if (!hasContext(ObjectContext
)) {
153 bool unset
= hasAllContext(UnsetContext
| LValue
);
154 func
->setContainsBareThis(
156 hasAnyContext(RefValue
| RefAssignmentLHS
) ||
157 m_sym
->isRefClosureVar() || unset
);
158 if (variables
->getAttribute(VariableTable::ContainsDynamicVariable
)) {
159 ClassScopePtr cls
= getClassScope();
160 TypePtr t
= !cls
|| cls
->isRedeclaring() ?
161 Type::Variant
: Type::CreateObjectType(cls
->getName());
162 variables
->add(m_sym
, t
, true, ar
, shared_from_this(),
163 getScope()->getModifiers());
167 if (m_sym
&& !(m_context
& AssignmentLHS
) &&
168 !((m_context
& UnsetContext
) && (m_context
& LValue
))) {
172 } else if (ar
->getPhase() == AnalysisResult::AnalyzeFinal
) {
173 if (m_sym
&& !m_this
) {
174 if (!m_sym
->isSystem() &&
176 (LValue
|RefValue
|RefParameter
|UnsetContext
|ExistContext
)) &&
177 m_sym
->getDeclaration().get() == this &&
178 !variables
->getAttribute(VariableTable::ContainsLDynamicVariable
) &&
179 !getScope()->is(BlockScope::ClassScope
)) {
180 if (getScope()->inPseudoMain()) {
181 Compiler::Error(Compiler::UseUndeclaredGlobalVariable
,
183 } else if (!m_sym
->isClosureVar()) {
184 Compiler::Error(Compiler::UseUndeclaredVariable
, shared_from_this());
187 // check function parameter that can occur in lval context
188 if (m_sym
->isParameter() &&
189 m_context
& (LValue
| RefValue
| DeepReference
|
190 UnsetContext
| InvokeArgument
| OprLValue
|
192 m_sym
->setLvalParam();
198 bool SimpleVariable::canonCompare(ExpressionPtr e
) const {
199 return Expression::canonCompare(e
) &&
200 getName() == static_cast<SimpleVariable
*>(e
.get())->getName();
203 TypePtr
SimpleVariable::inferTypes(AnalysisResultPtr ar
, TypePtr type
,
209 bool SimpleVariable::checkUnused() const {
210 return !m_superGlobal
&& !m_globals
&&
211 getScope()->getVariables()->checkUnused(m_sym
);
214 static inline TypePtr
GetAssertedInType(AnalysisResultPtr ar
,
215 TypePtr assertedType
,
217 assert(assertedType
);
218 if (!ret
) return assertedType
;
219 TypePtr res
= Type::Inferred(ar
, ret
, assertedType
);
220 // if the asserted type and the symbol table type are compatible, then use
221 // the result of Inferred() (which is at least as strict as assertedType).
222 // otherwise, go with the asserted type
223 return res
? res
: assertedType
;
226 TypePtr
SimpleVariable::inferAndCheck(AnalysisResultPtr ar
, TypePtr type
,
228 IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());
232 ConstructPtr construct
= shared_from_this();
233 BlockScopePtr scope
= getScope();
234 VariableTablePtr variables
= scope
->getVariables();
236 // check function parameter that can occur in lval context
237 if (m_sym
&& m_sym
->isParameter() &&
238 m_context
& (LValue
| RefValue
| DeepReference
|
239 UnsetContext
| InvokeArgument
| OprLValue
| DeepOprLValue
)) {
240 m_sym
->setLvalParam();
243 if (coerce
&& m_sym
&& type
&& type
->is(Type::KindOfAutoSequence
)) {
244 TypePtr t
= m_sym
->getType();
245 if (!t
|| t
->is(Type::KindOfVoid
) ||
246 t
->is(Type::KindOfSome
) || t
->is(Type::KindOfArray
)) {
253 ClassScopePtr cls
= getOriginalClass();
254 if (cls
&& (hasContext(ObjectContext
) || !cls
->derivedByDynamic())) {
255 ret
= Type::CreateObjectType(cls
->getName());
257 if (!hasContext(ObjectContext
) &&
258 variables
->getAttribute(VariableTable::ContainsDynamicVariable
)) {
259 if (variables
->getAttribute(VariableTable::ContainsLDynamicVariable
)) {
262 ret
= variables
->add(m_sym
, ret
, true, ar
,
263 construct
, scope
->getModifiers());
265 } else if ((m_context
& (LValue
|Declaration
)) &&
266 !(m_context
& (ObjectContext
|RefValue
))) {
269 } else if (m_superGlobal
) {
270 ret
= m_superGlobalType
;
271 } else if (m_superGlobalType
) { // For system
272 ret
= variables
->add(m_sym
, m_superGlobalType
,
273 ((m_context
& Declaration
) != Declaration
), ar
,
274 construct
, scope
->getModifiers());
276 ret
= variables
->add(m_sym
, type
,
277 ((m_context
& Declaration
) != Declaration
), ar
,
278 construct
, scope
->getModifiers());
281 if (m_superGlobalType
) {
282 ret
= m_superGlobalType
;
283 } else if (m_globals
) {
285 } else if (scope
->is(BlockScope::ClassScope
)) {
286 assert(getClassScope().get() == scope
.get());
287 // ClassVariable expression will come to this block of code
288 ret
= getClassScope()->checkProperty(getScope(), m_sym
, type
, true, ar
);
290 TypePtr tmpType
= type
;
291 if (m_context
& RefValue
) {
292 tmpType
= Type::Variant
;
295 ret
= variables
->checkVariable(m_sym
, tmpType
, coerce
, ar
, construct
);
296 if (ret
&& (ret
->is(Type::KindOfSome
) || ret
->is(Type::KindOfAny
))) {
302 // if m_assertedType is set, then this is a type assertion node
303 TypePtr inType
= m_assertedType
?
304 GetAssertedInType(ar
, m_assertedType
, ret
) : ret
;
305 TypePtr actual
= propagateTypes(ar
, inType
);
306 setTypes(ar
, actual
, type
);
307 if (Type::SameType(actual
, ret
)) {
308 m_implementedType
.reset();
310 m_implementedType
= ret
;
315 ///////////////////////////////////////////////////////////////////////////////
316 // code generation functions
318 void SimpleVariable::outputPHP(CodeGenerator
&cg
, AnalysisResultPtr ar
) {
319 cg_printf("$%s", m_name
.c_str());