TypePtr Symbol::setType(AnalysisResultConstPtr ar, BlockScopeRawPtr scope, TypePtr type, bool coerced) { if (!type) return type; if (ar->getPhase() == AnalysisResult::FirstInference) { // at this point, you *must* have a lock (if you are user scope) if (scope->is(BlockScope::FunctionScope)) { FunctionScopeRawPtr f = static_pointer_cast<FunctionScope>(scope); if (f->isUserFunction()) { f->getInferTypesMutex().assertOwnedBySelf(); } } else if (scope->is(BlockScope::ClassScope)) { ClassScopeRawPtr c = static_pointer_cast<ClassScope>(scope); if (c->isUserClass()) { c->getInferTypesMutex().assertOwnedBySelf(); } } } TypePtr oldType = m_coerced; if (!oldType) oldType = Type::Some; if (!coerced) return oldType; type = CoerceTo(ar, m_coerced, type); assert(!isRefClosureVar() || (type && type->is(Type::KindOfVariant))); if (ar->getPhase() >= AnalysisResult::AnalyzeAll && !Type::SameType(oldType, type)) { triggerUpdates(scope); } return type; }
static inline void DumpScope(BlockScopeRawPtr scope, const char *prefix, bool newline = true) { assert(scope->is(BlockScope::FunctionScope) || scope->is(BlockScope::ClassScope)); const char *type = scope->is(BlockScope::FunctionScope) ? "function" : "class"; std::cout << prefix << type << " " << scope->getName() << " @ " << scope->getContainingFile()->getName(); if (newline) std::cout << std::endl; }
void ScalarExpression::analyzeProgram(AnalysisResultPtr ar) { if (ar->getPhase() == AnalysisResult::AnalyzeAll) { auto const id = HPHP::toLower(getIdentifier()); switch (m_type) { case T_LINE: m_translated = folly::to<std::string>(line1()); break; case T_NS_C: m_translated = m_value; break; // case T_TRAIT_C: Note: T_TRAIT_C is translated at parse time case T_CLASS_C: case T_METHOD_C: { if (!m_translated.empty()) break; BlockScopeRawPtr b = getScope(); while (b && b->is(BlockScope::FunctionScope)) { b = b->getOuterScope(); } m_translated.clear(); if (b && b->is(BlockScope::ClassScope)) { auto clsScope = dynamic_pointer_cast<ClassScope>(b); if (!clsScope->isTrait()) { m_translated = clsScope->getOriginalName(); } } if (m_type == T_METHOD_C) { if (FunctionScopePtr func = getFunctionScope()) { if (b && b->is(BlockScope::ClassScope)) { m_translated += "::"; } if (func->isClosure()) { m_translated += "{closure}"; } else { m_translated += func->getOriginalName(); } } } break; } case T_FUNC_C: if (FunctionScopePtr func = getFunctionScope()) { if (func->isClosure()) { m_translated = "{closure}"; } else { m_translated = func->getOriginalName(); } } break; default: break; } } }
void Symbol::triggerUpdates(BlockScopeRawPtr scope) const { int useKind = BlockScope::GetNonStaticRefUseKind(getHash()); if (isConstant()) { useKind = BlockScope::UseKindConstRef; if (m_declaration) { BlockScopeRawPtr declScope(m_declaration->getScope()); /** * Constants can only belong to a file or class scope */ assert(scope->is(BlockScope::FileScope) || scope->is(BlockScope::ClassScope)); /** * Constants can only be declared in a function or * class scope */ assert(declScope->is(BlockScope::FunctionScope) || declScope->is(BlockScope::ClassScope)); /** * For class scopes, the declaration scope *must* * match the scope the symbol lives in */ assert(!scope->is(BlockScope::ClassScope) || scope == declScope); /** * For file scopes, the declaration scope *must* * live in a function scope */ assert(!scope->is(BlockScope::FileScope) || declScope->is(BlockScope::FunctionScope)); /** * This is really only for file scopes (constants created with * define('FOO', ...)). const FOO = 1 outside of a class is re-written * into a define('FOO', 1) by earlier phases of the compiler */ if (scope->is(BlockScope::FileScope)) { declScope->announceUpdates(BlockScope::UseKindConstRef); return; } } } else if (isStatic()) { useKind = BlockScope::UseKindStaticRef; } else if (isParameter()) { useKind = BlockScope::UseKindCallerParam; } if (isPassClosureVar()) { useKind |= BlockScope::UseKindClosure; } scope->addUpdates(useKind); }
static inline void DumpScopeWithDeps(BlockScopeRawPtr scope) { assert(scope->is(BlockScope::FunctionScope) || scope->is(BlockScope::ClassScope)); DumpScope(scope, ""); const BlockScopeRawPtrFlagsVec &ordered = scope->getOrderedUsers(); for (BlockScopeRawPtrFlagsVec::const_iterator it = ordered.begin(), end = ordered.end(); it != end; ++it) { BlockScopeRawPtrFlagsVec::value_type pf = *it; auto prefix = folly::to<string>(" (", pf->second, ") "); DumpScope(pf->first, prefix.c_str()); } }
TypePtr ConstantTable::check(BlockScopeRawPtr context, const std::string &name, TypePtr type, bool coerce, AnalysisResultConstPtr ar, ConstructPtr construct, const std::vector<std::string> &bases, BlockScope *&defScope) { ASSERT(!m_blockScope.is(BlockScope::FunctionScope)); bool isClassScope = m_blockScope.is(BlockScope::ClassScope); TypePtr actualType; defScope = NULL; if (name == "true" || name == "false") { actualType = Type::Boolean; } else { Symbol *sym = getSymbol(name); if (!sym) { if (ar->getPhase() != AnalysisResult::AnalyzeInclude) { if (isClassScope) { ClassScopeRawPtr parent = findBase(ar, name, bases); if (parent) { actualType = parent->getConstants()->check( context, name, type, coerce, ar, construct, bases, defScope); if (defScope) return actualType; } } Compiler::Error(Compiler::UseUndeclaredConstant, construct); actualType = isClassScope ? Type::Variant : Type::String; } } else { ASSERT(sym->isPresent()); ASSERT(sym->getType()); ASSERT(sym->isConstant()); defScope = &m_blockScope; if (isClassScope) { // if the current scope is a function scope, grab the lock. // otherwise if it's a class scope, then *try* to grab the lock. if (context->is(BlockScope::FunctionScope)) { GET_LOCK(BlockScopeRawPtr(&m_blockScope)); return setType(ar, sym, type, coerce); } else { TRY_LOCK(BlockScopeRawPtr(&m_blockScope)); return setType(ar, sym, type, coerce); } } else { Lock lock(m_blockScope.getMutex()); return setType(ar, sym, type, coerce); } } } return actualType; }
void ClassScope::setVolatile() { if (!m_volatile) { m_volatile = true; Lock lock(s_depsMutex); const BlockScopeRawPtrFlagsVec &orderedUsers = getOrderedUsers(); for (BlockScopeRawPtrFlagsVec::const_iterator it = orderedUsers.begin(), end = orderedUsers.end(); it != end; ++it) { BlockScopeRawPtrFlagsVec::value_type pf = *it; if (pf->second & UseKindParentRef) { BlockScopeRawPtr scope = pf->first; if (scope->is(BlockScope::ClassScope)) { ((HPHP::ClassScope*)scope.get())->setVolatile(); } } } } }
TypePtr VariableTable::checkProperty(BlockScopeRawPtr context, Symbol *sym, TypePtr type, bool coerce, AnalysisResultConstPtr ar) { always_assert(sym->isPresent()); if (sym->isOverride()) { Symbol *base; ClassScopePtr parent = findParent(ar, sym->getName(), base); assert(parent); assert(parent.get() != &m_blockScope); assert(base && !base->isPrivate()); if (context->is(BlockScope::FunctionScope)) { GET_LOCK(parent); type = parent->getVariables()->setType(ar, base, type, coerce); } else { TRY_LOCK(parent); type = parent->getVariables()->setType(ar, base, type, coerce); } } return setType(ar, sym, type, coerce); }