TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar, TypePtr type, bool coerce, FunctionScopePtr func) { ConstructPtr self = shared_from_this(); ar->getDependencyGraph()->add(DependencyGraph::KindOfFunctionCall, ar->getName(), getText(), self, func->getFullName(), func->getStmt()); TypePtr frt = func->getReturnType(); if (!frt) { m_voidReturn = true; setActualType(TypePtr()); if (!type->is(Type::KindOfAny)) { if (!m_allowVoidReturn && ar->isSecondPass() && !func->isAbstract()) { ar->getCodeError()->record(self, CodeError::UseVoidReturn, self); } m_voidWrapper = true; } } else { m_voidReturn = false; m_voidWrapper = false; type = checkTypesImpl(ar, type, frt, coerce); } m_extraArg = func->inferParamTypes(ar, self, m_params, m_valid); m_variableArgument = func->isVariableArgument(); if (m_valid) { m_implementedType.reset(); } else { m_implementedType = Type::Variant; } return type; }
TypePtr NewObjectExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { reset(); ConstructPtr self = shared_from_this(); if (!m_name.empty()) { ClassScopePtr cls = ar->resolveClass(m_name); if (cls) { m_name = cls->getName(); } if (!cls || cls->isRedeclaring()) { if (cls) { m_redeclared = true; ar->getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); } if (!cls && ar->isFirstPass()) { ar->getCodeError()->record(self, CodeError::UnknownClass, self); } if (m_params) m_params->inferAndCheck(ar, NEW_TYPE(Any), false); return NEW_TYPE(Object); } if (cls->isVolatile()) { ar->getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); } m_dynamic = cls->derivesFromRedeclaring(); m_validClass = true; FunctionScopePtr func = cls->findConstructor(ar, true); if (!func) { if (m_params) { if (!m_dynamic && m_params->getCount()) { if (ar->isFirstPass()) { ar->getCodeError()->record(self, CodeError::BadConstructorCall, self); } m_params->setOutputCount(0); } m_params->inferAndCheck(ar, NEW_TYPE(Any), false); } } else { m_extraArg = func->inferParamTypes(ar, self, m_params, m_validClass); m_variableArgument = func->isVariableArgument(); } return Type::CreateObjectType(m_name); } else { ar->containsDynamicClass(); if (ar->isFirstPass()) { ar->getCodeError()->record(self, CodeError::UseDynamicClass, self); } if (m_params) { m_params->markParams(false); } } m_nameExp->inferAndCheck(ar, Type::String, false); if (m_params) m_params->inferAndCheck(ar, NEW_TYPE(Any), false); return Type::Variant;//NEW_TYPE(Object); }
TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar, TypePtr type, bool coerce, FunctionScopePtr func, bool arrayParams) { ConstructPtr self = shared_from_this(); TypePtr frt = func->getReturnType(); if (!frt) { m_voidReturn = true; setActualType(TypePtr()); if (!type->is(Type::KindOfAny)) { if (!m_allowVoidReturn && !func->isFirstPass() && !func->isAbstract()) { Compiler::Error(Compiler::UseVoidReturn, self); } m_voidWrapper = true; } } else { m_voidReturn = false; m_voidWrapper = false; type = checkTypesImpl(ar, type, frt, coerce); } if (arrayParams) { m_extraArg = 0; (*m_params)[0]->inferAndCheck(ar, Type::Array, false); } else { m_extraArg = func->inferParamTypes(ar, self, m_params, m_valid); } m_variableArgument = func->isVariableArgument(); if (m_valid) { m_implementedType.reset(); } else { m_implementedType = Type::Variant; } return type; }
TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar, TypePtr type, bool coerce, FunctionScopePtr func, bool arrayParams) { #ifdef HPHP_DETAILED_TYPE_INF_ASSERT assert(func->hasUser(getScope(), BlockScope::UseKindCaller)); #endif /* HPHP_DETAILED_TYPE_INF_ASSERT */ ConstructPtr self = shared_from_this(); TypePtr frt; { TRY_LOCK(func); func->getInferTypesMutex().assertOwnedBySelf(); assert(!func->inVisitScopes() || getScope() == func); frt = func->getReturnType(); } if (!frt) { m_voidReturn = true; setActualType(TypePtr()); if (!isUnused() && !type->is(Type::KindOfAny)) { if (!hasContext(ReturnContext) && !func->isFirstPass() && !func->isAbstract()) { if (Option::WholeProgram || !func->getContainingClass() || func->isStatic() || func->isFinal() || func->isPrivate()) { Compiler::Error(Compiler::UseVoidReturn, self); } } if (!Type::IsMappedToVariant(type)) { setExpectedType(type); } m_voidWrapper = true; } } else { m_voidReturn = false; m_voidWrapper = false; type = checkTypesImpl(ar, type, frt, coerce); assert(m_actualType); } if (arrayParams) { m_extraArg = 0; (*m_params)[0]->inferAndCheck(ar, Type::Array, false); } else { m_extraArg = func->inferParamTypes(ar, self, m_params, m_valid); } m_variableArgument = func->isVariableArgument(); if (m_valid) { m_implementedType.reset(); } else { m_implementedType = Type::Variant; } assert(type); return type; }
TypePtr NewObjectExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { reset(); m_classScope.reset(); m_funcScope.reset(); ConstructPtr self = shared_from_this(); if (!m_name.empty()) { ClassScopePtr cls = resolveClass(getScope()); m_name = m_className; if (!cls) { if (isRedeclared()) { getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); } else if (getScope()->isFirstPass()) { Compiler::Error(Compiler::UnknownClass, self); } if (m_params) m_params->inferAndCheck(ar, Type::Any, false); return Type::Object; } if (cls->isVolatile() && !isPresent()) { getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); } m_dynamic = cls->derivesFromRedeclaring(); bool valid = true; FunctionScopePtr func = cls->findConstructor(ar, true); if (!func) { if (m_params) { if (!m_dynamic && m_params->getCount()) { if (getScope()->isFirstPass()) { Compiler::Error(Compiler::BadConstructorCall, self); } m_params->setOutputCount(0); } m_params->inferAndCheck(ar, Type::Some, false); } } else { m_extraArg = func->inferParamTypes(ar, self, m_params, valid); m_variableArgument = func->isVariableArgument(); } if (valid) { m_classScope = cls; m_funcScope = func; } if (!valid || m_dynamic) { m_implementedType = Type::Object; } else { m_implementedType.reset(); } return Type::CreateObjectType(m_name); } else { ar->containsDynamicClass(); if (m_params) { m_params->markParams(false); } } m_implementedType.reset(); m_nameExp->inferAndCheck(ar, Type::String, false); if (m_params) m_params->inferAndCheck(ar, Type::Any, false); return Type::Object; }
TypePtr NewObjectExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { reset(); m_classScope.reset(); FunctionScopePtr prev = m_funcScope; m_funcScope.reset(); ConstructPtr self = shared_from_this(); if (!m_name.empty() && !isStatic()) { ClassScopePtr cls = resolveClassWithChecks(); m_name = m_className; if (!cls) { if (m_params) m_params->inferAndCheck(ar, Type::Any, false); return Type::Object; } if (getScope()->isFirstPass() && (cls->isTrait() ? !isSelf() && !isParent() : cls->isInterface() || cls->isAbstract())) { Compiler::Error(Compiler::InvalidInstantiation, self); } if (cls->isVolatile() && !isPresent()) { getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); } m_dynamic = cls->derivesFromRedeclaring(); bool valid = true; FunctionScopePtr func = cls->findConstructor(ar, true); if (!func) { if (m_params) { if (!m_dynamic && m_params->getCount()) { if (getScope()->isFirstPass()) { Compiler::Error(Compiler::BadConstructorCall, self); } } m_params->inferAndCheck(ar, Type::Some, false); } } else { if (func != prev) func->addNewObjCaller(getScope()); m_extraArg = func->inferParamTypes(ar, self, m_params, valid); m_variableArgument = func->isVariableArgument(); } if (valid) { m_classScope = cls; m_funcScope = func; } if (!valid || m_dynamic) { m_implementedType = Type::Object; } else { m_implementedType.reset(); } return Type::CreateObjectType(m_name); } else { if (m_params) { m_params->markParams(canInvokeFewArgs()); } } m_implementedType.reset(); m_nameExp->inferAndCheck(ar, Type::String, false); if (m_params) m_params->inferAndCheck(ar, Type::Any, false); return Type::Object; }
TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar, TypePtr type, bool coerce, FunctionScopePtr func, bool arrayParams) { #ifdef HPHP_DETAILED_TYPE_INF_ASSERT assert(func->hasUser(getScope(), BlockScope::UseKindCaller)); #endif /* HPHP_DETAILED_TYPE_INF_ASSERT */ ConstructPtr self = shared_from_this(); TypePtr frt; { TRY_LOCK(func); func->getInferTypesMutex().assertOwnedBySelf(); assert(!func->inVisitScopes() || getScope() == func); frt = func->getReturnType(); } // fix return type for generators and async functions here, keep the // infered return type in function scope to allow further optimizations if (func->isGenerator()) { frt = Type::GetType(Type::KindOfObject, "Generator"); } else if (func->isAsync()) { frt = Type::GetType(Type::KindOfObject, "WaitHandle"); } m_voidUsed = false; if (!frt) { m_voidReturn = true; setActualType(TypePtr()); if (!isUnused() && !type->is(Type::KindOfAny)) { if (!hasContext(ReturnContext) && !func->isFirstPass() && !func->isAbstract()) { if (Option::WholeProgram || !func->getContainingClass() || func->isStatic() || func->isFinal() || func->isPrivate()) { m_voidUsed = true; } } if (!Type::IsMappedToVariant(type)) { setExpectedType(type); } } } else { m_voidReturn = false; type = checkTypesImpl(ar, type, frt, coerce); assert(m_actualType); } if (arrayParams) { m_extraArg = 0; (*m_params)[0]->inferAndCheck(ar, Type::Array, false); } else { m_extraArg = func->inferParamTypes(ar, self, m_params, m_valid); } m_variableArgument = func->allowsVariableArguments(); if (m_valid) { m_implementedType.reset(); } else { m_implementedType = Type::Variant; } assert(type); return type; }