Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
    }
  }
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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());
  }
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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);
}