Print better error messages when function overload resolution fails.
This commit is contained in:
148
expr.cpp
148
expr.cpp
@@ -2206,7 +2206,7 @@ AssignExpr::TypeCheck() {
|
|||||||
for (int i = 0; i < ftype->GetNumParameters(); ++i)
|
for (int i = 0; i < ftype->GetNumParameters(); ++i)
|
||||||
paramTypes.push_back(ftype->GetParameterType(i));
|
paramTypes.push_back(ftype->GetParameterType(i));
|
||||||
|
|
||||||
if (!fse->ResolveOverloads(paramTypes)) {
|
if (!fse->ResolveOverloads(rvalue->pos, paramTypes)) {
|
||||||
Error(pos, "Unable to find overloaded function for function "
|
Error(pos, "Unable to find overloaded function for function "
|
||||||
"pointer assignment.");
|
"pointer assignment.");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -2719,7 +2719,7 @@ FunctionCallExpr::TypeCheck() {
|
|||||||
argCouldBeNULL.push_back(lIsAllIntZeros(args->exprs[i]));
|
argCouldBeNULL.push_back(lIsAllIntZeros(args->exprs[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fse->ResolveOverloads(argTypes, &argCouldBeNULL) == false)
|
if (fse->ResolveOverloads(args->pos, argTypes, &argCouldBeNULL) == false)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
func = fse->TypeCheck();
|
func = fse->TypeCheck();
|
||||||
@@ -6189,110 +6189,22 @@ FunctionSymbolExpr::GetConstant(const Type *type) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::string
|
|
||||||
lGetFunctionDeclaration(const std::string &name, const FunctionType *type) {
|
|
||||||
std::string ret;
|
|
||||||
ret += type->GetReturnType()->GetString();
|
|
||||||
ret += " ";
|
|
||||||
ret += name;
|
|
||||||
ret += "(";
|
|
||||||
|
|
||||||
for (int i = 0; i < type->GetNumParameters(); ++i) {
|
|
||||||
const Type *paramType = type->GetParameterType(i);
|
|
||||||
ConstExpr *paramDefault = type->GetParameterDefault(i);
|
|
||||||
|
|
||||||
ret += paramType->GetString();
|
|
||||||
ret += " ";
|
|
||||||
ret += type->GetParameterName(i);
|
|
||||||
|
|
||||||
// Print the default value if present
|
|
||||||
if (paramDefault != NULL) {
|
|
||||||
char buf[32];
|
|
||||||
if (paramType->IsFloatType()) {
|
|
||||||
double val;
|
|
||||||
int count = paramDefault->AsDouble(&val);
|
|
||||||
assert(count == 1);
|
|
||||||
sprintf(buf, " = %g", val);
|
|
||||||
}
|
|
||||||
else if (paramType->IsBoolType()) {
|
|
||||||
bool val;
|
|
||||||
int count = paramDefault->AsBool(&val);
|
|
||||||
assert(count == 1);
|
|
||||||
sprintf(buf, " = %s", val ? "true" : "false");
|
|
||||||
}
|
|
||||||
else if (paramType->IsUnsignedType()) {
|
|
||||||
uint64_t val;
|
|
||||||
int count = paramDefault->AsUInt64(&val);
|
|
||||||
assert(count == 1);
|
|
||||||
#ifdef ISPC_IS_LINUX
|
|
||||||
sprintf(buf, " = %lu", val);
|
|
||||||
#else
|
|
||||||
sprintf(buf, " = %llu", val);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int64_t val;
|
|
||||||
int count = paramDefault->AsInt64(&val);
|
|
||||||
assert(count == 1);
|
|
||||||
#ifdef ISPC_IS_LINUX
|
|
||||||
sprintf(buf, " = %ld", val);
|
|
||||||
#else
|
|
||||||
sprintf(buf, " = %lld", val);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
ret += buf;
|
|
||||||
}
|
|
||||||
if (i != type->GetNumParameters() - 1)
|
|
||||||
ret += ", ";
|
|
||||||
}
|
|
||||||
ret += ")";
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lPrintFunctionOverloads(const std::string &name,
|
lPrintOverloadCandidates(SourcePos pos, const std::vector<Symbol *> &funcs,
|
||||||
const std::vector<std::pair<int, Symbol *> > &matches) {
|
const std::vector<const Type *> &argTypes,
|
||||||
fprintf(stderr, "Matching functions:\n");
|
const std::vector<bool> *argCouldBeNULL) {
|
||||||
int minCost = matches[0].first;
|
for (unsigned int i = 0; i < funcs.size(); ++i)
|
||||||
for (unsigned int i = 1; i < matches.size(); ++i)
|
Error(funcs[i]->pos, "Candidate function:");
|
||||||
minCost = std::min(minCost, matches[i].first);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < matches.size(); ++i) {
|
std::string passedTypes = "Passed types: (";
|
||||||
const FunctionType *t =
|
|
||||||
dynamic_cast<const FunctionType *>(matches[i].second->type);
|
|
||||||
assert(t != NULL);
|
|
||||||
if (matches[i].first == minCost)
|
|
||||||
fprintf(stderr, "\t%s\n", lGetFunctionDeclaration(name, t).c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
lPrintFunctionOverloads(const std::string &name,
|
|
||||||
const std::vector<Symbol *> &funcs) {
|
|
||||||
fprintf(stderr, "Candidate functions:\n");
|
|
||||||
for (unsigned int i = 0; i < funcs.size(); ++i) {
|
|
||||||
const FunctionType *t =
|
|
||||||
dynamic_cast<const FunctionType *>(funcs[i]->type);
|
|
||||||
assert(t != NULL);
|
|
||||||
fprintf(stderr, "\t%s\n", lGetFunctionDeclaration(name, t).c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
lPrintPassedTypes(const char *funName,
|
|
||||||
const std::vector<const Type *> &argTypes) {
|
|
||||||
fprintf(stderr, "Passed types: %*c(", (int)strlen(funName), ' ');
|
|
||||||
for (unsigned int i = 0; i < argTypes.size(); ++i) {
|
for (unsigned int i = 0; i < argTypes.size(); ++i) {
|
||||||
if (argTypes[i] != NULL)
|
if (argTypes[i] != NULL)
|
||||||
fprintf(stderr, "%s%s", argTypes[i]->GetString().c_str(),
|
passedTypes += argTypes[i]->GetString();
|
||||||
(i < argTypes.size()-1) ? ", " : ")\n\n");
|
|
||||||
else
|
else
|
||||||
fprintf(stderr, "(unknown type)%s",
|
passedTypes += "(unknown type)";
|
||||||
(i < argTypes.size()-1) ? ", " : ")\n\n");
|
passedTypes += (i < argTypes.size()-1) ? ", " : ")\n\n";
|
||||||
}
|
}
|
||||||
|
Error(pos, "%s", passedTypes.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -6468,6 +6380,7 @@ lGetBestMatch(std::vector<std::pair<int, Symbol *> > &matches) {
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
FunctionSymbolExpr::tryResolve(int (*matchFunc)(const Type *, const Type *),
|
FunctionSymbolExpr::tryResolve(int (*matchFunc)(const Type *, const Type *),
|
||||||
|
SourcePos argPos,
|
||||||
const std::vector<const Type *> &callTypes,
|
const std::vector<const Type *> &callTypes,
|
||||||
const std::vector<bool> *argCouldBeNULL) {
|
const std::vector<bool> *argCouldBeNULL) {
|
||||||
const char *funName = candidateFunctions.front()->name.c_str();
|
const char *funName = candidateFunctions.front()->name.c_str();
|
||||||
@@ -6547,8 +6460,19 @@ FunctionSymbolExpr::tryResolve(int (*matchFunc)(const Type *, const Type *),
|
|||||||
else {
|
else {
|
||||||
Error(pos, "Multiple overloaded instances of function \"%s\" matched.",
|
Error(pos, "Multiple overloaded instances of function \"%s\" matched.",
|
||||||
funName);
|
funName);
|
||||||
lPrintFunctionOverloads(funName, matches);
|
|
||||||
lPrintPassedTypes(funName, callTypes);
|
// select the matches that have the lowest cost
|
||||||
|
std::vector<Symbol *> bestMatches;
|
||||||
|
int minCost = matches[0].first;
|
||||||
|
for (unsigned int i = 1; i < matches.size(); ++i)
|
||||||
|
minCost = std::min(minCost, matches[i].first);
|
||||||
|
for (unsigned int i = 0; i < matches.size(); ++i)
|
||||||
|
if (matches[i].first == minCost)
|
||||||
|
bestMatches.push_back(matches[i].second);
|
||||||
|
|
||||||
|
// And print a useful error message
|
||||||
|
lPrintOverloadCandidates(argPos, bestMatches, callTypes, argCouldBeNULL);
|
||||||
|
|
||||||
// Stop trying to find more matches after an ambigious set of
|
// Stop trying to find more matches after an ambigious set of
|
||||||
// matches.
|
// matches.
|
||||||
return true;
|
return true;
|
||||||
@@ -6557,7 +6481,8 @@ FunctionSymbolExpr::tryResolve(int (*matchFunc)(const Type *, const Type *),
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FunctionSymbolExpr::ResolveOverloads(const std::vector<const Type *> &argTypes,
|
FunctionSymbolExpr::ResolveOverloads(SourcePos argPos,
|
||||||
|
const std::vector<const Type *> &argTypes,
|
||||||
const std::vector<bool> *argCouldBeNULL) {
|
const std::vector<bool> *argCouldBeNULL) {
|
||||||
triedToResolve = true;
|
triedToResolve = true;
|
||||||
|
|
||||||
@@ -6571,32 +6496,33 @@ FunctionSymbolExpr::ResolveOverloads(const std::vector<const Type *> &argTypes,
|
|||||||
|
|
||||||
// Is there an exact match that doesn't require any argument type
|
// Is there an exact match that doesn't require any argument type
|
||||||
// conversion (other than converting type -> reference type)?
|
// conversion (other than converting type -> reference type)?
|
||||||
if (tryResolve(lExactMatch, argTypes, argCouldBeNULL))
|
if (tryResolve(lExactMatch, argPos, argTypes, argCouldBeNULL))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (exactMatchOnly == false) {
|
if (exactMatchOnly == false) {
|
||||||
// Try to find a single match ignoring references
|
// Try to find a single match ignoring references
|
||||||
if (tryResolve(lMatchIgnoringReferences, argTypes, argCouldBeNULL))
|
if (tryResolve(lMatchIgnoringReferences, argPos, argTypes,
|
||||||
|
argCouldBeNULL))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Try to find an exact match via type widening--i.e. int8 ->
|
// Try to find an exact match via type widening--i.e. int8 ->
|
||||||
// int16, etc.--things that don't lose data.
|
// int16, etc.--things that don't lose data.
|
||||||
if (tryResolve(lMatchWithTypeWidening, argTypes, argCouldBeNULL))
|
if (tryResolve(lMatchWithTypeWidening, argPos, argTypes, argCouldBeNULL))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Next try to see if there's a match via just uniform -> varying
|
// Next try to see if there's a match via just uniform -> varying
|
||||||
// promotions.
|
// promotions.
|
||||||
if (tryResolve(lMatchIgnoringUniform, argTypes, argCouldBeNULL))
|
if (tryResolve(lMatchIgnoringUniform, argPos, argTypes, argCouldBeNULL))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Try to find a match via type conversion, but don't change
|
// Try to find a match via type conversion, but don't change
|
||||||
// unif->varying
|
// unif->varying
|
||||||
if (tryResolve(lMatchWithTypeConvSameVariability, argTypes,
|
if (tryResolve(lMatchWithTypeConvSameVariability, argPos, argTypes,
|
||||||
argCouldBeNULL))
|
argCouldBeNULL))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Last chance: try to find a match via arbitrary type conversion.
|
// Last chance: try to find a match via arbitrary type conversion.
|
||||||
if (tryResolve(lMatchWithTypeConv, argTypes, argCouldBeNULL))
|
if (tryResolve(lMatchWithTypeConv, argPos, argTypes, argCouldBeNULL))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6604,8 +6530,8 @@ FunctionSymbolExpr::ResolveOverloads(const std::vector<const Type *> &argTypes,
|
|||||||
const char *funName = candidateFunctions.front()->name.c_str();
|
const char *funName = candidateFunctions.front()->name.c_str();
|
||||||
Error(pos, "Unable to find matching overload for call to function \"%s\"%s.",
|
Error(pos, "Unable to find matching overload for call to function \"%s\"%s.",
|
||||||
funName, exactMatchOnly ? " only considering exact matches" : "");
|
funName, exactMatchOnly ? " only considering exact matches" : "");
|
||||||
lPrintFunctionOverloads(funName, candidateFunctions);
|
lPrintOverloadCandidates(argPos, candidateFunctions, argTypes,
|
||||||
lPrintPassedTypes(funName, argTypes);
|
argCouldBeNULL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
expr.h
5
expr.h
@@ -634,13 +634,14 @@ public:
|
|||||||
being done just given type information without the parameter
|
being done just given type information without the parameter
|
||||||
argument expressions being available. It returns true on success.
|
argument expressions being available. It returns true on success.
|
||||||
*/
|
*/
|
||||||
bool ResolveOverloads(const std::vector<const Type *> &argTypes,
|
bool ResolveOverloads(SourcePos argPos,
|
||||||
|
const std::vector<const Type *> &argTypes,
|
||||||
const std::vector<bool> *argCouldBeNULL = NULL);
|
const std::vector<bool> *argCouldBeNULL = NULL);
|
||||||
Symbol *GetMatchingFunction();
|
Symbol *GetMatchingFunction();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool tryResolve(int (*matchFunc)(const Type *, const Type *),
|
bool tryResolve(int (*matchFunc)(const Type *, const Type *),
|
||||||
const std::vector<const Type *> &argTypes,
|
SourcePos argPos, const std::vector<const Type *> &argTypes,
|
||||||
const std::vector<bool> *argCouldBeNULL);
|
const std::vector<bool> *argCouldBeNULL);
|
||||||
|
|
||||||
/** Name of the function that is being called. */
|
/** Name of the function that is being called. */
|
||||||
|
|||||||
2
stmt.cpp
2
stmt.cpp
@@ -135,7 +135,7 @@ lPossiblyResolveFunctionOverloads(Expr *expr, const Type *type) {
|
|||||||
for (int i = 0; i < funcType->GetNumParameters(); ++i)
|
for (int i = 0; i < funcType->GetNumParameters(); ++i)
|
||||||
paramTypes.push_back(funcType->GetParameterType(i));
|
paramTypes.push_back(funcType->GetParameterType(i));
|
||||||
|
|
||||||
if (fse->ResolveOverloads(paramTypes) == false)
|
if (fse->ResolveOverloads(expr->pos, paramTypes) == false)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user