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 = resolveClass(); 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 { if (func != prev) func->addCaller(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 { ar->containsDynamicClass(); 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 ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { reset(); ConstructPtr self = shared_from_this(); TypePtr objectType = m_object->inferAndCheck(ar, Type::Object, false); m_valid = true; m_bindClass = true; if (m_name.empty()) { m_nameExp->inferAndCheck(ar, Type::String, false); setInvokeParams(ar); // we have to use a variant to hold dynamic value return checkTypesImpl(ar, type, Type::Variant, coerce); } ClassScopePtr cls; if (objectType && !objectType->getName().empty()) { if (m_classScope && !strcasecmp(objectType->getName().c_str(), m_classScope->getName().c_str())) { cls = m_classScope; } else { cls = ar->findExactClass(shared_from_this(), objectType->getName()); } } if (!cls) { if (getScope()->isFirstPass()) { // call resolveClass to mark functions as dynamic // but we cant do anything else with the result. resolveClass(ar, m_name); if (!ar->classMemberExists(m_name, AnalysisResult::MethodName)) { Compiler::Error(Compiler::UnknownObjectMethod, self); } } m_classScope.reset(); m_funcScope.reset(); setInvokeParams(ar); return checkTypesImpl(ar, type, Type::Variant, coerce); } if (m_classScope != cls) { m_classScope = cls; m_funcScope.reset(); } FunctionScopePtr func = m_funcScope; if (!func) { func = cls->findFunction(ar, m_name, true, true); if (!func) { if (!cls->hasAttribute(ClassScope::HasUnknownMethodHandler, ar)) { if (ar->classMemberExists(m_name, AnalysisResult::MethodName)) { setDynamicByIdentifier(ar, m_name); } else { Compiler::Error(Compiler::UnknownObjectMethod, self); } } m_valid = false; setInvokeParams(ar); return checkTypesImpl(ar, type, Type::Variant, coerce); } m_funcScope = func; func->addCaller(getScope()); } bool valid = true; m_bindClass = func->isStatic(); // use $this inside a static function if (m_object->isThis()) { FunctionScopePtr localfunc = getFunctionScope(); if (localfunc->isStatic()) { if (getScope()->isFirstPass()) { Compiler::Error(Compiler::MissingObjectContext, self); } valid = false; } } // invoke() will return Variant if (!m_object->getType()->isSpecificObject() || (func->isVirtual() && !func->isPerfectVirtual())) { valid = false; } if (!valid) { setInvokeParams(ar); checkTypesImpl(ar, type, Type::Variant, coerce); m_valid = false; // so we use invoke() syntax func->setDynamic(); return m_actualType; } return checkParamsAndReturn(ar, type, coerce, func, false); }
TypePtr ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { assert(type); IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope()); resetTypes(); reset(); ConstructPtr self = shared_from_this(); TypePtr objectType = m_object->inferAndCheck(ar, Type::Some, false); m_valid = true; m_bindClass = true; if (m_name.empty()) { m_nameExp->inferAndCheck(ar, Type::Some, false); setInvokeParams(ar); // we have to use a variant to hold dynamic value return checkTypesImpl(ar, type, Type::Variant, coerce); } ClassScopePtr cls; if (objectType && !objectType->getName().empty()) { if (m_classScope && !strcasecmp(objectType->getName().c_str(), m_classScope->getName().c_str())) { cls = m_classScope; } else { cls = ar->findExactClass(shared_from_this(), objectType->getName()); } } if (!cls) { m_classScope.reset(); m_funcScope.reset(); m_valid = false; setInvokeParams(ar); return checkTypesImpl(ar, type, Type::Variant, coerce); } if (m_classScope != cls) { m_classScope = cls; m_funcScope.reset(); } FunctionScopePtr func = m_funcScope; if (!func) { func = cls->findFunction(ar, m_name, true, true); if (!func) { if (!cls->isTrait() && !cls->getAttribute(ClassScope::MayHaveUnknownMethodHandler) && !cls->getAttribute(ClassScope::HasUnknownMethodHandler) && !cls->getAttribute(ClassScope::InheritsUnknownMethodHandler)) { if (ar->classMemberExists(m_name, AnalysisResult::MethodName)) { if (!Option::AllDynamic) { setDynamicByIdentifier(ar, m_name); } } else { Compiler::Error(Compiler::UnknownObjectMethod, self); } } m_valid = false; setInvokeParams(ar); return checkTypesImpl(ar, type, Type::Variant, coerce); } m_funcScope = func; func->addCaller(getScope(), !type->is(Type::KindOfAny)); } bool valid = true; m_bindClass = func->isStatic(); // use $this inside a static function if (m_object->isThis()) { FunctionScopePtr localfunc = getFunctionScope(); if (localfunc->isStatic()) { if (getScope()->isFirstPass()) { Compiler::Error(Compiler::MissingObjectContext, self); } valid = false; } } // invoke() will return Variant if (cls->isInterface() || (func->isVirtual() && (!Option::WholeProgram || func->isAbstract() || (func->hasOverride() && cls->getAttribute(ClassScope::NotFinal))) && !func->isPerfectVirtual())) { valid = false; } if (!valid) { setInvokeParams(ar); checkTypesImpl(ar, type, Type::Variant, coerce); m_valid = false; // so we use invoke() syntax if (!Option::AllDynamic) { func->setDynamic(); } assert(m_actualType); return m_actualType; } assert(func); return checkParamsAndReturn(ar, type, coerce, func, false); }