void InterfaceStatement::analyzeProgram(AnalysisResultPtr ar) { ClassScopeRawPtr classScope = getClassScope(); if (m_stmt) { m_stmt->analyzeProgram(ar); } checkVolatile(ar); if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; vector<string> bases; if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if (!cls->isInterface()) { Compiler::Error( Compiler::InvalidDerivation, shared_from_this(), cls->getOriginalName() + " must be an interface"); } if (cls->isUserClass()) { cls->addUse(classScope, BlockScope::UseKindParentRef); } } } }
void ClassStatement::analyzeProgramImpl(AnalysisResultPtr ar) { vector<string> bases; if (!m_parent.empty()) bases.push_back(m_parent); if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { string className = bases[i]; addUserClass(ar, bases[i]); } checkVolatile(ar); if (m_stmt) { m_stmt->analyzeProgram(ar); } if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if ((!cls->isInterface() && (m_parent.empty() || i > 0 )) || (cls->isInterface() && (!m_parent.empty() && i == 0 ))) { Compiler::Error(Compiler::InvalidDerivation, shared_from_this(), cls->getOriginalName()); } if (cls->isUserClass()) { cls->addUse(getScope(), BlockScope::UseKindParentRef); } } } }
void InterfaceStatement::analyzeProgramImpl(AnalysisResultPtr ar) { ClassScopeRawPtr classScope = getClassScope(); if (m_stmt) { classScope->setIncludeLevel(ar->getIncludeLevel()); m_stmt->analyzeProgram(ar); } ar->recordClassSource(m_name, m_loc, getFileScope()->getName()); checkVolatile(ar); if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; vector<string> bases; if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { addUserClass(ar, bases[i]); ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if (!cls->isInterface()) { Compiler::Error(Compiler::InvalidDerivation, shared_from_this(), cls->getOriginalName()); } if (cls->isUserClass()) { cls->addUse(classScope, BlockScope::UseKindParentRef); } } } }
void ClassStatement::analyzeProgram(AnalysisResultPtr ar) { std::vector<std::string> bases; auto const hasParent = !m_originalParent.empty(); if (hasParent) bases.push_back(m_originalParent); if (m_base) m_base->getStrings(bases); checkVolatile(ar); if (m_stmt) { m_stmt->analyzeProgram(ar); } if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { auto const expectClass = hasParent && i == 0; if (expectClass == cls->isInterface() || cls->isTrait()) { Compiler::Error(Compiler::InvalidDerivation, shared_from_this(), "You are extending " + cls->getOriginalName() + " which is an interface or a trait"); } if (cls->isUserClass()) { cls->addUse(getScope(), BlockScope::UseKindParentRef); } } } }
void ClassStatement::analyzeProgram(AnalysisResultPtr ar) { vector<string> bases; if (!m_parent.empty()) bases.push_back(m_parent); if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { string className = bases[i]; addUserClass(ar, bases[i]); } checkVolatile(ar); if (m_stmt) { m_stmt->analyzeProgram(ar); } ClassScopePtr clsScope = getClassScope(); // Check that every trait stmt is either a method, class_var, or trait_use if (clsScope->isTrait()) { StatementListPtr stmts = getStmts(); if (stmts) { for (int s = 0; s < stmts->getCount(); s++) { StatementPtr stmt = (*stmts)[s]; if(!dynamic_pointer_cast<UseTraitStatement>(stmt) && !dynamic_pointer_cast<MethodStatement>(stmt) && !dynamic_pointer_cast<ClassVariable>(stmt)) { Compiler::Error(Compiler::InvalidTraitStatement, stmt); } } } } if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; clsScope->importUsedTraits(ar); ar->recordClassSource(m_name, m_loc, getFileScope()->getName()); for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if ((!cls->isInterface() && (m_parent.empty() || i > 0 )) || (cls->isInterface() && (!m_parent.empty() && i == 0 )) || (cls->isTrait())) { Compiler::Error(Compiler::InvalidDerivation, shared_from_this(), cls->getOriginalName()); } if (cls->isUserClass()) { cls->addUse(getScope(), BlockScope::UseKindParentRef); } } } }
ExpressionPtr ClassConstantExpression::preOptimize(AnalysisResultConstPtr ar) { if (ar->getPhase() < AnalysisResult::FirstPreOptimize) { return ExpressionPtr(); } if (m_class) { updateClassName(); if (m_class) { return ExpressionPtr(); } } ClassScopePtr cls = resolveClass(); if (!cls || (cls->isVolatile() && !isPresent())) { if (cls && !m_depsSet) { cls->addUse(getScope(), BlockScope::UseKindConstRef); m_depsSet = true; } return ExpressionPtr(); } ConstantTablePtr constants = cls->getConstants(); ClassScopePtr defClass = cls; ConstructPtr decl = constants->getValueRecur(ar, m_varName, defClass); if (decl) { BlockScope::s_constMutex.lock(); ExpressionPtr value = dynamic_pointer_cast<Expression>(decl); BlockScope::s_constMutex.unlock(); if (!value->isScalar() && (value->is(KindOfClassConstantExpression) || value->is(KindOfConstantExpression))) { std::set<ExpressionPtr> seen; do { if (!seen.insert(value).second) return ExpressionPtr(); value = value->preOptimize(ar); if (!value) return ExpressionPtr(); } while (!value->isScalar() && (value->is(KindOfClassConstantExpression) || value->is(KindOfConstantExpression))); } ExpressionPtr rep = Clone(value, getScope()); rep->setComment(getText()); copyLocationTo(rep); return replaceValue(rep); } return ExpressionPtr(); }
TypePtr ObjectPropertyExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { m_valid = false; ConstructPtr self = shared_from_this(); TypePtr objectType = m_object->inferAndCheck(ar, Type::Some, false); if (!m_property->is(Expression::KindOfScalarExpression)) { m_property->inferAndCheck(ar, Type::String, false); // we also lost track of which class variable an expression is about, hence // any type inference could be wrong. Instead, we just force variants on // all class variables. if (m_context & (LValue | RefValue)) { ar->forceClassVariants(getOriginalClass(), false); } return Type::Variant; // we have to use a variant to hold dynamic value } ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>(m_property); string name = exp->getString(); ASSERT(!name.empty()); m_property->inferAndCheck(ar, Type::String, false); ClassScopePtr cls; if (objectType && !objectType->getName().empty()) { // what object-> has told us cls = ar->findExactClass(shared_from_this(), objectType->getName()); } else { if ((m_context & LValue) && objectType && !objectType->is(Type::KindOfObject) && !objectType->is(Type::KindOfVariant) && !objectType->is(Type::KindOfSome) && !objectType->is(Type::KindOfAny)) { m_object->inferAndCheck(ar, Type::Object, true); } } if (!cls) { if (m_context & (LValue | RefValue | DeepReference | UnsetContext)) { ar->forceClassVariants(name, getOriginalClass(), false); } return Type::Variant; } int prop = hasContext(AssignmentLHS) ? ClassScope::MayHaveUnknownPropSetter : hasContext(ExistContext) ? ClassScope::MayHaveUnknownPropTester : hasContext(UnsetContext) && hasContext(LValue) ? ClassScope::MayHavePropUnsetter : ClassScope::MayHaveUnknownPropGetter; if ((m_context & (AssignmentLHS|OprLValue)) || !cls->implementsAccessor(prop)) { clearEffect(AccessorEffect); } // resolved to this class if (m_context & RefValue) { type = Type::Variant; coerce = true; } // use $this inside a static function if (m_object->isThis()) { FunctionScopePtr func = m_object->getOriginalFunction(); if (!func || func->isStatic()) { if (getScope()->isFirstPass()) { Compiler::Error(Compiler::MissingObjectContext, self); } m_actualType = Type::Variant; return m_actualType; } } if (!m_propSym || cls != m_objectClass.lock()) { m_objectClass = cls; ClassScopePtr parent; m_propSym = cls->findProperty(parent, name, ar, self); assert(m_propSym); if (!parent) { parent = cls; } m_propSymValid = m_propSym->isPresent() && (!m_propSym->isPrivate() || getOriginalClass() == parent) && !m_propSym->isStatic(); if (m_propSymValid) { parent->addUse(getScope(), BlockScope::UseKindNonStaticRef); } } TypePtr ret; if (m_propSymValid && (!cls->derivesFromRedeclaring() || m_propSym->isPrivate())) { ret = cls->checkProperty(m_propSym, type, coerce, ar); assert(m_object->getType()->isSpecificObject()); m_valid = true; clearEffect(AccessorEffect); clearEffect(CreateEffect); return ret; } else { m_actualType = Type::Variant; return m_actualType; } }