void MethodStatement::onParseRecur(AnalysisResultConstRawPtr ar, FileScopeRawPtr fileScope, ClassScopePtr classScope) { checkParameters(fileScope); FunctionScopeRawPtr funcScope = getFunctionScope(); funcScope->setOuterScope(classScope); const bool isNative = funcScope->isNative(); if (m_modifiers) { if ((m_modifiers->isExplicitlyPublic() + m_modifiers->isProtected() + m_modifiers->isPrivate()) > 1) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, Strings::PICK_ACCESS_MODIFIER ); } if (m_modifiers->hasDuplicates()) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, Strings::PICK_ACCESS_MODIFIER); } if (classScope->isInterface()) { if (m_modifiers->isProtected() || m_modifiers->isPrivate() || m_modifiers->isAbstract() || m_modifiers->isFinal() || isNative) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, "Access type for interface method %s::%s() must be omitted", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (m_modifiers->isAsync()) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, Strings::ASYNC_WITHOUT_BODY, "interface", classScope->getOriginalName().c_str(), getOriginalName().c_str() ); } if (getStmts()) { getStmts()->parseTimeFatal( fileScope, Compiler::InvalidMethodDefinition, "Interface method %s::%s() cannot contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } } if (m_modifiers->isAbstract()) { if (!Option::WholeProgram && funcScope->userAttributes().count("__Memoize")) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, "Abstract method %s::%s cannot be memoized", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (m_modifiers->isPrivate() || m_modifiers->isFinal() || isNative) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, "Cannot declare abstract method %s::%s() %s", classScope->getOriginalName().c_str(), getOriginalName().c_str(), m_modifiers->isPrivate() ? "private" : (m_modifiers->isFinal() ? "final" : "native")); } if (!classScope->isInterface() && !classScope->isAbstract()) { /* note that classScope->isAbstract() returns true for traits */ m_modifiers->parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Class %s contains abstract method %s and " "must therefore be declared abstract", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (getStmts()) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Abstract method %s::%s() cannot contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (m_modifiers->isAsync()) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, Strings::ASYNC_WITHOUT_BODY, "abstract", classScope->getOriginalName().c_str(), getOriginalName().c_str() ); } } if (!m_modifiers->isStatic() && classScope->isStaticUtil()) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, "Class %s contains non-static method %s and " "therefore cannot be declared 'abstract final'", classScope->getOriginalName().c_str(), getOriginalName().c_str() ); } if (isNative) { if (getStmts()) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Native method %s::%s() cannot contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } auto is_ctordtor = isNamed("__construct") || isNamed("__destruct"); if (!m_retTypeAnnotation && !is_ctordtor) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Native method %s::%s() must have a return type hint", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } else if (m_retTypeAnnotation && is_ctordtor && (m_retTypeAnnotation->dataType() != KindOfNull)) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Native method %s::%s() must return void", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } } } if ((!m_modifiers || !m_modifiers->isAbstract()) && !getStmts() && !classScope->isInterface() && !isNative) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Non-abstract method %s::%s() must contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } classScope->addFunction(ar, fileScope, funcScope); setSpecialMethod(fileScope, classScope); if (RuntimeOption::DynamicInvokeFunctions.count(getOriginalFullName())) { funcScope->setDynamicInvoke(); } if (m_params) { auto nParams = m_params->getCount(); for (int i = 0; i < nParams; i++) { auto param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); param->parseHandler(fileScope, classScope); // Variadic capture params don't need types because they'll // be treated as Arrays as far as HNI is concerned. if (isNative && !param->hasUserType() && !param->isVariadic()) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Native method calls must have type hints on all args"); } } } FunctionScope::RecordFunctionInfo(m_originalName, funcScope); }
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; }
void MethodStatement::onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr classScope) { if (m_modifiers) { if (classScope->isInterface()) { if (m_modifiers->isProtected() || m_modifiers->isPrivate() || m_modifiers->isAbstract() || m_modifiers->isFinal()) { m_modifiers->parseTimeFatal( Compiler::InvalidAttribute, "Access type for interface method %s::%s() must be omitted", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } } if (m_modifiers->isAbstract()) { if (m_modifiers->isPrivate() || m_modifiers->isFinal()) { m_modifiers->parseTimeFatal( Compiler::InvalidAttribute, "Cannot declare abstract method %s::%s() %s", classScope->getOriginalName().c_str(), getOriginalName().c_str(), m_modifiers->isPrivate() ? "private" : "final"); } if (!classScope->isInterface() && !classScope->isAbstract()) { /* note that classScope->isAbstract() returns true for traits */ m_modifiers->parseTimeFatal(Compiler::InvalidAttribute, "Class %s contains abstract method %s and " "must therefore be declared abstract", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (getStmts()) { parseTimeFatal(Compiler::InvalidAttribute, "Abstract method %s::%s() cannot contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } } } if ((!m_modifiers || !m_modifiers->isAbstract()) && !getStmts() && !classScope->isInterface()) { parseTimeFatal(Compiler::InvalidAttribute, "Non-abstract method %s::%s() must contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } FunctionScopeRawPtr fs = getFunctionScope(); classScope->addFunction(ar, fs); m_className = classScope->getName(); m_originalClassName = classScope->getOriginalName(); setSpecialMethod(classScope); if (Option::DynamicInvokeFunctions.find(getFullName()) != Option::DynamicInvokeFunctions.end()) { fs->setDynamicInvoke(); } if (m_params) { for (int i = 0; i < m_params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); param->parseHandler(classScope); } } FunctionScope::RecordFunctionInfo(m_name, fs); }
void MethodStatement::onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr classScope) { FunctionScopeRawPtr fs = getFunctionScope(); const bool isNative = fs->isNative(); if (m_modifiers) { if ((m_modifiers->isExplicitlyPublic() + m_modifiers->isProtected() + m_modifiers->isPrivate()) > 1) { m_modifiers->parseTimeFatal( Compiler::InvalidAttribute, "%s: method %s::%s()", Strings::PICK_ACCESS_MODIFIER, classScope->getOriginalName().c_str(), getOriginalName().c_str() ); } if (classScope->isInterface()) { if (m_modifiers->isProtected() || m_modifiers->isPrivate() || m_modifiers->isAbstract() || m_modifiers->isFinal() || isNative) { m_modifiers->parseTimeFatal( Compiler::InvalidAttribute, "Access type for interface method %s::%s() must be omitted", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (m_modifiers->isAsync()) { m_modifiers->parseTimeFatal( Compiler::InvalidAttribute, Strings::ASYNC_WITHOUT_BODY, "interface", classScope->getOriginalName().c_str(), getOriginalName().c_str() ); } } if (m_modifiers->isAbstract()) { if (m_modifiers->isPrivate() || m_modifiers->isFinal() || isNative) { m_modifiers->parseTimeFatal( Compiler::InvalidAttribute, "Cannot declare abstract method %s::%s() %s", classScope->getOriginalName().c_str(), getOriginalName().c_str(), m_modifiers->isPrivate() ? "private" : (m_modifiers->isFinal() ? "final" : "native")); } if (!classScope->isInterface() && !classScope->isAbstract()) { /* note that classScope->isAbstract() returns true for traits */ m_modifiers->parseTimeFatal(Compiler::InvalidAttribute, "Class %s contains abstract method %s and " "must therefore be declared abstract", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (getStmts()) { parseTimeFatal(Compiler::InvalidAttribute, "Abstract method %s::%s() cannot contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (m_modifiers->isAsync()) { m_modifiers->parseTimeFatal( Compiler::InvalidAttribute, Strings::ASYNC_WITHOUT_BODY, "abstract", classScope->getOriginalName().c_str(), getOriginalName().c_str() ); } } if (isNative) { if (getStmts()) { parseTimeFatal(Compiler::InvalidAttribute, "Native method %s::%s() cannot contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (!m_retTypeAnnotation) { parseTimeFatal(Compiler::InvalidAttribute, "Native method %s::%s() must have a return type hint", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } } } if ((!m_modifiers || !m_modifiers->isAbstract()) && !getStmts() && !classScope->isInterface() && !isNative) { parseTimeFatal(Compiler::InvalidAttribute, "Non-abstract method %s::%s() must contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } classScope->addFunction(ar, fs); m_className = classScope->getName(); m_originalClassName = classScope->getOriginalName(); setSpecialMethod(classScope); if (Option::DynamicInvokeFunctions.find(getFullName()) != Option::DynamicInvokeFunctions.end()) { fs->setDynamicInvoke(); } if (m_params) { for (int i = 0; i < m_params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); param->parseHandler(classScope); if (isNative && !param->hasUserType()) { parseTimeFatal(Compiler::InvalidAttribute, "Native method calls must have type hints on all args"); } } } FunctionScope::RecordFunctionInfo(m_name, fs); }