예제 #1
0
ConversionRank CallCandidate::updateConversionRank() {
  conversionRank_ = IdenticalTypes;
  conversionCount_ = 0;

  size_t argCount = callExpr_->argCount();
  for (size_t argIndex = 0; argIndex < argCount; ++argIndex) {
    Expr * argExpr = callExpr_->arg(argIndex);
    QualifiedType paramType = this->paramType(argIndex);
    combineConversionRanks(TypeConversion::check(argExpr, paramType, TypeConversion::COERCE));
  }

  QualifiedType expectedReturnType = callExpr_->expectedReturnType();
  if (!expectedReturnType.isNull() && callExpr_->exprType() != Expr::Construct) {
    AnalyzerBase::analyzeType(resultType_, Task_PrepTypeComparison);
    combineConversionRanks(
        TypeConversion::check(resultType_, expectedReturnType, TypeConversion::COERCE));
  }

  // If there are explicit specializations, then check those too.
  // Note that these must be an exact match.
  if (spCandidate_ != NULL) {
    combineConversionRanks(spCandidate_->updateConversionRank());
  }

  if (method_ != NULL && !method_->checkMutableSelf(base_)) {
    combineConversionRanks(QualifierLoss);
  }

#if 0
  if (typeArgs_ != NULL) {
    size_t typeArgCount = typeArgs_->size();
    for (size_t i = 0; i < typeArgCount; ++i) {
      const Type * typeArg = (*typeArgs_)[i];
      const Type * typeParam = (*typeParams_)[i];
      ConversionRank rank = typeParam->canConvert(typeArg);
      if (rank < IdenticalTypes) {
        conversionRank_ = Incompatible;
        break;
      }
    }
  }
#endif

  return conversionRank_;
}
예제 #2
0
void CallCandidate::reportConversionErrors() {
  diag.info(method_) << Format_Type << method_ << " [" << conversionRank_ << "]";

  size_t argCount = callExpr_->argCount();
  for (size_t argIndex = 0; argIndex < argCount; ++argIndex) {
    Expr * argExpr = callExpr_->arg(argIndex);
    QualifiedType paramType = this->paramType(argIndex);
    ConversionRank rank = TypeConversion::check(argExpr, paramType, TypeConversion::COERCE);
    if (isConversionWarning(rank)) {
      diag.indent();
      diag.info(callExpr_) << compatibilityError(rank) << Format_Dealias << " converting argument " <<
          argIndex << " from '" << argExpr->type() << "' to '" << paramType << "'.";
      diag.unindent();
    }
  }

  QualifiedType expectedReturnType = callExpr_->expectedReturnType();
  if (!expectedReturnType.isNull() && callExpr_->exprType() != Expr::Construct) {
    AnalyzerBase::analyzeType(resultType_, Task_PrepTypeComparison);
    ConversionRank rank = TypeConversion::check(
        resultType_, expectedReturnType, TypeConversion::COERCE);
    if (isConversionWarning(rank)) {
      diag.indent();
      diag.info(callExpr_) << compatibilityError(rank) << Format_Dealias <<
          " converting return value from '" << resultType_ << "' to '" <<
          expectedReturnType << "'.";
      diag.unindent();
    }
  }

  // If there are explicit specializations, then check those too.
  // Note that these must be an exact match.
  if (spCandidate_ != NULL) {
    spCandidate_->reportConversionErrors();
  }

  if (method_ != NULL && !method_->checkMutableSelf(base_)) {
    diag.indent();
    diag.info(callExpr_) << "Non-readonly method with a readonly 'self' argument";
    diag.unindent();
  }
}
예제 #3
0
bool CallCandidate::unify(CallExpr * callExpr, BindingEnv & env, FormatStream * errStrm) {
  size_t argCount = callExpr_->argCount();
  for (size_t argIndex = 0; argIndex < argCount; ++argIndex) {
    QualifiedType paramType = this->paramType(argIndex);
    AnalyzerBase::analyzeType(paramType, Task_PrepConversion);
  }

  if (!isTemplate_) {
    return true;
  }

  // Now, for each parameter attempt unification.
  SourceContext callSite(callExpr, NULL, callExpr);
  SourceContext candidateSite(method_, &callSite, method_, Format_Type);

  // Unify explicit template arguments with template parameters.
  if (spCandidate_ != NULL) {
    if (!spCandidate_->unify(&candidateSite, env)) {
      return false;
    }
  }

  //bool hasUnsizedArgs = false;
  for (size_t argIndex = 0; argIndex < argCount; ++argIndex) {
    Expr * argExpr = callExpr_->arg(argIndex);
    QualifiedType argType = argExpr->type();
    QualifiedType paramType = this->paramType(argIndex);

    // Skip unsized type integers for now, we'll bind them on the second pass.
    if (!env.unify(&candidateSite, paramType, argType, Constraint::LOWER_BOUND)) {
      if (errStrm) {
        *errStrm << "Argument #" << argIndex + 1 << " type " << paramType <<
            " failed to unify with " << argType;
      }
      return false;
    }
  }

  // Unify the return type
  QualifiedType expectedReturnType = callExpr_->expectedReturnType();
  if (!expectedReturnType.isNull()) {
    if (!env.unify(&candidateSite, resultType_, expectedReturnType, Constraint::UPPER_BOUND)) {
      if (errStrm) {
        *errStrm << "Return type " << expectedReturnType << " failed to unify with " << resultType_;
      }
      return false;
    }
  }

  // A proper unification requires that each template parameter be bound to something.
  for (Defn * def = method_; def != NULL && !def->isSingular(); def = def->parentDefn()) {
    Template * ts = def->templateSignature();
    if (ts != NULL) {
      size_t numParams = ts->typeParams()->size();
      // For each template parameter, create a TypeAssignment instance.
      for (size_t i = 0; i < numParams; ++i) {
        const TypeVariable * var = ts->patternVar(i);
        const TypeAssignment * ta = env.getAssignment(var, this);
        if (ta->constraints().empty()) {
          if (errStrm) {
            *errStrm << "No binding for template parameter " << var << " in " << env;
          }
          return false;
        }
      }
    }
  }

  return true;
}