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; }
TypePtr ParameterExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { ASSERT(type->is(Type::KindOfSome) || type->is(Type::KindOfAny)); TypePtr ret = getTypeSpec(ar); 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. VariableTablePtr variables = ar->getScope()->getVariables(); if (ar->isFirstPass()) { ret = variables->addParam(m_name, ret, ar, shared_from_this()); } else { // Functions that can be called dynamically have to have // variant parameters, even if they have a type hint if (ar->getFunctionScope()->isDynamic() || ar->getFunctionScope()->isRedeclaring() || ar->getFunctionScope()->isVirtual()) { variables->forceVariant(ar, m_name); } int p; ret = variables->checkVariable(m_name, ret, true, ar, shared_from_this(), p); if (ar->isSecondPass() && 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); ret = Type::Variant; } else if (ar->getPhase() == AnalysisResult::LastInference && !ret->getName().empty()) { addUserClass(ar, ret->getName(), true); } } return ret; }
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; }
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 }