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); }
void ClassVariable::onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr scope) { ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers); for (int i = 0; i < m_declaration->getCount(); i++) { VariableTablePtr variables = scope->getVariables(); ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr var = assignment->getVariable(); const std::string &name = dynamic_pointer_cast<SimpleVariable>(var)->getName(); if (variables->isPresent(name)) { Compiler::Error(Compiler::DeclaredVariableTwice, exp); m_declaration->removeElement(i--); } else { assignment->onParseRecur(ar, scope); } } else { const std::string &name = dynamic_pointer_cast<SimpleVariable>(exp)->getName(); if (variables->isPresent(name)) { Compiler::Error(Compiler::DeclaredVariableTwice, exp); m_declaration->removeElement(i--); } else { variables->add(name, Type::Variant, false, ar, exp, m_modifiers); } } } scope->setModifiers(modifiers); }
void ClassVariable::onParse(AnalysisResultPtr ar) { ModifierExpressionPtr modifiers = ar->getScope()->setModifiers(m_modifiers); for (int i = 0; i < m_declaration->getCount(); i++) { VariableTablePtr variables = ar->getScope()->getVariables(); ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr var = assignment->getVariable(); const std::string &name = dynamic_pointer_cast<SimpleVariable>(var)->getName(); if (variables->isPresent(name)) { ar->getCodeError()->record(CodeError::DeclaredVariableTwice, exp); } IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>(exp); ph->onParse(ar); } else { const std::string &name = dynamic_pointer_cast<SimpleVariable>(exp)->getName(); if (variables->isPresent(name)) { ar->getCodeError()->record(CodeError::DeclaredVariableTwice, exp); } variables->add(name, TypePtr(), false, ar, exp, m_modifiers); } } ar->getScope()->setModifiers(modifiers); }
void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) { m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name); m_superGlobalType = BuiltinSymbols::GetSuperGlobalType(m_name); VariableTablePtr variables = getScope()->getVariables(); if (m_superGlobal) { variables->setAttribute(VariableTable::NeedGlobalPointer); } else if (m_name == "GLOBALS") { m_globals = true; } else { m_sym = variables->addSymbol(m_name); } if (ar->getPhase() == AnalysisResult::AnalyzeAll) { if (FunctionScopePtr func = getFunctionScope()) { if (m_name == "this" && getClassScope()) { func->setContainsThis(); m_this = true; if (!hasContext(ObjectContext)) { func->setContainsBareThis(); if (variables->getAttribute(VariableTable::ContainsDynamicVariable)) { ClassScopePtr cls = getClassScope(); TypePtr t = cls->isRedeclaring() ? Type::Variant : Type::CreateObjectType(cls->getName()); variables->add(m_sym, t, true, ar, shared_from_this(), getScope()->getModifiers()); } } } if (m_sym && !(m_context & AssignmentLHS) && !((m_context & UnsetContext) && (m_context & LValue))) { m_sym->setUsed(); } } } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { if (m_sym && !m_sym->isSystem() && !(getContext() & (LValue|RefValue|RefParameter|UnsetContext|ExistContext)) && m_sym->getDeclaration().get() == this && !variables->getAttribute(VariableTable::ContainsLDynamicVariable) && !getScope()->is(BlockScope::ClassScope)) { if (getScope()->inPseudoMain()) { Compiler::Error(Compiler::UseUndeclaredGlobalVariable, shared_from_this()); } else { Compiler::Error(Compiler::UseUndeclaredVariable, shared_from_this()); } } } }
void ClassVariable::onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr scope) { ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers); if (m_modifiers->isAbstract()) { parseTimeFatal(Compiler::InvalidAttribute, "Properties cannot be declared abstract"); } if (m_modifiers->isFinal()) { parseTimeFatal(Compiler::InvalidAttribute, "Properties cannot be declared final"); } for (int i = 0; i < m_declaration->getCount(); i++) { VariableTablePtr variables = scope->getVariables(); ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr var = assignment->getVariable(); const std::string &name = dynamic_pointer_cast<SimpleVariable>(var)->getName(); if (variables->isPresent(name)) { exp->parseTimeFatal(Compiler::DeclaredVariableTwice, "Cannot redeclare %s::$%s", scope->getOriginalName().c_str(), name.c_str()); } else { assignment->onParseRecur(ar, scope); } } else { const std::string &name = dynamic_pointer_cast<SimpleVariable>(exp)->getName(); if (variables->isPresent(name)) { exp->parseTimeFatal(Compiler::DeclaredVariableTwice, "Cannot redeclare %s::$%s", scope->getOriginalName().c_str(), name.c_str()); } else { variables->add(name, Type::Null, false, ar, exp, m_modifiers); } } } scope->setModifiers(modifiers); }
TypePtr ParameterExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { ASSERT(type->is(Type::KindOfSome) || type->is(Type::KindOfAny)); TypePtr ret = getTypeSpec(ar, true); VariableTablePtr variables = getScope()->getVariables(); // Functions that can be called dynamically have to have // variant parameters, even if they have a type hint if (getFunctionScope()->isDynamic() || getFunctionScope()->isRedeclaring() || getFunctionScope()->isVirtual()) { if (Option::HardTypeHints && (ret->is(Type::KindOfArray) || ret->is(Type::KindOfObject))) { } else { variables->forceVariant(ar, m_name, VariableTable::AnyVars); ret = Type::Variant; } } if (m_defaultValue && !m_ref) { ret = m_defaultValue->inferAndCheck(ar, ret, false); } // parameters are like variables, but we need to remember these are // parameters so when variable table is generated, they are not generated // as declared variables. if (getScope()->isFirstPass()) { ret = variables->add(m_name, ret, false, ar, shared_from_this(), ModifierExpressionPtr()); } else { int p; ret = variables->checkVariable(m_name, ret, true, ar, shared_from_this(), p); if (ret->is(Type::KindOfSome)) { // This is probably too conservative. The problem is that // a function never called will have parameter types of Any. // Functions that it calls won't be able to accept variant unless // it is forced here. variables->forceVariant(ar, m_name, VariableTable::AnyVars); ret = Type::Variant; } } return ret; }
void ClassVariable::addTraitPropsToScope(AnalysisResultPtr ar, ClassScopePtr scope) { ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers); VariableTablePtr variables = scope->getVariables(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; SimpleVariablePtr var; ExpressionPtr value; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); value = assignment->getValue(); } else { var = dynamic_pointer_cast<SimpleVariable>(exp); value = makeConstant(ar, "null"); } const string &name = var->getName(); Symbol *sym; ClassScopePtr prevScope = variables->isPresent(name) ? scope : scope->getVariables()->findParent(ar, name, sym); if (prevScope && !isEquivRedecl(name, exp, m_modifiers, prevScope->getVariables()->getSymbol(name))) { Compiler::Error(Compiler::DeclaredVariableTwice, exp); m_declaration->removeElement(i--); } else { if (prevScope != scope) { // Property is new or override, so add it variables->add(name, Type::Variant, false, ar, exp, m_modifiers); variables->getSymbol(name)->setValue(exp); variables->setClassInitVal(name, value); variables->markOverride(ar, name); } else { m_declaration->removeElement(i--); } } } scope->setModifiers(modifiers); }
void BuiltinSymbols::ImportExtProperties(AnalysisResultPtr ar, VariableTablePtr dest, ClassInfo *cls) { ClassInfo::PropertyVec src = cls->getPropertiesVec(); for (auto it = src.begin(); it != src.end(); ++it) { ClassInfo::PropertyInfo *pinfo = *it; int attrs = pinfo->attribute; ModifierExpressionPtr modifiers( new ModifierExpression(BlockScopePtr(), LocationPtr())); if (attrs & ClassInfo::IsPrivate) { modifiers->add(T_PRIVATE); } else if (attrs & ClassInfo::IsProtected) { modifiers->add(T_PROTECTED); } if (attrs & ClassInfo::IsStatic) { modifiers->add(T_STATIC); } dest->add(pinfo->name.data(), typePtrFromDataType(pinfo->type, Type::Variant), false, ar, ExpressionPtr(), modifiers); } }
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { TypePtr ret; ConstructPtr construct = shared_from_this(); BlockScopePtr scope = getScope(); VariableTablePtr variables = scope->getVariables(); // check function parameter that can occur in lval context if (m_sym && m_sym->isParameter() && m_context & (LValue | RefValue | DeepReference | UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) { m_sym->setLvalParam(); } if (m_this) { ClassScopePtr cls = getOriginalClass(); if (!hasContext(ObjectContext) && cls->derivedByDynamic()) { ret = Type::Object; } else { ret = Type::CreateObjectType(cls->getName()); } if (!hasContext(ObjectContext) && variables->getAttribute(VariableTable::ContainsDynamicVariable)) { ret = variables->add(m_sym, ret, true, ar, construct, scope->getModifiers()); } } else if ((m_context & (LValue|Declaration)) && !(m_context & (ObjectContext|RefValue))) { if (m_globals) { ret = Type::Variant; } else if (m_superGlobal) { ret = m_superGlobalType; } else if (m_superGlobalType) { // For system ret = variables->add(m_sym, m_superGlobalType, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } else { ret = variables->add(m_sym, type, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } } else { 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 ret = getClassScope()->checkProperty(m_sym, type, true, ar); } else { TypePtr tmpType = type; if (m_context & RefValue) { tmpType = Type::Variant; coerce = true; } int p; ret = variables->checkVariable(m_sym, tmpType, coerce, ar, construct, p); } } TypePtr actual = propagateTypes(ar, ret); setTypes(ar, actual, type); if (Type::SameType(actual, ret)) { m_implementedType.reset(); } else { m_implementedType = ret; } return actual; }
/** * ArrayElementExpression comes from: * * reference_variable[|expr] * ->object_dim_list[|expr] * encaps T_VARIABLE[expr] * encaps ${T_STRING[expr]} */ TypePtr ArrayElementExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { ConstructPtr self = shared_from_this(); // handling $GLOBALS[...] if (m_variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable); if (var->getName() == "GLOBALS") { clearEffect(AccessorEffect); m_global = true; m_dynamicGlobal = true; ar->getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); VariableTablePtr vars = ar->getVariables(); if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) { ScalarExpressionPtr offset = dynamic_pointer_cast<ScalarExpression>(m_offset); if (offset->isLiteralString()) { m_globalName = offset->getIdentifier(); if (!m_globalName.empty()) { m_dynamicGlobal = false; ar->getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); TypePtr ret; ConstructPtr decl = vars->getDeclaration(m_globalName); if (decl) { ar->getDependencyGraph()-> add(DependencyGraph::KindOfGlobalVariable, ar->getName(), m_globalName, self, m_globalName, decl); } if (coerce) { ret = vars->add(m_globalName, type, true, ar, self, ModifierExpressionPtr()); } else { int p; ret = vars->checkVariable(m_globalName, type, coerce, ar, self, p); } ar->getScope()->getVariables()->addSuperGlobal(m_globalName); return ret; } } } else { vars->setAttribute(VariableTable::ContainsDynamicVariable); } if (hasContext(LValue) || hasContext(RefValue)) { if (ar->isFirstPass()) { ar->getCodeError()->record(self, CodeError::UseLDynamicVariable, self); } ar->getVariables()->forceVariants(ar); ar->getVariables()-> setAttribute(VariableTable::ContainsLDynamicVariable); } else { if (ar->isFirstPass()) { ar->getCodeError()->record(self, CodeError::UseRDynamicVariable, self); } } if (m_offset) { m_offset->inferAndCheck(ar, NEW_TYPE(Primitive), false); } return m_implementedType = Type::Variant; // so not to lose values } } if ((hasContext(LValue) || hasContext(RefValue)) && !hasContext(UnsetContext)) { m_variable->setContext(LValue); } TypePtr varType; if (m_offset) { varType = m_variable->inferAndCheck(ar, NEW_TYPE(Sequence), false); m_offset->inferAndCheck(ar, NEW_TYPE(Some), false); } else { if (hasContext(ExistContext) || hasContext(UnsetContext)) { if (ar->isFirstPass()) { ar->getCodeError()->record(self, CodeError::InvalidArrayElement, self); } } m_variable->inferAndCheck(ar, Type::Array, true); } if (varType && Type::SameType(varType, Type::String)) { clearEffect(AccessorEffect); m_implementedType.reset(); return Type::String; } if (varType && Type::SameType(varType, Type::Array)) { clearEffect(AccessorEffect); } if (hasContext(LValue) || hasContext(RefValue)) setEffect(CreateEffect); TypePtr ret = propagateTypes(ar, Type::Variant); m_implementedType = Type::Variant; return ret; // so not to lose values }
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope()); resetTypes(); TypePtr ret; ConstructPtr construct = shared_from_this(); BlockScopePtr scope = getScope(); VariableTablePtr variables = scope->getVariables(); // check function parameter that can occur in lval context if (m_sym && m_sym->isParameter() && m_context & (LValue | RefValue | DeepReference | UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) { m_sym->setLvalParam(); } if (coerce && m_sym && type && type->is(Type::KindOfAutoSequence)) { TypePtr t = m_sym->getType(); if (!t || t->is(Type::KindOfVoid) || t->is(Type::KindOfSome) || t->is(Type::KindOfArray)) { type = Type::Array; } } if (m_this) { ret = Type::Object; ClassScopePtr cls = getOriginalClass(); if (cls && (hasContext(ObjectContext) || !cls->derivedByDynamic())) { ret = Type::CreateObjectType(cls->getName()); } if (!hasContext(ObjectContext) && variables->getAttribute(VariableTable::ContainsDynamicVariable)) { if (variables->getAttribute(VariableTable::ContainsLDynamicVariable)) { ret = Type::Variant; } ret = variables->add(m_sym, ret, true, ar, construct, scope->getModifiers()); } } else if ((m_context & (LValue|Declaration)) && !(m_context & (ObjectContext|RefValue))) { if (m_globals) { ret = Type::Array; } else if (m_superGlobal) { ret = m_superGlobalType; } else if (m_superGlobalType) { // For system ret = variables->add(m_sym, m_superGlobalType, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } else { ret = variables->add(m_sym, type, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } } else { if (m_superGlobalType) { ret = m_superGlobalType; } else if (m_globals) { ret = Type::Array; } else if (scope->is(BlockScope::ClassScope)) { assert(getClassScope().get() == scope.get()); // ClassVariable expression will come to this block of code ret = getClassScope()->checkProperty(getScope(), m_sym, type, true, ar); } else { TypePtr tmpType = type; if (m_context & RefValue) { tmpType = Type::Variant; coerce = true; } ret = variables->checkVariable(m_sym, tmpType, coerce, ar, construct); if (ret && (ret->is(Type::KindOfSome) || ret->is(Type::KindOfAny))) { ret = Type::Variant; } } } // if m_assertedType is set, then this is a type assertion node TypePtr inType = m_assertedType ? GetAssertedInType(ar, m_assertedType, ret) : ret; TypePtr actual = propagateTypes(ar, inType); setTypes(ar, actual, type); if (Type::SameType(actual, ret)) { m_implementedType.reset(); } else { m_implementedType = ret; } return actual; }
void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) { m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name); m_superGlobalType = BuiltinSymbols::GetSuperGlobalType(m_name); VariableTablePtr variables = getScope()->getVariables(); if (m_superGlobal) { variables->setAttribute(VariableTable::NeedGlobalPointer); } else if (m_name == "GLOBALS") { m_globals = true; } else { m_sym = variables->addDeclaredSymbol(m_name, shared_from_this()); } if (ar->getPhase() == AnalysisResult::AnalyzeAll) { if (FunctionScopePtr func = getFunctionScope()) { if (m_name == "this" && func->mayContainThis()) { func->setContainsThis(); m_this = true; if (!hasContext(ObjectContext)) { bool unset = hasAllContext(UnsetContext | LValue); func->setContainsBareThis( true, hasAnyContext(RefValue | RefAssignmentLHS) || m_sym->isRefClosureVar() || unset); if (variables->getAttribute(VariableTable::ContainsDynamicVariable)) { ClassScopePtr cls = getClassScope(); TypePtr t = !cls || cls->isRedeclaring() ? Type::Variant : Type::CreateObjectType(cls->getName()); variables->add(m_sym, t, true, ar, shared_from_this(), getScope()->getModifiers()); } } } if (m_sym && !(m_context & AssignmentLHS) && !((m_context & UnsetContext) && (m_context & LValue))) { m_sym->setUsed(); } } } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { if (m_sym && !m_this) { if (!m_sym->isSystem() && !(getContext() & (LValue|RefValue|RefParameter|UnsetContext|ExistContext)) && m_sym->getDeclaration().get() == this) { assert(!m_sym->isParameter()); if (!variables->getAttribute(VariableTable::ContainsLDynamicVariable) && !getScope()->is(BlockScope::ClassScope)) { if (getScope()->inPseudoMain()) { Compiler::Error(Compiler::UseUndeclaredGlobalVariable, shared_from_this()); } else if (!m_sym->isClosureVar()) { Compiler::Error(Compiler::UseUndeclaredVariable, shared_from_this()); } } } // check function parameter that can occur in lval context if (m_sym->isParameter() && m_context & (LValue | RefValue | DeepReference | UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) { m_sym->setLvalParam(); } } } }
void ClassVariable::onParseRecur(AnalysisResultConstRawPtr ar, FileScopeRawPtr fs, ClassScopePtr scope) { ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers); if (m_modifiers->isAbstract()) { m_modifiers->parseTimeFatal(fs, Compiler::InvalidAttribute, "Properties cannot be declared abstract"); } if (m_modifiers->isFinal()) { m_modifiers->parseTimeFatal(fs, Compiler::InvalidAttribute, "Properties cannot be declared final"); } if (!m_modifiers->isStatic() && scope->isStaticUtil()) { m_modifiers->parseTimeFatal( fs, Compiler::InvalidAttribute, "Class %s contains non-static property declaration and " "therefore cannot be declared 'abstract final'", scope->getOriginalName().c_str() ); } if ((m_modifiers->isExplicitlyPublic() + m_modifiers->isProtected() + m_modifiers->isPrivate()) > 1) { m_modifiers->parseTimeFatal( fs, Compiler::InvalidAttribute, "%s: properties of %s", Strings::PICK_ACCESS_MODIFIER, scope->getOriginalName().c_str() ); } for (int i = 0; i < m_declaration->getCount(); i++) { VariableTablePtr variables = scope->getVariables(); ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { auto assignment = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr var = assignment->getVariable(); const auto& name = dynamic_pointer_cast<SimpleVariable>(var)->getName(); if (variables->isPresent(name)) { exp->parseTimeFatal(fs, Compiler::DeclaredVariableTwice, "Cannot redeclare %s::$%s", scope->getOriginalName().c_str(), name.c_str()); } else { assignment->onParseRecur(ar, fs, scope); } } else { const std::string &name = dynamic_pointer_cast<SimpleVariable>(exp)->getName(); if (variables->isPresent(name)) { exp->parseTimeFatal(fs, Compiler::DeclaredVariableTwice, "Cannot redeclare %s::$%s", scope->getOriginalName().c_str(), name.c_str()); } else { variables->add(name, false, ar, exp, m_modifiers); } } } scope->setModifiers(modifiers); }
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; }
/** * ArrayElementExpression comes from: * * reference_variable[|expr] * ->object_dim_list[|expr] * encaps T_VARIABLE[expr] * encaps ${T_STRING[expr]} */ TypePtr ArrayElementExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { ConstructPtr self = shared_from_this(); if (m_offset && !(m_context & (UnsetContext | ExistContext | InvokeArgument | LValue | RefValue))) { setEffect(DiagnosticEffect); } if (m_context & (AssignmentLHS|OprLValue)) { clearEffect(AccessorEffect); } else if (m_context & (LValue | RefValue)) { setEffect(CreateEffect); } // handling $GLOBALS[...] if (m_variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable); if (var->getName() == "GLOBALS") { clearEffect(AccessorEffect); m_global = true; m_dynamicGlobal = true; getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); VariableTablePtr vars = ar->getVariables(); if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) { ScalarExpressionPtr offset = dynamic_pointer_cast<ScalarExpression>(m_offset); if (offset->isLiteralString()) { m_globalName = offset->getIdentifier(); if (!m_globalName.empty()) { m_dynamicGlobal = false; clearEffect(DiagnosticEffect); getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); TypePtr ret; if (coerce) { ret = vars->add(m_globalName, type, true, ar, self, ModifierExpressionPtr()); } else { int p; ret = vars->checkVariable(m_globalName, type, coerce, ar, self, p); } getScope()->getVariables()->addSuperGlobal(m_globalName); return ret; } } } else { vars->setAttribute(VariableTable::ContainsDynamicVariable); } if (hasContext(LValue) || hasContext(RefValue)) { ar->getVariables()->forceVariants(ar, VariableTable::AnyVars); ar->getVariables()-> setAttribute(VariableTable::ContainsLDynamicVariable); } if (m_offset) { m_offset->inferAndCheck(ar, Type::Primitive, false); } return m_implementedType = Type::Variant; // so not to lose values } } if ((hasContext(LValue) || hasContext(RefValue)) && !hasContext(UnsetContext)) { m_variable->setContext(LValue); } TypePtr varType; if (m_offset) { varType = m_variable->inferAndCheck(ar, coerce ? Type::AutoSequence : Type::Sequence, coerce); m_offset->inferAndCheck(ar, Type::Some, false); } else { if (hasContext(ExistContext) || hasContext(UnsetContext)) { if (getScope()->isFirstPass()) { Compiler::Error(Compiler::InvalidArrayElement, self); } } m_variable->inferAndCheck(ar, Type::Array, true); } if (varType && Type::SameType(varType, Type::String)) { clearEffect(AccessorEffect); m_implementedType.reset(); return Type::String; } if (varType && Type::SameType(varType, Type::Array)) { clearEffect(AccessorEffect); } TypePtr ret = propagateTypes(ar, Type::Variant); m_implementedType = Type::Variant; return ret; // so not to lose values }