You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We will introduce some new concepts in call resolving
CastResult and Language.tryCast
CastResult will be the result of the function Language.tryCast and describes whether a cast of one type into another is successful according to the logic of the Language. A default implementation is provided. It also has a property that describes the "depth" of the cast needed, which is the distance in the ancestry between base and derived class.
It is a sealed class that has the following sub-classes/objects:
CastNotPossible, which says that the two types are incompatible and cannot be cast into each other. It has a depth of -1.
DirectMatchNoCastNeeded, which says that the types directly match with a depth of 0. This is mostly for languages that have no implicit casts and directly match types to interfaces (such as Go). Also for types that are basically the same or just an alias of each other.
ImplicitCast (as a companion object) with a depth of 1 specifies that one (implicit) cast is needed to convert between the types. This is used in most languages to cast between numeric types.
ImplicitCast (as a class) with a configurable depth means that an (implicit) cast is needed between object types and depth specifies the distance between the base and derived type. We probably should rename this to something else.
SignatureResult and FunctionDeclaration.matchesSignature
SignatureResult will be the result of the function FunctionDeclaration.matchesSignature which calculates whether the provided CallExpression will match the signature of the current FunctionDeclaration. It can be configured to take into account variadic and default parameters (depending on the Language).
It is a sealed class that has the following sub-classes/objects:
IncompatibleSignature which specifies that the signatures do not match even after implicit casts
SignatureMatches specifies that the signature matches, although implicit casts might be necessary, it also has a casts parameter which contains a list of CastResult, one for each parameter. This can then later be used to compare different signature match results in order to decide which function is suitable best.
CallResolutionResult and ScopeManager.resolveCall
CallResolutionResult is the result of ScopeManager.resolveCall. It holds all necessary intermediate results as well as the final result of the call resolution. Among the results we want to store:
a reference to the CallExpression we are resolving
a list of candidateFunctions, which are the starting point of the resolution and contain all symbols with the desired name of the call in scope
a set of viableFunctions that restrict the candidate functions to functions whose signature match
the signatureResults, which is a map of function declarations and their SignatureResult
bestViable which contains the best viable function(s) of the viable functions. Ideally this is only one, but because of ambiguities or other factors, this can contain multiple functions.
Language.bestViableResolution
This implementation of ScopeManager.resolveCall follows a very simple version of the C++ function call resolving algorithm. It can be fine-tuned by a Language by implementing the function Language.bestViableResolution. A default implementation is provided that does the following steps:
If the list of viableFunctions is empty, we can directly return
If we have only one item in viableFunctions, we can take it
Next, we can check for direct matches, meaning that they have a SignatureResult that only has DirectMatchNoCastNeeded casts
Lastly, if we have not direct matches, we need to sort the viable functions using a simple ranking. The function(s) will the best (lowest) ranking will be chosen as the best. The ranking is determined by the "depth" of all cast results in the signature results
The text was updated successfully, but these errors were encountered:
Concepts
We will introduce some new concepts in call resolving
CastResult
andLanguage.tryCast
CastResult
will be the result of the functionLanguage.tryCast
and describes whether a cast of one type into another is successful according to the logic of theLanguage
. A default implementation is provided. It also has a property that describes the "depth" of the cast needed, which is the distance in the ancestry between base and derived class.It is a sealed class that has the following sub-classes/objects:
CastNotPossible
, which says that the two types are incompatible and cannot be cast into each other. It has a depth of -1.DirectMatchNoCastNeeded
, which says that the types directly match with a depth of 0. This is mostly for languages that have no implicit casts and directly match types to interfaces (such as Go). Also for types that are basically the same or just an alias of each other.ImplicitCast
(as a companion object) with a depth of 1 specifies that one (implicit) cast is needed to convert between the types. This is used in most languages to cast between numeric types.ImplicitCast
(as a class) with a configurable depth means that an (implicit) cast is needed between object types and depth specifies the distance between the base and derived type. We probably should rename this to something else.SignatureResult
andFunctionDeclaration.matchesSignature
SignatureResult
will be the result of the functionFunctionDeclaration.matchesSignature
which calculates whether the providedCallExpression
will match the signature of the currentFunctionDeclaration
. It can be configured to take into account variadic and default parameters (depending on theLanguage
).It is a sealed class that has the following sub-classes/objects:
IncompatibleSignature
which specifies that the signatures do not match even after implicit castsSignatureMatches
specifies that the signature matches, although implicit casts might be necessary, it also has acasts
parameter which contains a list ofCastResult
, one for each parameter. This can then later be used to compare different signature match results in order to decide which function is suitable best.CallResolutionResult
andScopeManager.resolveCall
CallResolutionResult
is the result ofScopeManager.resolveCall
. It holds all necessary intermediate results as well as the final result of the call resolution. Among the results we want to store:CallExpression
we are resolvingcandidateFunctions
, which are the starting point of the resolution and contain all symbols with the desired name of the call in scopeviableFunctions
that restrict the candidate functions to functions whose signature matchsignatureResults
, which is a map of function declarations and theirSignatureResult
bestViable
which contains the best viable function(s) of the viable functions. Ideally this is only one, but because of ambiguities or other factors, this can contain multiple functions.Language.bestViableResolution
This implementation of
ScopeManager.resolveCall
follows a very simple version of the C++ function call resolving algorithm. It can be fine-tuned by aLanguage
by implementing the functionLanguage.bestViableResolution
. A default implementation is provided that does the following steps:viableFunctions
is empty, we can directly returnviableFunctions
, we can take itSignatureResult
that only hasDirectMatchNoCastNeeded
castsThe text was updated successfully, but these errors were encountered: