예제 #1
0
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);
      }
    }
  }
}
예제 #2
0
void ClassConstant::onParseRecur(AnalysisResultConstPtr ar,
                                 ClassScopePtr scope) {
  ConstantTablePtr constants = scope->getConstants();

  if (scope->isTrait()) {
    parseTimeFatal(Compiler::InvalidTraitStatement,
                   "Traits cannot have constants");
  }

  for (int i = 0; i < m_exp->getCount(); i++) {
    AssignmentExpressionPtr assignment =
      dynamic_pointer_cast<AssignmentExpression>((*m_exp)[i]);

    ExpressionPtr var = assignment->getVariable();
    const std::string &name =
      dynamic_pointer_cast<ConstantExpression>(var)->getName();
    if (constants->isPresent(name)) {
      assignment->parseTimeFatal(Compiler::DeclaredConstantTwice,
                                 "Cannot redeclare %s::%s",
                                 scope->getOriginalName().c_str(),
                                 name.c_str());
    } else {
      assignment->onParseRecur(ar, scope);
    }
  }
}
예제 #3
0
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);
  }

  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 )) ||
          (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);
      }
    }
  }
}
예제 #4
0
bool ClosureExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
                                     int state) {
  FunctionScopeRawPtr cfunc(m_func->getFunctionScope());
  bool output = false;
  for (BlockScopePtr sc = cfunc->getOuterScope(); sc;
       sc = sc->getOuterScope()) {
    if (sc->is(BlockScope::ClassScope)) {
      ClassScopePtr cls = boost::static_pointer_cast<ClassScope>(sc);
      if (cls->isTrait()) {
        output = true;
        break;
      }
    }
  }

  if (!cg.inExpression()) {
    return output || Expression::preOutputCPP(cg, ar, state);
  }

  if (output) {
    cg.wrapExpressionBegin();
    cfunc->outputCPPPreface(cg, ar);
  }
  return Expression::preOutputCPP(cg, ar, state) || output;
}
예제 #5
0
void ClassConstant::onParseRecur(AnalysisResultConstPtr ar,
                                 ClassScopePtr scope) {
  ConstantTablePtr constants = scope->getConstants();

  if (scope->isTrait()) {
    parseTimeFatal(Compiler::InvalidTraitStatement,
                   "Traits cannot have constants");
  }

  if (isAbstract()) {
    for (int i = 0; i < m_exp->getCount(); i++) {
      ConstantExpressionPtr exp =
        dynamic_pointer_cast<ConstantExpression>((*m_exp)[i]);
      const std::string &name = exp->getName();
      if (constants->isPresent(name)) {
        exp->parseTimeFatal(Compiler::DeclaredConstantTwice,
                                   "Cannot redeclare %s::%s",
                                   scope->getOriginalName().c_str(),
                                   name.c_str());
      }

      // HACK: break attempts to write global constants here;
      // see ConstantExpression::preOptimize
      exp->setContext(Expression::LValue);

      // Unlike with assignment expression below, nothing needs to be added
      // to the scope's constant table
    }
  } else {
    for (int i = 0; i < m_exp->getCount(); i++) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>((*m_exp)[i]);

      ExpressionPtr var = assignment->getVariable();
      const std::string &name =
        dynamic_pointer_cast<ConstantExpression>(var)->getName();
      if (constants->isPresent(name)) {
        assignment->parseTimeFatal(Compiler::DeclaredConstantTwice,
                                   "Cannot redeclare %s::%s",
                                   scope->getOriginalName().c_str(),
                                   name.c_str());
      } else {
        if (isTypeconst()) {
          // We do not want type constants to be available at run time.
          // To ensure this we do not want them to be added to the constants
          // table. The constants table is used to inline values for expressions
          // See ClassConstantExpression::preOptimize.
          // AssignmentExpression::onParseRecur essentially adds constants to
          // the constant table so we skip it.
          continue;
        }
        assignment->onParseRecur(ar, scope);
      }
    }
  }
}
예제 #6
0
void ParameterExpression::parseHandler(ClassScopePtr cls) {
  // Trait has not been 'inlined' into using class so context is not available
  if (!m_type.empty() && !cls->isTrait()) {
    fixupSelfAndParentTypehints(cls);

    if (m_defaultValue) {
      compatibleDefault();
    }
  }
}
예제 #7
0
void TraitRequireStatement::onParseRecur(AnalysisResultConstPtr ar,
                                         ClassScopePtr scope) {
  if (!scope->isTrait()) {
    parseTimeFatal(Compiler::InvalidTraitStatement,
                   "Only traits can require in class scope");
  }

  ar->parseOnDemandByClass(toLower(m_required));
  scope->addTraitRequirement(m_required, m_extends);
}
예제 #8
0
void ClassScope::applyTraitAliasRule(AnalysisResultPtr ar,
                                     TraitAliasStatementPtr stmt) {
  assert(Option::WholeProgram);
  const string traitName = toLower(stmt->getTraitName());
  const string origMethName = toLower(stmt->getMethodName());
  const string newMethName = toLower(stmt->getNewMethodName());

  // Get the trait's "class"
  ClassScopePtr traitCls;
  if (traitName.empty()) {
    traitCls = findSingleTraitWithMethod(ar, origMethName);
  } else {
    traitCls = ar->findClass(traitName);
  }
  if (!traitCls || !(traitCls->isTrait())) {
    stmt->analysisTimeFatal(
      Compiler::UnknownTrait,
      Strings::TRAITS_UNKNOWN_TRAIT,
      traitName.empty() ? origMethName.c_str() : traitName.c_str()
    );
  }

  // Keep record of alias rule
  addTraitAlias(stmt);

  // Get the method
  std::set<ClassScopePtr> visitedTraits;
  MethodStatementPtr methStmt = findTraitMethod(ar, traitCls, origMethName,
                                                visitedTraits);
  if (!methStmt) {
    stmt->analysisTimeFatal(
      Compiler::UnknownTraitMethod,
      Strings::TRAITS_UNKNOWN_TRAIT_METHOD, origMethName.c_str()
    );
  }

  if (origMethName == newMethName) {
    setImportTraitMethodModifiers(origMethName, traitCls, stmt->getModifiers());
  }
  else {
    // Insert renamed entry into the set of methods to be imported
    TraitMethod traitMethod(traitCls, methStmt, stmt->getModifiers(), stmt,
                            stmt->getNewMethodName());
    addImportTraitMethod(traitMethod, newMethName);
  }
}
예제 #9
0
void ClassRequireStatement::onParseRecur(AnalysisResultConstPtr ar,
                                         FileScopeRawPtr fs,
                                         ClassScopePtr scope) {
  if (!scope->isTrait() && !scope->isInterface()) {
    parseTimeFatal(fs,
                   Compiler::InvalidTraitStatement,
                   "Only traits and interfaces may use 'require' in class scope");
  }
  if (scope->isInterface() && !m_extends) {
    parseTimeFatal(
      fs,
      Compiler::InvalidTraitStatement,
      "'require implements' may not be used in interface scope"
      "; instead, use interface inheritance");
  }

  ar->parseOnDemandByClass(toLower(m_required));
  scope->addClassRequirement(m_required, m_extends);
}
예제 #10
0
파일: class_scope.cpp 프로젝트: orok/hhvm
void ClassScope::importUsedTraits(AnalysisResultPtr ar) {
  // Trait flattening is supposed to happen only when we have awareness of the
  // whole program.
  assert(Option::WholeProgram);

  if (m_traitStatus == FLATTENED) return;
  if (m_traitStatus == BEING_FLATTENED) {
    getStmt()->analysisTimeFatal(
      Compiler::CyclicDependentTraits,
      "Cyclic dependency between traits involving %s",
      getScopeName().c_str()
    );
    return;
  }
  if (m_usedTraitNames.size() == 0) {
    m_traitStatus = FLATTENED;
    return;
  }
  m_traitStatus = BEING_FLATTENED;

  m_numDeclMethods = m_functionsVec.size();

  // First, make sure that parent classes have their traits imported.
  if (!m_parent.empty()) {
    ClassScopePtr parent = ar->findClass(m_parent);
    if (parent) {
      parent->importUsedTraits(ar);
    }
  }

  TMIData tmid;

  if (isTrait()) {
    for (auto const& req : getClassRequiredExtends()) {
      ClassScopePtr rCls = ar->findClass(req);
      if (!rCls || rCls->isFinal() || rCls->isInterface()) {
        getStmt()->analysisTimeFatal(
          Compiler::InvalidDerivation,
          Strings::TRAIT_BAD_REQ_EXTENDS,
          m_scopeName.c_str(),
          req.c_str(),
          req.c_str()
        );
      }
    }
    for (auto const& req : getClassRequiredImplements()) {
      ClassScopePtr rCls = ar->findClass(req);
      if (!rCls || !(rCls->isInterface())) {
        getStmt()->analysisTimeFatal(
          Compiler::InvalidDerivation,
          Strings::TRAIT_BAD_REQ_IMPLEMENTS,
          m_scopeName.c_str(),
          req.c_str(),
          req.c_str()
        );
      }
    }
  }

  // Find trait methods to be imported.
  for (unsigned i = 0; i < m_usedTraitNames.size(); i++) {
    ClassScopePtr tCls = ar->findClass(m_usedTraitNames[i]);
    if (!tCls || !(tCls->isTrait())) {
      setAttribute(UsesUnknownTrait); // XXX: is this useful ... for anything?
      getStmt()->analysisTimeFatal(
        Compiler::UnknownTrait,
        Strings::TRAITS_UNKNOWN_TRAIT,
        m_usedTraitNames[i].c_str()
      );
    }

    // First, make sure the used trait is flattened.
    tCls->importUsedTraits(ar);

    findTraitMethodsToImport(ar, tCls, tmid);

    // Import any interfaces implemented.
    tCls->getInterfaces(ar, m_bases, /* recursive */ false);

    importClassRequirements(ar, tCls);
  }

  // Apply rules.
  applyTraitRules(tmid);

  // Remove methods declared on the current class from the trait import list;
  // the class methods take precedence.
  for (auto const& methName : tmid.methodNames()) {
    if (findFunction(ar, methName, false /* recursive */,
                     false /* exclIntfBase */)) {
      // This does not affect the methodNames() vector.
      tmid.erase(methName);
    }
  }

  auto traitMethods = tmid.finish(this);

  std::map<string, MethodStatementPtr, stdltistr> importedTraitMethods;
  std::vector<std::pair<string,const TraitMethod*>> importedTraitsWithOrigName;

  // Actually import the methods.
  for (auto const& mdata : traitMethods) {
    if ((mdata.tm.modifiers ? mdata.tm.modifiers
                            : mdata.tm.method->getModifiers()
        )->isAbstract()) {
      // Skip abstract methods, if the method already exists in the class.
      if (findFunction(ar, mdata.name, true) ||
          importedTraitMethods.count(mdata.name)) {
        continue;
      }
    }

    auto sourceName = mdata.tm.ruleStmt
      ? ((TraitAliasStatement*)mdata.tm.ruleStmt.get())->getMethodName()
      : mdata.name;

    importedTraitMethods[sourceName] = MethodStatementPtr();
    importedTraitsWithOrigName.push_back(
      std::make_pair(sourceName, &mdata.tm));
  }

  // Make sure there won't be 2 constructors after importing
  auto traitConstruct = importedTraitMethods.count("__construct");
  auto traitName = importedTraitMethods.count(getScopeName());
  auto classConstruct = m_functions.count("__construct");
  auto className = m_functions.count(getScopeName());
  if ((traitConstruct && traitName) ||
      (traitConstruct && className) ||
      (classConstruct && traitName)) {
    getStmt()->analysisTimeFatal(
      Compiler::InvalidDerivation,
      "%s has colliding constructor definitions coming from traits",
      getScopeName().c_str()
    );
  }

  for (auto const& traitPair : importedTraitsWithOrigName) {
    auto traitMethod = traitPair.second;

    MethodStatementPtr newMeth = importTraitMethod(
      *traitMethod,
      ar,
      traitMethod->originalName
    );
  }

  // Import trait properties
  importTraitProperties(ar);

  m_traitStatus = FLATTENED;
}
예제 #11
0
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;
}
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);
}
예제 #13
0
void ClassScope::importUsedTraits(AnalysisResultPtr ar) {
  // Trait flattening is supposed to happen only when we have awareness of
  // the whole program.
  assert(Option::WholeProgram);

  if (m_traitStatus == FLATTENED) return;
  if (m_traitStatus == BEING_FLATTENED) {
    getStmt()->analysisTimeFatal(
      Compiler::CyclicDependentTraits,
      "Cyclic dependency between traits involving %s",
      getOriginalName().c_str()
    );
    return;
  }
  if (m_usedTraitNames.size() == 0) {
    m_traitStatus = FLATTENED;
    return;
  }
  m_traitStatus = BEING_FLATTENED;

  // First, make sure that parent classes have their traits imported
  if (!m_parent.empty()) {
    ClassScopePtr parent = ar->findClass(m_parent);
    if (parent) {
      parent->importUsedTraits(ar);
    }
  }

  if (isTrait()) {
    for (auto const& req : getTraitRequiredExtends()) {
      ClassScopePtr rCls = ar->findClass(req);
      if (!rCls || rCls->isFinal() || rCls->isInterface()) {
        getStmt()->analysisTimeFatal(
          Compiler::InvalidDerivation,
          Strings::TRAIT_BAD_REQ_EXTENDS,
          m_originalName.c_str(),
          req.c_str(),
          req.c_str()
        );
      }
    }
    for (auto const& req : getTraitRequiredImplements()) {
      ClassScopePtr rCls = ar->findClass(req);
      if (!rCls || !(rCls->isInterface())) {
        getStmt()->analysisTimeFatal(
          Compiler::InvalidDerivation,
          Strings::TRAIT_BAD_REQ_IMPLEMENTS,
          m_originalName.c_str(),
          req.c_str(),
          req.c_str()
        );
      }
    }
  }

  // Find trait methods to be imported
  for (unsigned i = 0; i < m_usedTraitNames.size(); i++) {
    ClassScopePtr tCls = ar->findClass(m_usedTraitNames[i]);
    if (!tCls || !(tCls->isTrait())) {
      setAttribute(UsesUnknownTrait); // XXX: is this useful ... for anything?
      getStmt()->analysisTimeFatal(
        Compiler::UnknownTrait,
        Strings::TRAITS_UNKNOWN_TRAIT,
        m_usedTraitNames[i].c_str()
      );
    }
    // First, make sure the used trait is flattened
    tCls->importUsedTraits(ar);

    findTraitMethodsToImport(ar, tCls);

    // Import any interfaces implemented
    tCls->getInterfaces(ar, m_bases, false);
  }
  for (unsigned i = 0; i < m_usedTraitNames.size(); i++) {
    // Requirements must be checked in a separate loop because the
    // interfaces required by one trait may be implemented by another trait
    // whose "use" appears later in the class' scope
    ClassScopePtr tCls = ar->findClass(m_usedTraitNames[i]);
    importTraitRequirements(ar, tCls);
  }

  // Apply rules
  applyTraitRules(ar);

  // Remove trait abstract methods provided by other traits and duplicates
  removeSpareTraitAbstractMethods(ar);

  // Apply precedence of current class over used traits
  for (MethodToTraitListMap::iterator iter = m_importMethToTraitMap.begin();
       iter != m_importMethToTraitMap.end(); ) {
    MethodToTraitListMap::iterator thisiter = iter;
    iter++;
    if (findFunction(ar, thisiter->first, 0, 0) != FunctionScopePtr()) {
      m_importMethToTraitMap.erase(thisiter);
    }
  }

  std::map<string, MethodStatementPtr> importedTraitMethods;
  std::vector<std::pair<string,const TraitMethod*>> importedTraitsWithOrigName;

  // Actually import the methods
  for (MethodToTraitListMap::const_iterator
         iter = m_importMethToTraitMap.begin();
       iter != m_importMethToTraitMap.end(); iter++) {

    // The rules may rule out a method from all traits.
    // In this case, simply don't import the method.
    if (iter->second.size() == 0) {
      continue;
    }
    // Consistency checking: each name must only refer to one imported method
    if (iter->second.size() > 1) {
      getStmt()->analysisTimeFatal(
        Compiler::MethodInMultipleTraits,
        Strings::METHOD_IN_MULTIPLE_TRAITS,
        iter->first.c_str()
      );
    } else {
      TraitMethodList::const_iterator traitMethIter = iter->second.begin();
      if ((traitMethIter->m_modifiers ? traitMethIter->m_modifiers :
           traitMethIter->m_method->getModifiers())->isAbstract()) {
        // Skip abstract methods, if method already exists in the class
        if (findFunction(ar, iter->first, true) ||
            importedTraitMethods.count(iter->first)) {
          continue;
        }
      }
      string sourceName = traitMethIter->m_ruleStmt ?
        toLower(((TraitAliasStatement*)traitMethIter->m_ruleStmt.get())->
                      getMethodName()) : iter->first;
      importedTraitMethods[sourceName] = MethodStatementPtr();
      importedTraitsWithOrigName.push_back(
        make_pair(sourceName, &*traitMethIter));
    }
  }

  // Make sure there won't be 2 constructors after importing
  auto traitConstruct = importedTraitMethods.count("__construct");
  auto traitName = importedTraitMethods.count(getName());
  auto classConstruct = m_functions.count("__construct");
  auto className = m_functions.count(getName());
  if ((traitConstruct && traitName) ||
      (traitConstruct && className) ||
      (classConstruct && traitName)) {
    getStmt()->analysisTimeFatal(
      Compiler::InvalidDerivation,
      "%s has colliding constructor definitions coming from traits",
      getOriginalName().c_str()
    );
  }

  for (unsigned i = 0; i < importedTraitsWithOrigName.size(); i++) {
    const string &sourceName = importedTraitsWithOrigName[i].first;
    const TraitMethod *traitMethod = importedTraitsWithOrigName[i].second;
    MethodStatementPtr newMeth = importTraitMethod(
      *traitMethod, ar, toLower(traitMethod->m_originalName),
      importedTraitMethods);
    if (newMeth) {
      importedTraitMethods[sourceName] = newMeth;
    }
  }

  // Import trait properties
  importTraitProperties(ar);

  m_traitStatus = FLATTENED;
}