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_; }
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(); } }
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; }