void CatchStatement::inferTypes(AnalysisResultPtr ar) { ClassScopePtr cls = ar->findClass(m_className); TypePtr type; m_valid = cls; if (!m_valid) { if (ar->isFirstPass()) { ConstructPtr self = shared_from_this(); ar->getCodeError()->record(self, CodeError::UnknownClass, self); } type = NEW_TYPE(Object); } else if (cls->isRedeclaring()) { type = NEW_TYPE(Object); } else { type = Type::CreateObjectType(m_className); } BlockScopePtr scope = ar->getScope(); VariableTablePtr variables = scope->getVariables(); variables->add(m_variable, type, false, ar, shared_from_this(), ModifierExpressionPtr(), false); if (ar->isFirstPass()) { FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope); if (func && variables->isParameter(m_variable)) { variables->addLvalParam(m_variable); } } if (m_stmt) m_stmt->inferTypes(ar); }
bool ListAssignment::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { ASSERT(m_array); if (!cg.inExpression()) return true; if (m_variables) { preOutputVariables(cg, ar, m_variables->hasEffect() || m_array->hasEffect() ? FixOrder : 0); } m_array->preOutputCPP(cg, ar, 0); bool isArray = false, notArray = false; if (TypePtr type = m_array->getActualType()) { isArray = type->is(Type::KindOfArray); notArray = type->isPrimitive() || type->is(Type::KindOfString) || type->is(Type::KindOfObject); } m_cppTemp = genCPPTemp(cg, ar); cg.wrapExpressionBegin(); if (outputLineMap(cg, ar)) cg_printf("0);\n"); cg_printf("CVarRef %s((", m_cppTemp.c_str()); m_array->outputCPP(cg, ar); cg_printf("));\n"); std::string tmp; if (notArray) { tmp = "null"; } else { tmp = genCPPTemp(cg, ar); bool need_ref = true; if (m_array->is(Expression::KindOfSimpleVariable)) { std::string name = static_pointer_cast<SimpleVariable>(m_array)->getName(); VariableTablePtr variables = getScope()->getVariables(); if (variables->isParameter(name) && !variables->isLvalParam(name)) { need_ref = false; } } cg_printf("Variant %s((", tmp.c_str()); if (need_ref) cg_printf("ref("); cg_printf("%s",m_cppTemp.c_str()); if (need_ref) cg_printf(")"); cg_printf("));\n"); if (!isArray) { cg_printf("if (!f_is_array(%s)) %s.unset();\n",tmp.c_str(), tmp.c_str()); } } outputCPPAssignment(cg, ar, tmp); return true; }
bool ObjectPropertyExpression::directVariantProxy(AnalysisResultPtr ar) { TypePtr actualType = m_object->getActualType(); if (actualType && actualType->is(Type::KindOfVariant)) { if (m_object->is(KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_object); const std::string &name = var->getName(); FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(ar->getScope()); VariableTablePtr variables = func->getVariables(); if (!variables->isParameter(name) || variables->isLvalParam(name)) { return true; } if (variables->getAttribute(VariableTable::ContainsDynamicVariable) || variables->getAttribute(VariableTable::ContainsExtract)) { return true; } } else { return true; } } return false; }
TypePtr UnaryOpExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { TypePtr et; // expected m_exp's type TypePtr rt; // return type switch (m_op) { case '!': et = rt = Type::Boolean; break; case '+': case '-': et = NEW_TYPE(Numeric); rt = NEW_TYPE(Numeric); break; case T_INC: case T_DEC: case '~': et = rt = NEW_TYPE(Primitive); break; case T_CLONE: et = rt = NEW_TYPE(Object); break; case '@': et = type; rt = Type::Variant; break; case '(': et = rt = type; break; case T_INT_CAST: et = rt = Type::Int64; break; case T_DOUBLE_CAST: et = rt = Type::Double; break; case T_STRING_CAST: et = rt = Type::String; break; case T_ARRAY: et = NEW_TYPE(Some); rt = Type::Array; break; case T_ARRAY_CAST: et = rt = Type::Array; break; case T_OBJECT_CAST: et = rt = NEW_TYPE(Object); break; case T_BOOL_CAST: et = rt = Type::Boolean; break; case T_UNSET_CAST: et = NEW_TYPE(Some); rt = Type::Variant; break; case T_EXIT: et = NEW_TYPE(Primitive); rt = Type::Variant; break; case T_PRINT: et = Type::String; rt = Type::Boolean; break; case T_ISSET: et = Type::Variant; rt = Type::Boolean; setExistContext(); break; case T_EMPTY: et = NEW_TYPE(Some); rt = Type::Boolean; setExistContext(); break; case T_INCLUDE: case T_INCLUDE_ONCE: case T_REQUIRE: case T_REQUIRE_ONCE: et = Type::String; rt = Type::Variant; break; case T_EVAL: et = Type::String; rt = NEW_TYPE(Any); ar->getScope()->getVariables()->forceVariants(ar); break; case T_FILE: et = rt = Type::String; break; default: ASSERT(false); } if (m_exp) { bool ecoerce = false; // expected type needs m_exp to coerce to switch (m_op) { case T_CLONE: case T_ISSET: ecoerce = true; default: break; } TypePtr expType = m_exp->inferAndCheck(ar, et, ecoerce); if (Type::SameType(expType, Type::String) && (m_op == T_INC || m_op == T_DEC)) { rt = expType = m_exp->inferAndCheck(ar, Type::Variant, true); } switch (m_op) { case '(': /* Need to make sure that type conversion happens at the right point. Without this, types are inferred differently: Consider (a+b)+1 and (a+b)."foo". In the first one, the "(" expression ends up with actualType int, in the second it ends up with actualType string. This is bad for cse, and type propagation (we rely on the fact that the same expression, with the same arguments, must have the same actual type). */ m_exp->setExpectedType(TypePtr()); rt = m_exp->getType(); break; case '+': case '-': if (Type::SameType(expType, Type::Int64) || Type::SameType(expType, Type::Double)) { rt = expType; } break; case T_INC: case T_DEC: if (m_exp->is(Expression::KindOfSimpleVariable)) { FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(ar->getScope()); if (func) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_exp); VariableTablePtr variables = ar->getScope()->getVariables(); const std::string &name = var->getName(); if (variables->isParameter(name)) { variables->addLvalParam(name); } } } // fall through case '~': if (Type::SameType(expType, Type::Int64) || Type::SameType(expType, Type::Double) || Type::SameType(expType, Type::String)) { rt = expType; } break; default: break; } } return rt; }
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { TypePtr ret; ConstructPtr construct = shared_from_this(); BlockScopePtr scope = ar->getScope(); VariableTablePtr variables = scope->getVariables(); // check function parameter that can occur in lval context if (m_context & (LValue | RefValue | UnsetContext | InvokeArgument)) { FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope); if (func) { if (variables->isParameter(m_name)) { variables->addLvalParam(m_name); } } } if (m_name == "this") { ClassScopePtr cls = getOriginalScope(ar); if (cls) { bool isStaticFunc = false; FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope); if (func->isStatic()) isStaticFunc = true; if (cls->isRedeclaring()) { ret = Type::Variant; } else { ret = Type::CreateObjectType(cls->getName()); } if (!isStaticFunc || (m_context & ObjectContext)) m_this = true; } } if ((m_context & (LValue|Declaration)) && !(m_context & ObjectContext)) { if (m_superGlobal) { ret = m_superGlobalType; } else if (m_superGlobalType) { // For system if (!m_this) { ret = variables->add(m_name, m_superGlobalType, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } } else { if (m_globals) { ret = Type::Variant; // this can happen with "unset($GLOBALS)" } else if (!m_this) { ret = variables->add(m_name, type, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } } } else { if (!m_this) { if (m_superGlobalType) { ret = m_superGlobalType; } else if (m_globals) { ret = Type::Array; } else if (scope->is(BlockScope::ClassScope)) { // ClassVariable expression will come to this block of code int properties; ret = variables->checkProperty(m_name, type, true, ar, construct, properties); } else { TypePtr tmpType = type; if (m_context & RefValue) { tmpType = Type::Variant; coerce = true; } int p; ret = variables->checkVariable(m_name, tmpType, coerce, ar, construct, p); } } } TypePtr actual = propagateTypes(ar, ret); setTypes(actual, type); if (Type::SameType(actual, ret)) { m_implementedType.reset(); } else { m_implementedType = ret; } return actual; }