Implement 1.20 style function signature matching under implicit conversion. This was the last key unimplemented feature of versions 120 through 330.
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23798 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
8cbd18ecaa
commit
0d22e31c75
36 changed files with 323 additions and 65 deletions
|
|
@ -846,20 +846,30 @@ public:
|
|||
// See if two types match, in all aspects except arrayness
|
||||
bool sameElementType(const TType& right) const
|
||||
{
|
||||
return basicType == right.basicType &&
|
||||
sampler == right.sampler &&
|
||||
return basicType == right.basicType && sameElementShape(right);
|
||||
}
|
||||
|
||||
// See if two type's arrayness match
|
||||
bool sameArrayness(const TType& right) const
|
||||
{
|
||||
return ((arraySizes == 0 && right.arraySizes == 0) ||
|
||||
(arraySizes && right.arraySizes && arraySizes->sizes == right.arraySizes->sizes));
|
||||
}
|
||||
|
||||
// See if two type's elements match in all ways except basic type
|
||||
bool sameElementShape(const TType& right) const
|
||||
{
|
||||
return sampler == right.sampler &&
|
||||
vectorSize == right.vectorSize &&
|
||||
matrixCols == right.matrixCols &&
|
||||
matrixRows == right.matrixRows &&
|
||||
sameStructType(right);
|
||||
}
|
||||
|
||||
// See if two types match in all ways (just the actual type, not qualification
|
||||
// See if two types match in all ways (just the actual type, not qualification)
|
||||
bool operator==(const TType& right) const
|
||||
{
|
||||
return sameElementType(right) &&
|
||||
((arraySizes == 0 && right.arraySizes == 0) ||
|
||||
(arraySizes && right.arraySizes && arraySizes->sizes == right.arraySizes->sizes));
|
||||
return sameElementType(right) && sameArrayness(right);
|
||||
}
|
||||
|
||||
bool operator!=(const TType& right) const
|
||||
|
|
|
|||
|
|
@ -829,7 +829,13 @@ TIntermAggregate* TParseContext::handleFunctionPrototype(TSourceLoc loc, TFuncti
|
|||
}
|
||||
|
||||
//
|
||||
// Handle seeing a function call in the grammar.
|
||||
// Handle seeing function call syntax in the grammar, which could be any of
|
||||
// - .length() method
|
||||
// - constructor
|
||||
// - a call to a built-in function mapped to an operator
|
||||
// - a call to a built-in function that will remain a function call (e.g., texturing)
|
||||
// - user function
|
||||
// - subroutine call (not implemented yet)
|
||||
//
|
||||
TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCall, TIntermNode* intermNode, TIntermAggregate* intermAggregate)
|
||||
{
|
||||
|
|
@ -866,11 +872,11 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
|
|||
}
|
||||
} else {
|
||||
//
|
||||
// Not a constructor. Find it in the symbol table.
|
||||
// Find it in the symbol table.
|
||||
//
|
||||
const TFunction* fnCandidate;
|
||||
bool builtIn;
|
||||
fnCandidate = findFunction(loc, fnCall, &builtIn);
|
||||
fnCandidate = findFunction(loc, *fnCall, builtIn);
|
||||
if (fnCandidate) {
|
||||
//
|
||||
// A declared function. But, it might still map to a built-in
|
||||
|
|
@ -898,6 +904,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
|
|||
intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName());
|
||||
}
|
||||
|
||||
// Make sure storage qualifications work for these arguments.
|
||||
TStorageQualifier qual;
|
||||
TQualifierList& qualifierList = result->getAsAggregate()->getQualifierList();
|
||||
for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
|
||||
|
|
@ -912,12 +919,6 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
|
|||
if (builtIn)
|
||||
nonOpBuiltInCheck(loc, *fnCandidate, result->getAsAggregate());
|
||||
}
|
||||
} else {
|
||||
// error message was put out by PaFindFunction()
|
||||
// Put on a dummy node for error recovery
|
||||
TConstUnionArray unionArray(1);
|
||||
unionArray[0].setDConst(0.0);
|
||||
result = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), loc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2543,26 +2544,107 @@ void TParseContext::checkNoShaderLayouts(TSourceLoc loc, const TPublicType& publ
|
|||
//
|
||||
// Return the function symbol if found, otherwise 0.
|
||||
//
|
||||
const TFunction* TParseContext::findFunction(TSourceLoc loc, TFunction* call, bool *builtIn)
|
||||
const TFunction* TParseContext::findFunction(TSourceLoc loc, const TFunction& call, bool& builtIn)
|
||||
{
|
||||
TSymbol* symbol = symbolTable.find(call->getMangledName(), builtIn);
|
||||
const TFunction* function = 0;
|
||||
|
||||
if (symbol == 0) {
|
||||
error(loc, "no matching overloaded function found", call->getName().c_str(), "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const TFunction* function = symbol->getAsFunction();
|
||||
if (! function) {
|
||||
error(loc, "function name expected", call->getName().c_str(), "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
if (profile == EEsProfile || version < 120)
|
||||
function = findFunctionExact(loc, call, builtIn);
|
||||
else if (version < 400)
|
||||
function = findFunction120(loc, call, builtIn);
|
||||
else
|
||||
function = findFunction400(loc, call, builtIn);
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
// Function finding algorithm for ES and desktop 110.
|
||||
const TFunction* TParseContext::findFunctionExact(TSourceLoc loc, const TFunction& call, bool& builtIn)
|
||||
{
|
||||
const TFunction* function = 0;
|
||||
|
||||
TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
|
||||
if (symbol == 0) {
|
||||
error(loc, "no matching overloaded function found", call.getName().c_str(), "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return symbol->getAsFunction();
|
||||
}
|
||||
|
||||
// Function finding algorithm for desktop versions 120 through 330.
|
||||
const TFunction* TParseContext::findFunction120(TSourceLoc loc, const TFunction& call, bool& builtIn)
|
||||
{
|
||||
// first, look for an exact match
|
||||
TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
|
||||
if (symbol)
|
||||
return symbol->getAsFunction();
|
||||
|
||||
// exact match not found, look through a list of overloaded functions of the same name
|
||||
|
||||
// "If no exact match is found, then [implicit conversions] will be applied to find a match. Mismatched types
|
||||
// on input parameters (in or inout or default) must have a conversion from the calling argument type to the
|
||||
// formal parameter type. Mismatched types on output parameters (out or inout) must have a conversion
|
||||
// from the formal parameter type to the calling argument type. When argument conversions are used to find
|
||||
// a match, it is a semantic error if there are multiple ways to apply these conversions to make the call match
|
||||
// more than one function."
|
||||
|
||||
const TFunction* candidate = 0;
|
||||
TVector<TFunction*> candidateList;
|
||||
symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
|
||||
|
||||
int numPossibleMatches = 0;
|
||||
for (TVector<TFunction*>::const_iterator it = candidateList.begin(); it != candidateList.end(); ++it) {
|
||||
bool possibleMatch = true;
|
||||
const TFunction& function = *(*it);
|
||||
for (int i = 0; i < function.getParamCount(); ++i) {
|
||||
// same types is easy
|
||||
if (*function[i].type == *call[i].type)
|
||||
continue;
|
||||
|
||||
// We have a mismatch in type, see if it is implicitly convertible
|
||||
|
||||
if (function[i].type->isArray() || call[i].type->isArray() ||
|
||||
! function[i].type->sameElementShape(*call[i].type))
|
||||
possibleMatch = false;
|
||||
else {
|
||||
// do direction-specific checks for conversion of basic type
|
||||
TStorageQualifier qualifier = function[i].type->getQualifier().storage;
|
||||
if (qualifier == EvqIn || qualifier == EvqInOut) {
|
||||
if (! intermediate.canImplicitlyPromote(call[i].type->getBasicType(), function[i].type->getBasicType()))
|
||||
possibleMatch = false;
|
||||
}
|
||||
if (qualifier == EvqOut || qualifier == EvqInOut) {
|
||||
if (! intermediate.canImplicitlyPromote(function[i].type->getBasicType(), call[i].type->getBasicType()))
|
||||
possibleMatch = false;
|
||||
}
|
||||
}
|
||||
if (! possibleMatch)
|
||||
break;
|
||||
}
|
||||
if (possibleMatch) {
|
||||
if (candidate) {
|
||||
// our second match, meaning ambiguity
|
||||
error(loc, "ambiguous function signature match: multiple signatures match under implicit type conversion", call.getName().c_str(), "");
|
||||
} else
|
||||
candidate = &function;
|
||||
}
|
||||
}
|
||||
|
||||
if (candidate == 0)
|
||||
error(loc, "no matching overloaded function found", call.getName().c_str(), "");
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
// Function finding algorithm for desktop version 400 and above.
|
||||
const TFunction* TParseContext::findFunction400(TSourceLoc loc, const TFunction& call, bool& builtIn)
|
||||
{
|
||||
// TODO: 4.00 functionality: findFunction400()
|
||||
return findFunction120(loc, call, builtIn);
|
||||
}
|
||||
|
||||
//
|
||||
// Do everything necessary to handle a variable (non-block) declaration.
|
||||
// Either redeclaring a variable, or making a new one, updating the symbol
|
||||
|
|
|
|||
|
|
@ -140,7 +140,10 @@ public:
|
|||
void layoutQualifierCheck(TSourceLoc, const TQualifier&);
|
||||
void checkNoShaderLayouts(TSourceLoc, const TPublicType&);
|
||||
|
||||
const TFunction* findFunction(TSourceLoc, TFunction* pfnCall, bool *builtIn = 0);
|
||||
const TFunction* findFunction(TSourceLoc loc, const TFunction& call, bool& builtIn);
|
||||
const TFunction* findFunctionExact(TSourceLoc loc, const TFunction& call, bool& builtIn);
|
||||
const TFunction* findFunction120(TSourceLoc loc, const TFunction& call, bool& builtIn);
|
||||
const TFunction* findFunction400(TSourceLoc loc, const TFunction& call, bool& builtIn);
|
||||
TIntermNode* declareVariable(TSourceLoc, TString& identifier, TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0);
|
||||
TIntermTyped* addConstructor(TSourceLoc, TIntermNode*, const TType&, TOperator);
|
||||
TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc);
|
||||
|
|
|
|||
|
|
@ -378,10 +378,11 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo
|
|||
switch(version) {
|
||||
case 100:
|
||||
case 300:
|
||||
// versions are complete
|
||||
break;
|
||||
|
||||
case 110:
|
||||
case 120:
|
||||
// versions are complete
|
||||
break;
|
||||
case 130:
|
||||
case 140:
|
||||
infoSink.info << "Warning, version " << version << " is not yet complete; most features are present, but a few are missing.\n";
|
||||
|
|
|
|||
|
|
@ -322,6 +322,19 @@ public:
|
|||
return (*it).second;
|
||||
}
|
||||
|
||||
void findFunctionNameList(const TString& name, TVector<TFunction*>& list)
|
||||
{
|
||||
size_t parenAt = name.find_first_of('(');
|
||||
TString base(name, 0, parenAt + 1);
|
||||
|
||||
tLevel::const_iterator begin = level.lower_bound(base);
|
||||
base[parenAt] = ')'; // assume ')' is lexically after '('
|
||||
tLevel::const_iterator end = level.upper_bound(base);
|
||||
for (tLevel::const_iterator it = begin; it != end; ++it)
|
||||
list.push_back(it->second->getAsFunction());
|
||||
}
|
||||
|
||||
// See if there is already a function in the table having the given non-function-style name.
|
||||
bool hasFunctionName(const TString& name) const
|
||||
{
|
||||
tLevel::const_iterator candidate = level.lower_bound(name);
|
||||
|
|
@ -397,7 +410,7 @@ public:
|
|||
while (table.size() > adoptedLevels)
|
||||
pop(0);
|
||||
}
|
||||
|
||||
|
||||
void adoptLevels(TSymbolTable& symTable)
|
||||
{
|
||||
for (unsigned int level = 0; level < symTable.table.size(); ++level) {
|
||||
|
|
@ -511,6 +524,27 @@ public:
|
|||
return symbol;
|
||||
}
|
||||
|
||||
void findFunctionNameList(const TString& name, TVector<TFunction*>& list, bool& builtIn)
|
||||
{
|
||||
// For user levels, return the set found in the first scope with a match
|
||||
builtIn = false;
|
||||
int level = currentLevel();
|
||||
do {
|
||||
table[level]->findFunctionNameList(name, list);
|
||||
--level;
|
||||
} while (list.empty() && level >= globalLevel);
|
||||
|
||||
if (! list.empty())
|
||||
return;
|
||||
|
||||
// Gather across all built-in levels; they don't hide each other
|
||||
builtIn = true;
|
||||
do {
|
||||
table[level]->findFunctionNameList(name, list);
|
||||
--level;
|
||||
} while (level >= 0);
|
||||
}
|
||||
|
||||
void relateToOperator(const char* name, TOperator op)
|
||||
{
|
||||
for (unsigned int level = 0; level < table.size(); ++level)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue