1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #ifndef CMAJOR_BINDER_OVERLOAD_RESOLUTION_INCLUDED
  7 #define CMAJOR_BINDER_OVERLOAD_RESOLUTION_INCLUDED
  8 #include <cmajor/binder/BoundExpression.hpp>
  9 #include <cmajor/symbols/Scope.hpp>
 10 #include <cmajor/symbols/Exception.hpp>
 11 #include <cmajor/symbols/FunctionSymbol.hpp>
 12 
 13 namespace cmajor { namespace binder {
 14 
 15 class BoundExpression;
 16 class BoundFunctionCall;
 17 class BoundCompileUnit;
 18 class BoundFunction;
 19 class BoundConstraint;
 20 
 21 using namespace cmajor::symbols;
 22 
 23 enum class OverloadResolutionFlags : uint8_t 
 24 {
 25     none=  0
 26     dontThrow=  1 << 0
 27     dontInstantiate=  1 << 1
 28     noTemplates=  1 << 2
 29     noRvalueRef=  1 << 3
 30     includeSystemDefaultFunctions=  1 << 4
 31 };
 32 
 33 inline OverloadResolutionFlags operator&(OverloadResolutionFlags leftOverloadResolutionFlags right)
 34 {
 35     return OverloadResolutionFlags(uint8_t(left) & uint8_t(right));
 36 }
 37 
 38 inline OverloadResolutionFlags operator|(OverloadResolutionFlags leftOverloadResolutionFlags right)
 39 {
 40     return OverloadResolutionFlags(uint8_t(left) | uint8_t(right));
 41 }
 42 
 43 struct FunctionScopeLookup 
 44 {
 45     FunctionScopeLookup(ScopeLookup scopeLookup_) : scopeLookup(scopeLookup_)scope(nullptr) {}
 46     FunctionScopeLookup(ScopeLookup scopeLookup_ContainerScope* scope_) : scopeLookup(scopeLookup_)scope(scope_) {}
 47     ScopeLookup scopeLookup;
 48     ContainerScope* scope;
 49 };
 50 
 51 struct ArgumentMatch 
 52 {
 53     ArgumentMatch() : preReferenceConversionFlags(OperationFlags::none)conversionFun(nullptr)postReferenceConversionFlags(OperationFlags::none)conversionDistance(0) {}
 54     ArgumentMatch(OperationFlags preReferenceConversionFlags_FunctionSymbol* conversionFun_OperationFlags postReferenceConversionFlags_int conversionDistance_) :
 55         preReferenceConversionFlags(preReferenceConversionFlags_)conversionFun(conversionFun_)postReferenceConversionFlags(postReferenceConversionFlags_)conversionDistance(conversionDistance_) {}
 56     OperationFlags preReferenceConversionFlags;
 57     FunctionSymbol* conversionFun;
 58     OperationFlags postReferenceConversionFlags;
 59     int conversionDistance;
 60 };
 61 
 62 inline bool BetterArgumentMatch(const ArgumentMatch& leftconst ArgumentMatch& right)
 63 {
 64     if (left.preReferenceConversionFlags == OperationFlags::none && right.preReferenceConversionFlags != OperationFlags::none) return true;
 65     if (left.preReferenceConversionFlags != OperationFlags::none && right.preReferenceConversionFlags == OperationFlags::none) return false;
 66     if (left.conversionFun == nullptr && right.conversionFun != nullptr) return true;
 67     if (right.conversionFun == nullptr && left.conversionFun != nullptr) return false;
 68     if (left.postReferenceConversionFlags == OperationFlags::none && right.postReferenceConversionFlags != OperationFlags::none) return true;
 69     if (left.postReferenceConversionFlags != OperationFlags::none && right.postReferenceConversionFlags == OperationFlags::none) return false;
 70     if (left.conversionDistance < right.conversionDistance) return true;
 71     if (left.conversionDistance > right.conversionDistance) return false;
 72     return false;
 73 }
 74 
 75 struct FunctionMatch 
 76 {
 77     FunctionMatch(FunctionSymbol* fun_) :
 78         fun(fun_)numConversions(0)numQualifyingConversions(0)referenceMustBeInitialized(false)castRequired(false)cannotBindConstArgToNonConstParam(false)cannotAssignToConstObject(false)
 79         sourceType(nullptr)targetType(nullptr)conceptCheckException(nullptr)boundConstraint(nullptr) {}
 80     FunctionSymbol* fun;
 81     std::vector<ArgumentMatch> argumentMatches;
 82     int numConversions;
 83     int numQualifyingConversions;
 84     bool referenceMustBeInitialized;
 85     bool castRequired;
 86     bool cannotBindConstArgToNonConstParam;
 87     bool cannotAssignToConstObject;
 88     TypeSymbol* sourceType;
 89     TypeSymbol* targetType;
 90     std::unordered_map<TemplateParameterSymbol*TypeSymbol*> templateParameterMap;
 91     Exception* conceptCheckException;
 92     BoundConstraint* boundConstraint;
 93 };
 94 
 95 struct BetterFunctionMatch 
 96 {
 97     bool operator()(const FunctionMatch& leftconst FunctionMatch& right) const;
 98 };
 99 
100 bool FindConversions(BoundCompileUnit& boundCompileUnitFunctionSymbol* functionstd::std::vector<std::std::unique_ptr<BoundExpression>>&argumentsFunctionMatch&functionMatch
101     ConversionType conversionTypeContainerScope* containerScopeBoundFunction* currentFunctionconst Span& spanconst boost::uuids::uuid& moduleId);
102 
103 std::unique_ptr<BoundFunctionCall> ResolveOverload(const std::u32string& groupNameContainerScope* containerScopeconst std::std::vector<FunctionScopeLookup>&functionScopeLookups
104     std::std::vector<std::std::unique_ptr<BoundExpression>>&argumentsBoundCompileUnit&boundCompileUnitBoundFunction*currentFunctionconstSpan&spanconstboost::uuids::uuid&moduleId);
105 
106 std::unique_ptr<BoundFunctionCall> ResolveOverload(const std::u32string& groupNameContainerScope* containerScopeconst std::std::vector<FunctionScopeLookup>&functionScopeLookups
107     std::std::vector<std::std::unique_ptr<BoundExpression>>&argumentsBoundCompileUnit&boundCompileUnitBoundFunction*currentFunctionconstSpan&spanconstboost::uuids::uuid&moduleId
108     OverloadResolutionFlags flagsstd::std::vector<TypeSymbol*>&templateArgumentTypesstd::std::unique_ptr<Exception>&exception);
109 
110 } } // namespace cmajor::binder
111 
112 #endif // CMAJOR_BINDER_OVERLOAD_RESOLUTION_INCLUDED