refactoring match algorithm to not use recursion

This commit is contained in:
davu 2023-03-22 11:35:21 +01:00
parent c324b60da3
commit 15881dca19
1 changed files with 52 additions and 45 deletions

View File

@ -41,7 +41,7 @@ enum string[string] INTEGER_PROMOTIONS = [
"dchar": "uint", "dchar": "uint",
]; ];
enum MAX_RECURSION_DEPTH = 50; enum MAX_NUMBER_OF_MATCHING_RUNS = 50;
private const(DSymbol)* deduceSymbolType(const(DSymbol)* symbol) private const(DSymbol)* deduceSymbolType(const(DSymbol)* symbol)
{ {
@ -257,60 +257,74 @@ private DSymbol*[] getUFCSSymbolsForParenCompletion(const(DSymbol)* symbolType,
} }
private bool willImplicitBeUpcasted(const(DSymbol)* from, const(DSymbol)* to) private bool willImplicitBeUpcasted(ref const(DSymbol) incomingSymbolType, ref const(DSymbol) significantSymbolType)
{ {
if (from is null || to is null || to.functionParameters.empty || to.functionParameters.front.type is null) { string fromTypeName = significantSymbolType.name.data;
return false; string toTypeName = incomingSymbolType.name.data;
}
string fromTypeName = from.name.data;
string toTypeName = to.functionParameters.front.type.name.data;
return typeWillBeUpcastedTo(fromTypeName, toTypeName); return typeWillBeUpcastedTo(fromTypeName, toTypeName);
} }
private bool typeWillBeUpcastedTo(string from, string to) { private bool typeWillBeUpcastedTo(string from, string to)
{
if (auto promotionType = from in INTEGER_PROMOTIONS) if (auto promotionType = from in INTEGER_PROMOTIONS)
return *promotionType == to; return *promotionType == to;
return false; return false;
} }
private bool matchAliasThis(const(DSymbol)* beforeDotType, const(DSymbol)* incomingSymbol, int recursionDepth) bool isNonConstrainedTemplate(ref const(DSymbol) symbolType)
{ {
// For now we are only resolving the first alias this symbol return symbolType.kind is CompletionKind.typeTmpParam;
// when multiple alias this are supported, we can rethink another solution
if (beforeDotType.aliasThisSymbols.empty || beforeDotType.aliasThisSymbols.front == beforeDotType)
{
return false;
}
//Incrementing depth count to ensure we don't run into an infinite loop
recursionDepth++;
return isCallableWithArg(incomingSymbol, beforeDotType.aliasThisSymbols.front.type, false, recursionDepth);
} }
bool isNonConstrainedTemplate(const(DSymbol)* incomingSymbol){ private bool matchesWithTypeOfPointer(ref const(DSymbol) incomingSymbolType, ref const(DSymbol) significantSymbolType)
return incomingSymbol.functionParameters.front.type !is null {
&& incomingSymbol.functionParameters.front.type.kind is CompletionKind.typeTmpParam; return incomingSymbolType.qualifier == SymbolQualifier.pointer
&& significantSymbolType.qualifier == SymbolQualifier.pointer
&& incomingSymbolType.type is significantSymbolType.type;
} }
private bool matchesWithTypeOfPointer(const(DSymbol)* incomingSymbol, const(DSymbol)* cursorSymbolType) { private bool matchesWithTypeOfArray(ref const(DSymbol) incomingSymbolType, ref const(DSymbol) cursorSymbolType)
{
return incomingSymbol.functionParameters.front.type.qualifier == SymbolQualifier.pointer return incomingSymbolType.qualifier == SymbolQualifier.array
&& cursorSymbolType.qualifier == SymbolQualifier.pointer
&& incomingSymbol.functionParameters.front.type.type is cursorSymbolType.type;
}
private bool matchesWithTypeOfArray(const(DSymbol)* incomingSymbol, const(DSymbol)* cursorSymbolType) {
return incomingSymbol.functionParameters.front.type.qualifier == SymbolQualifier.array
&& cursorSymbolType.qualifier == SymbolQualifier.array && cursorSymbolType.qualifier == SymbolQualifier.array
&& incomingSymbol.functionParameters.front.type.type is cursorSymbolType.type; && incomingSymbolType.type is cursorSymbolType.type;
} }
private bool typeMatchesWith(ref const(DSymbol) incomingSymbolType, ref const(DSymbol) significantSymbolType) {
return incomingSymbolType is significantSymbolType
|| isNonConstrainedTemplate(incomingSymbolType)
|| matchesWithTypeOfArray(incomingSymbolType, significantSymbolType)
|| matchesWithTypeOfPointer(incomingSymbolType, significantSymbolType)
|| willImplicitBeUpcasted(incomingSymbolType, significantSymbolType);
}
private bool matchSymbolType(const(DSymbol)* incomingSymbolType, const(DSymbol)* significantSymbolType) {
auto currentSignificantSymbolType = significantSymbolType;
uint numberOfRetries = 0;
do
{
if (typeMatchesWith(*incomingSymbolType, *currentSignificantSymbolType)){
return true;
}
if (currentSignificantSymbolType.aliasThisSymbols.empty || currentSignificantSymbolType is currentSignificantSymbolType.aliasThisSymbols.front){
return false;
}
numberOfRetries++;
// For now we are only resolving the first alias this symbol
// when multiple alias this are supported, we can rethink another solution
currentSignificantSymbolType = currentSignificantSymbolType.aliasThisSymbols.front.type;
}
while(numberOfRetries <= MAX_NUMBER_OF_MATCHING_RUNS);
return false;
}
/** /**
* Params: * Params:
* incomingSymbol = the function symbol to check if it is valid for UFCS with `beforeDotType`. * incomingSymbol = the function symbol to check if it is valid for UFCS with `beforeDotType`.
@ -320,25 +334,18 @@ private bool matchesWithTypeOfArray(const(DSymbol)* incomingSymbol, const(DSymbo
* `true` if `incomingSymbols`' first parameter matches `beforeDotType` * `true` if `incomingSymbols`' first parameter matches `beforeDotType`
* `false` otherwise * `false` otherwise
*/ */
bool isCallableWithArg(const(DSymbol)* incomingSymbol, const(DSymbol)* beforeDotType, bool isGlobalScope = false, int recursionDepth = 0) bool isCallableWithArg(const(DSymbol)* incomingSymbol, const(DSymbol)* beforeDotType, bool isGlobalScope = false)
{ {
if (incomingSymbol is null if (incomingSymbol is null
|| beforeDotType is null || beforeDotType is null
|| isGlobalScope && incomingSymbol.protection is tok!"private" // don't show private functions if we are in global scope || isGlobalScope && incomingSymbol.protection is tok!"private") // don't show private functions if we are in global scope
|| recursionDepth > MAX_RECURSION_DEPTH)
{ {
return false; return false;
} }
if (incomingSymbol.kind is CompletionKind.functionName && !incomingSymbol.functionParameters.empty && incomingSymbol.functionParameters.front.type) if (incomingSymbol.kind is CompletionKind.functionName && !incomingSymbol.functionParameters.empty && incomingSymbol.functionParameters.front.type)
{ {
return beforeDotType is incomingSymbol.functionParameters.front.type return matchSymbolType(incomingSymbol.functionParameters.front.type, beforeDotType);
|| isNonConstrainedTemplate(incomingSymbol)
|| matchesWithTypeOfArray(incomingSymbol, beforeDotType)
|| matchesWithTypeOfPointer(incomingSymbol, beforeDotType)
|| willImplicitBeUpcasted(beforeDotType, incomingSymbol)
|| matchAliasThis(beforeDotType, incomingSymbol, recursionDepth);
} }
return false; return false;
} }