make #includes consistent
[hiphop-php.git] / hphp / compiler / expression / simple_variable.cpp
blob1e994a35b0411865722a54af8386bda32c04aa86
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
27 using namespace HPHP;
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);
47 return exp;
50 ///////////////////////////////////////////////////////////////////////////////
51 // parser functions
53 ///////////////////////////////////////////////////////////////////////////////
54 // static analysis functions
56 void SimpleVariable::setContext(Context context) {
57 m_context |= context;
58 if (m_this) {
59 bool ref = context & (RefValue | RefAssignmentLHS);
60 bool unset = ((context & Expression::UnsetContext) &&
61 (context & Expression::LValue));
62 if (ref || unset) {
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()) {
73 return LocalEffect;
75 return NoEffect;
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;
87 always_assert(m_sym);
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) {
99 always_assert(m_sym);
100 always_assert(other->m_sym);
101 if (!m_originalSym) m_originalSym = m_sym;
102 m_sym->clearUsed();
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();
111 return (needsCont &&
112 m_name != CONTINUATION_OBJECT_NAME &&
113 !isHidden) ?
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();
129 return
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();
139 if (m_superGlobal) {
140 variables->setAttribute(VariableTable::NeedGlobalPointer);
141 } else if (m_name == "GLOBALS") {
142 m_globals = true;
143 } else {
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();
151 m_this = true;
152 if (!hasContext(ObjectContext)) {
153 bool unset = hasAllContext(UnsetContext | LValue);
154 func->setContainsBareThis(
155 true,
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))) {
169 m_sym->setUsed();
172 } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
173 if (m_sym && !m_this) {
174 if (!m_sym->isSystem() &&
175 !(getContext() &
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,
182 shared_from_this());
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 |
191 DeepOprLValue)) {
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,
204 bool coerce) {
205 assert(false);
206 return TypePtr();
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,
216 TypePtr ret) {
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,
227 bool coerce) {
228 IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());
230 resetTypes();
231 TypePtr ret;
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)) {
247 type = Type::Array;
251 if (m_this) {
252 ret = Type::Object;
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)) {
260 ret = Type::Variant;
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))) {
267 if (m_globals) {
268 ret = Type::Array;
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());
275 } else {
276 ret = variables->add(m_sym, type,
277 ((m_context & Declaration) != Declaration), ar,
278 construct, scope->getModifiers());
280 } else {
281 if (m_superGlobalType) {
282 ret = m_superGlobalType;
283 } else if (m_globals) {
284 ret = Type::Array;
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);
289 } else {
290 TypePtr tmpType = type;
291 if (m_context & RefValue) {
292 tmpType = Type::Variant;
293 coerce = true;
295 ret = variables->checkVariable(m_sym, tmpType, coerce, ar, construct);
296 if (ret && (ret->is(Type::KindOfSome) || ret->is(Type::KindOfAny))) {
297 ret = Type::Variant;
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();
309 } else {
310 m_implementedType = ret;
312 return actual;
315 ///////////////////////////////////////////////////////////////////////////////
316 // code generation functions
318 void SimpleVariable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
319 cg_printf("$%s", m_name.c_str());