Update function overload resolution logic.
Closer compatibility with C++: given a non-reference type, treat matching to a non-const reference of that type as a better match than a const reference of that type (rather than both being equal cost). Issue #224.
This commit is contained in:
67
expr.cpp
67
expr.cpp
@@ -7498,6 +7498,23 @@ lPrintOverloadCandidates(SourcePos pos, const std::vector<Symbol *> &funcs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
lIsMatchToNonConstReference(const Type *callType, const Type *funcArgType) {
|
||||||
|
return (dynamic_cast<const ReferenceType *>(funcArgType) &&
|
||||||
|
(funcArgType->IsConstType() == false) &&
|
||||||
|
Type::Equal(callType, funcArgType->GetReferenceTarget()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
lIsMatchToNonConstReferenceUnifToVarying(const Type *callType,
|
||||||
|
const Type *funcArgType) {
|
||||||
|
return (dynamic_cast<const ReferenceType *>(funcArgType) &&
|
||||||
|
(funcArgType->IsConstType() == false) &&
|
||||||
|
Type::Equal(callType->GetAsVaryingType(),
|
||||||
|
funcArgType->GetReferenceTarget()));
|
||||||
|
}
|
||||||
|
|
||||||
/** Helper function used for function overload resolution: returns true if
|
/** Helper function used for function overload resolution: returns true if
|
||||||
converting the argument to the call type only requires a type
|
converting the argument to the call type only requires a type
|
||||||
conversion that won't lose information. Otherwise return false.
|
conversion that won't lose information. Otherwise return false.
|
||||||
@@ -7597,6 +7614,20 @@ FunctionSymbolExpr::getCandidateFunctions(int argCount) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
lArgIsPointerType(const Type *type) {
|
||||||
|
if (dynamic_cast<const PointerType *>(type) != NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const ReferenceType *rt = dynamic_cast<const ReferenceType *>(type);
|
||||||
|
if (rt == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const Type *t = rt->GetReferenceTarget();
|
||||||
|
return (dynamic_cast<const PointerType *>(t) != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** This function computes the value of a cost function that represents the
|
/** This function computes the value of a cost function that represents the
|
||||||
cost of calling a function of the given type with arguments of the
|
cost of calling a function of the given type with arguments of the
|
||||||
given types. If it's not possible to call the function, regardless of
|
given types. If it's not possible to call the function, regardless of
|
||||||
@@ -7623,19 +7654,11 @@ FunctionSymbolExpr::computeOverloadCost(const FunctionType *ftype,
|
|||||||
const Type *fargType = ftype->GetParameterType(i);
|
const Type *fargType = ftype->GetParameterType(i);
|
||||||
const Type *callType = argTypes[i];
|
const Type *callType = argTypes[i];
|
||||||
|
|
||||||
// For convenience, normalize to non-const types (except for
|
|
||||||
// references, where const-ness matters). For all other types,
|
|
||||||
// we're passing by value anyway, so const doesn't matter.
|
|
||||||
if (dynamic_cast<const ReferenceType *>(callType) == NULL)
|
|
||||||
callType = callType->GetAsNonConstType();
|
|
||||||
if (dynamic_cast<const ReferenceType *>(fargType) == NULL)
|
|
||||||
fargType = fargType->GetAsNonConstType();
|
|
||||||
|
|
||||||
if (Type::Equal(callType, fargType))
|
if (Type::Equal(callType, fargType))
|
||||||
// Perfect match: no cost
|
// Perfect match: no cost
|
||||||
costSum += 0;
|
costSum += 0;
|
||||||
else if (argCouldBeNULL && (*argCouldBeNULL)[i] &&
|
else if (argCouldBeNULL && (*argCouldBeNULL)[i] &&
|
||||||
dynamic_cast<const PointerType *>(fargType) != NULL)
|
lArgIsPointerType(fargType))
|
||||||
// Passing NULL to a pointer-typed parameter is also a no-cost
|
// Passing NULL to a pointer-typed parameter is also a no-cost
|
||||||
// operation
|
// operation
|
||||||
costSum += 0;
|
costSum += 0;
|
||||||
@@ -7645,19 +7668,33 @@ FunctionSymbolExpr::computeOverloadCost(const FunctionType *ftype,
|
|||||||
// cost if it wasn't--so scale up the cost when this isn't the
|
// cost if it wasn't--so scale up the cost when this isn't the
|
||||||
// case..
|
// case..
|
||||||
if (argIsConstant == NULL || (*argIsConstant)[i] == false)
|
if (argIsConstant == NULL || (*argIsConstant)[i] == false)
|
||||||
costScale *= 32;
|
costScale *= 128;
|
||||||
|
|
||||||
if (Type::Equal(callType, fargType))
|
// For convenience, normalize to non-const types (except for
|
||||||
|
// references, where const-ness matters). For all other types,
|
||||||
|
// we're passing by value anyway, so const doesn't matter.
|
||||||
|
const Type *callTypeNC = callType, *fargTypeNC = fargType;
|
||||||
|
if (dynamic_cast<const ReferenceType *>(callType) == NULL)
|
||||||
|
callTypeNC = callType->GetAsNonConstType();
|
||||||
|
if (dynamic_cast<const ReferenceType *>(fargType) == NULL)
|
||||||
|
fargTypeNC = fargType->GetAsNonConstType();
|
||||||
|
|
||||||
|
if (Type::Equal(callTypeNC, fargTypeNC))
|
||||||
// Exact match (after dealing with references, above)
|
// Exact match (after dealing with references, above)
|
||||||
costSum += 1 * costScale;
|
costSum += 1 * costScale;
|
||||||
else if (lIsMatchWithTypeWidening(callType, fargType))
|
// note: orig fargType for the next two...
|
||||||
|
else if (lIsMatchToNonConstReference(callTypeNC, fargType))
|
||||||
costSum += 2 * costScale;
|
costSum += 2 * costScale;
|
||||||
else if (lIsMatchWithUniformToVarying(callType, fargType))
|
else if (lIsMatchToNonConstReferenceUnifToVarying(callTypeNC, fargType))
|
||||||
costSum += 4 * costScale;
|
costSum += 4 * costScale;
|
||||||
else if (lIsMatchWithTypeConvSameVariability(callType, fargType))
|
else if (lIsMatchWithTypeWidening(callTypeNC, fargTypeNC))
|
||||||
costSum += 8 * costScale;
|
costSum += 8 * costScale;
|
||||||
else if (CanConvertTypes(callType, fargType))
|
else if (lIsMatchWithUniformToVarying(callTypeNC, fargTypeNC))
|
||||||
costSum += 16 * costScale;
|
costSum += 16 * costScale;
|
||||||
|
else if (lIsMatchWithTypeConvSameVariability(callTypeNC, fargTypeNC))
|
||||||
|
costSum += 32 * costScale;
|
||||||
|
else if (CanConvertTypes(callTypeNC, fargTypeNC))
|
||||||
|
costSum += 64 * costScale;
|
||||||
else
|
else
|
||||||
// Failure--no type conversion possible...
|
// Failure--no type conversion possible...
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
14
tests/func-overload-refs.ispc
Normal file
14
tests/func-overload-refs.ispc
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
export uniform int width() { return programCount; }
|
||||||
|
|
||||||
|
float foo(float &a) { return 1; }
|
||||||
|
float foo(const float &a) { return 2; }
|
||||||
|
|
||||||
|
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||||
|
float x = 0;
|
||||||
|
RET[programIndex] = foo(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
export void result(uniform float RET[]) {
|
||||||
|
RET[programIndex] = 1;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user