Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2025 ChilliBits. All rights reserved. | ||
2 | |||
3 | #include "FunctionManager.h" | ||
4 | #include "TypeChecker.h" | ||
5 | |||
6 | #include <ast/ASTNodes.h> | ||
7 | #include <exception/SemanticError.h> | ||
8 | #include <model/GenericType.h> | ||
9 | #include <symboltablebuilder/Scope.h> | ||
10 | #include <symboltablebuilder/SymbolTableBuilder.h> | ||
11 | #include <typechecker/TypeMatcher.h> | ||
12 | #include <util/CodeLoc.h> | ||
13 | #include <util/CustomHashFunctions.h> | ||
14 | |||
15 | namespace spice::compiler { | ||
16 | |||
17 | // Static member initialization | ||
18 | std::unordered_map<uint64_t, Function *> FunctionManager::lookupCache = {}; | ||
19 | |||
20 | 10260 | Function *FunctionManager::insert(Scope *insertScope, const Function &baseFunction, std::vector<Function *> *nodeFunctionList) { | |
21 | // Open a new manifestation list for the function definition | ||
22 |
3/6✓ Branch 0 (2→3) taken 10260 times.
✗ Branch 1 (2→43) not taken.
✓ Branch 2 (3→4) taken 10260 times.
✗ Branch 3 (3→40) not taken.
✓ Branch 4 (4→5) taken 10260 times.
✗ Branch 5 (4→38) not taken.
|
10260 | const std::string fctId = baseFunction.name + ":" + baseFunction.declNode->codeLoc.toPrettyLineAndColumn(); |
23 |
2/4✓ Branch 0 (8→9) taken 10260 times.
✗ Branch 1 (8→46) not taken.
✓ Branch 2 (9→10) taken 10260 times.
✗ Branch 3 (9→44) not taken.
|
10260 | insertScope->functions.insert({fctId, FunctionManifestationList()}); |
24 | |||
25 | // Collect substantiations | ||
26 | 10260 | std::vector<Function> manifestations; | |
27 |
1/2✓ Branch 0 (12→13) taken 10260 times.
✗ Branch 1 (12→51) not taken.
|
10260 | substantiateOptionalParams(baseFunction, manifestations); |
28 |
1/2✗ Branch 0 (14→15) not taken.
✓ Branch 1 (14→16) taken 10260 times.
|
10260 | assert(!manifestations.empty()); |
29 | |||
30 | // Save substantiations in declaration node | ||
31 | 10260 | Function *manifestationPtr = nullptr; | |
32 |
2/2✓ Branch 0 (26→18) taken 11002 times.
✓ Branch 1 (26→27) taken 10258 times.
|
21260 | for (const Function &manifestation : manifestations) { |
33 |
2/2✓ Branch 0 (19→20) taken 11000 times.
✓ Branch 1 (19→50) taken 2 times.
|
11002 | manifestationPtr = insertSubstantiation(insertScope, manifestation, baseFunction.declNode); |
34 |
1/2✗ Branch 0 (20→21) not taken.
✓ Branch 1 (20→22) taken 11000 times.
|
11000 | assert(manifestationPtr != nullptr); |
35 |
1/2✓ Branch 0 (22→23) taken 11000 times.
✗ Branch 1 (22→24) not taken.
|
11000 | if (nodeFunctionList) |
36 |
1/2✓ Branch 0 (23→24) taken 11000 times.
✗ Branch 1 (23→50) not taken.
|
11000 | nodeFunctionList->push_back(manifestationPtr); |
37 | } | ||
38 | |||
39 |
1/2✗ Branch 0 (27→28) not taken.
✓ Branch 1 (27→29) taken 10258 times.
|
10258 | if (!nodeFunctionList) |
40 | ✗ | return manifestationPtr; | |
41 | |||
42 |
1/2✗ Branch 0 (30→31) not taken.
✓ Branch 1 (30→32) taken 10258 times.
|
10258 | assert(!nodeFunctionList->empty()); |
43 | 10258 | return nodeFunctionList->front(); | |
44 | 10262 | } | |
45 | |||
46 | /** | ||
47 | * Create definite functions from ambiguous ones, in regard to optional arguments. | ||
48 | * | ||
49 | * Example: | ||
50 | * int testFunc(string, int?, double?) | ||
51 | * gets | ||
52 | * int testFunc(string) | ||
53 | * int testFunc(string, int) | ||
54 | * int testFunc(string, int, double) | ||
55 | * | ||
56 | * This method also accepts functions, that are already definite, but does nothing to them. | ||
57 | * | ||
58 | * @param baseFunction Ambiguous base function | ||
59 | * @param manifestations Vector to store the definite manifestations | ||
60 | * @return True, if there were optional arguments found | ||
61 | */ | ||
62 | 10260 | void FunctionManager::substantiateOptionalParams(const Function &baseFunction, std::vector<Function> &manifestations) { | |
63 | // Handle the case of no parameters -> simply return the base function | ||
64 |
2/2✓ Branch 0 (3→4) taken 2610 times.
✓ Branch 1 (3→6) taken 7650 times.
|
10260 | if (baseFunction.paramList.empty()) { |
65 |
1/2✓ Branch 0 (4→5) taken 2610 times.
✗ Branch 1 (4→39) not taken.
|
2610 | manifestations.push_back(baseFunction); |
66 | 2610 | return; | |
67 | } | ||
68 | |||
69 | 7650 | ParamList currentFunctionParamTypes; | |
70 |
1/2✓ Branch 0 (7→8) taken 7650 times.
✗ Branch 1 (7→37) not taken.
|
7650 | currentFunctionParamTypes.reserve(baseFunction.paramList.size()); |
71 | 7650 | bool metFirstOptionalParam = false; | |
72 |
1/2✓ Branch 0 (8→9) taken 7650 times.
✗ Branch 1 (8→37) not taken.
|
7650 | Function manifestation = baseFunction; |
73 | |||
74 | // Loop over all parameters | ||
75 |
2/2✓ Branch 0 (24→11) taken 12133 times.
✓ Branch 1 (24→25) taken 7650 times.
|
19783 | for (const auto &[qualType, isOptional] : baseFunction.paramList) { |
76 | // Check if we have a mandatory parameter | ||
77 |
2/2✓ Branch 0 (12→13) taken 11391 times.
✓ Branch 1 (12→15) taken 742 times.
|
12133 | if (!isOptional) { |
78 |
1/2✓ Branch 0 (13→14) taken 11391 times.
✗ Branch 1 (13→32) not taken.
|
11391 | currentFunctionParamTypes.push_back({qualType, /*optional=*/false}); |
79 | 11391 | continue; | |
80 | } | ||
81 | |||
82 | // Add substantiation without the optional parameter | ||
83 |
2/2✓ Branch 0 (15→16) taken 736 times.
✓ Branch 1 (15→19) taken 6 times.
|
742 | if (!metFirstOptionalParam) { |
84 |
1/2✓ Branch 0 (16→17) taken 736 times.
✗ Branch 1 (16→34) not taken.
|
736 | manifestation.paramList = currentFunctionParamTypes; |
85 |
1/2✓ Branch 0 (17→18) taken 736 times.
✗ Branch 1 (17→34) not taken.
|
736 | manifestations.push_back(manifestation); |
86 | // Now we cannot accept mandatory parameters anymore | ||
87 | 736 | metFirstOptionalParam = true; | |
88 | } | ||
89 | |||
90 | // Add substantiation with the optional parameter | ||
91 |
1/2✓ Branch 0 (19→20) taken 742 times.
✗ Branch 1 (19→33) not taken.
|
742 | currentFunctionParamTypes.push_back({qualType, /*optional=*/false}); |
92 |
1/2✓ Branch 0 (20→21) taken 742 times.
✗ Branch 1 (20→34) not taken.
|
742 | manifestation.paramList = currentFunctionParamTypes; |
93 |
1/2✓ Branch 0 (21→22) taken 742 times.
✗ Branch 1 (21→34) not taken.
|
742 | manifestations.push_back(manifestation); |
94 | } | ||
95 | |||
96 | // Ensure at least once manifestation | ||
97 |
2/2✓ Branch 0 (26→27) taken 6914 times.
✓ Branch 1 (26→28) taken 736 times.
|
7650 | if (manifestations.empty()) |
98 |
1/2✓ Branch 0 (27→28) taken 6914 times.
✗ Branch 1 (27→35) not taken.
|
6914 | manifestations.push_back(baseFunction); |
99 | 7650 | } | |
100 | |||
101 | 2 | Function FunctionManager::createMainFunction(SymbolTableEntry *entry, const QualTypeList ¶mTypes, ASTNode *declNode) { | |
102 | 2 | ParamList paramList; | |
103 |
2/2✓ Branch 0 (8→4) taken 2 times.
✓ Branch 1 (8→9) taken 2 times.
|
4 | for (const QualType ¶mType : paramTypes) |
104 |
1/2✓ Branch 0 (5→6) taken 2 times.
✗ Branch 1 (5→24) not taken.
|
2 | paramList.push_back({paramType, false}); |
105 |
4/8✓ Branch 0 (11→12) taken 2 times.
✗ Branch 1 (11→31) not taken.
✓ Branch 2 (12→13) taken 2 times.
✗ Branch 3 (12→28) not taken.
✓ Branch 4 (13→14) taken 2 times.
✗ Branch 5 (13→27) not taken.
✓ Branch 6 (14→15) taken 2 times.
✗ Branch 7 (14→26) not taken.
|
4 | return {MAIN_FUNCTION_NAME, entry, QualType(TY_DYN), QualType(TY_INT), paramList, {}, declNode}; |
106 | 2 | } | |
107 | |||
108 | 12712 | Function *FunctionManager::insertSubstantiation(Scope *insertScope, const Function &newManifestation, const ASTNode *declNode) { | |
109 |
2/4✓ Branch 0 (2→3) taken 12712 times.
✗ Branch 1 (2→79) not taken.
✗ Branch 2 (3→4) not taken.
✓ Branch 3 (3→5) taken 12712 times.
|
12712 | assert(newManifestation.hasSubstantiatedParams()); |
110 | |||
111 |
1/2✓ Branch 0 (5→6) taken 12712 times.
✗ Branch 1 (5→79) not taken.
|
12712 | const std::string signature = newManifestation.getSignature(); |
112 | |||
113 | // Check if the function exists already | ||
114 |
5/8✓ Branch 0 (6→7) taken 12712 times.
✗ Branch 1 (6→68) not taken.
✓ Branch 2 (7→8) taken 12712 times.
✗ Branch 3 (7→68) not taken.
✓ Branch 4 (8→9) taken 12712 times.
✗ Branch 5 (8→68) not taken.
✓ Branch 6 (33→10) taken 154692 times.
✓ Branch 7 (33→34) taken 12710 times.
|
167402 | for (const auto &manifestations : insertScope->functions | std::views::values) { |
115 |
3/4✓ Branch 0 (11→12) taken 154692 times.
✗ Branch 1 (11→68) not taken.
✓ Branch 2 (12→13) taken 2 times.
✓ Branch 3 (12→31) taken 154690 times.
|
154692 | if (manifestations.contains(signature)) { |
116 |
2/2✓ Branch 0 (16→17) taken 1 times.
✓ Branch 1 (16→24) taken 1 times.
|
2 | if (newManifestation.isFunction()) |
117 |
3/6✓ Branch 0 (18→19) taken 1 times.
✗ Branch 1 (18→55) not taken.
✓ Branch 2 (19→20) taken 1 times.
✗ Branch 3 (19→53) not taken.
✓ Branch 4 (20→21) taken 1 times.
✗ Branch 5 (20→50) not taken.
|
1 | throw SemanticError(declNode, FUNCTION_DECLARED_TWICE, "'" + signature + "' is declared twice"); |
118 | else | ||
119 |
3/6✓ Branch 0 (25→26) taken 1 times.
✗ Branch 1 (25→64) not taken.
✓ Branch 2 (26→27) taken 1 times.
✗ Branch 3 (26→62) not taken.
✓ Branch 4 (27→28) taken 1 times.
✗ Branch 5 (27→59) not taken.
|
1 | throw SemanticError(declNode, PROCEDURE_DECLARED_TWICE, "'" + signature + "' is declared twice"); |
120 | } | ||
121 | } | ||
122 | |||
123 | // Retrieve the matching manifestation list of the scope | ||
124 |
3/6✓ Branch 0 (34→35) taken 12710 times.
✗ Branch 1 (34→74) not taken.
✓ Branch 2 (35→36) taken 12710 times.
✗ Branch 3 (35→71) not taken.
✓ Branch 4 (36→37) taken 12710 times.
✗ Branch 5 (36→69) not taken.
|
12710 | const std::string fctId = newManifestation.name + ":" + declNode->codeLoc.toPrettyLineAndColumn(); |
125 |
2/4✓ Branch 0 (39→40) taken 12710 times.
✗ Branch 1 (39→75) not taken.
✗ Branch 2 (40→41) not taken.
✓ Branch 3 (40→42) taken 12710 times.
|
12710 | assert(insertScope->functions.contains(fctId)); |
126 |
1/2✓ Branch 0 (42→43) taken 12710 times.
✗ Branch 1 (42→75) not taken.
|
12710 | FunctionManifestationList &manifestationList = insertScope->functions.at(fctId); |
127 | |||
128 | // Add substantiated function | ||
129 |
1/2✓ Branch 0 (43→44) taken 12710 times.
✗ Branch 1 (43→75) not taken.
|
12710 | manifestationList.emplace(signature, newManifestation); |
130 |
1/2✓ Branch 0 (44→45) taken 12710 times.
✗ Branch 1 (44→75) not taken.
|
25420 | return &manifestationList.at(signature); |
131 | 12712 | } | |
132 | |||
133 | /** | ||
134 | * Checks if a function exists by matching it, but not setting it to used | ||
135 | * | ||
136 | * @param matchScope Scope to match against | ||
137 | * @param reqName Function name requirement | ||
138 | * @param reqThisType This type requirement | ||
139 | * @param reqArgs Argument requirement | ||
140 | * @param strictQualifierMatching Match argument and this type qualifiers strictly | ||
141 | * @return Found function or nullptr | ||
142 | */ | ||
143 | 6719 | const Function *FunctionManager::lookup(Scope *matchScope, const std::string &reqName, const QualType &reqThisType, | |
144 | const ArgList &reqArgs, bool strictQualifierMatching) { | ||
145 |
2/4✓ Branch 0 (2→3) taken 6719 times.
✗ Branch 1 (2→66) not taken.
✗ Branch 2 (3→4) not taken.
✓ Branch 3 (3→5) taken 6719 times.
|
6719 | assert(reqThisType.isOneOf({TY_DYN, TY_STRUCT})); |
146 | |||
147 | // Do cache lookup | ||
148 |
1/2✓ Branch 0 (6→7) taken 6719 times.
✗ Branch 1 (6→67) not taken.
|
6719 | const uint64_t cacheKey = getCacheKey(matchScope, reqName, reqThisType, reqArgs, {}); |
149 |
3/4✓ Branch 0 (8→9) taken 6719 times.
✗ Branch 1 (8→83) not taken.
✓ Branch 2 (9→10) taken 1867 times.
✓ Branch 3 (9→12) taken 4852 times.
|
6719 | if (lookupCache.contains(cacheKey)) |
150 |
1/2✓ Branch 0 (10→11) taken 1867 times.
✗ Branch 1 (10→83) not taken.
|
1867 | return lookupCache.at(cacheKey); |
151 | |||
152 | 2145 | const auto pred = [&](const Arg &arg) { return arg.first.hasAnyGenericParts(); }; | |
153 |
5/8✓ Branch 0 (12→13) taken 4852 times.
✗ Branch 1 (12→83) not taken.
✓ Branch 2 (13→14) taken 4673 times.
✓ Branch 3 (13→17) taken 179 times.
✓ Branch 4 (14→15) taken 4673 times.
✗ Branch 5 (14→83) not taken.
✓ Branch 6 (15→16) taken 4673 times.
✗ Branch 7 (15→17) not taken.
|
4852 | const bool requestedFullySubstantiated = !reqThisType.hasAnyGenericParts() && std::ranges::none_of(reqArgs, pred); |
154 | |||
155 | // Copy the registry to prevent iterating over items, that are created within the loop | ||
156 |
1/2✓ Branch 0 (18→19) taken 4852 times.
✗ Branch 1 (18→83) not taken.
|
4852 | FunctionRegistry functionRegistry = matchScope->functions; |
157 | // Loop over function registry to find functions, that match the requirements of the call | ||
158 | 4852 | std::vector<const Function *> matches; | |
159 |
2/2✓ Branch 0 (55→21) taken 38531 times.
✓ Branch 1 (55→56) taken 4852 times.
|
43383 | for (const auto &[defCodeLocStr, m] : functionRegistry) { |
160 | // Copy the manifestation list to prevent iterating over items, that are created within the loop | ||
161 |
1/2✓ Branch 0 (24→25) taken 38531 times.
✗ Branch 1 (24→77) not taken.
|
38531 | const FunctionManifestationList manifestations = m; |
162 |
2/2✓ Branch 0 (51→27) taken 40995 times.
✓ Branch 1 (51→52) taken 12870 times.
|
53865 | for (const auto &[signature, presetFunction] : manifestations) { |
163 |
2/4✓ Branch 0 (30→31) taken 40995 times.
✗ Branch 1 (30→73) not taken.
✗ Branch 2 (31→32) not taken.
✓ Branch 3 (31→33) taken 40995 times.
|
40995 | assert(presetFunction.hasSubstantiatedParams()); // No optional params are allowed at this point |
164 | |||
165 | // - search for concrete fct: Only match against fully substantiated versions to prevent double matching of a function | ||
166 | // - search for generic fct: Only match against generic preset functions | ||
167 |
3/4✓ Branch 0 (33→34) taken 40995 times.
✗ Branch 1 (33→73) not taken.
✓ Branch 2 (34→35) taken 10102 times.
✓ Branch 3 (34→36) taken 30893 times.
|
40995 | if (presetFunction.isFullySubstantiated() != requestedFullySubstantiated) |
168 | 15334 | continue; | |
169 | |||
170 | // Copy the function to be able to substantiate types | ||
171 |
1/2✓ Branch 0 (36→37) taken 30893 times.
✗ Branch 1 (36→73) not taken.
|
30893 | Function candidate = presetFunction; |
172 | |||
173 | // Create empty type mapping | ||
174 | 30893 | TypeMapping &typeMapping = candidate.typeMapping; | |
175 | |||
176 | 30893 | bool forceSubstantiation = false; | |
177 |
1/2✓ Branch 0 (37→38) taken 30893 times.
✗ Branch 1 (37→71) not taken.
|
30893 | const MatchResult matchResult = matchManifestation(candidate, matchScope, reqName, reqThisType, reqArgs, typeMapping, |
178 | strictQualifierMatching, forceSubstantiation, nullptr); | ||
179 |
2/2✓ Branch 0 (38→39) taken 24773 times.
✓ Branch 1 (38→40) taken 6120 times.
|
30893 | if (matchResult == MatchResult::SKIP_FUNCTION) |
180 | 24773 | break; // Leave the whole function | |
181 |
2/2✓ Branch 0 (40→41) taken 5232 times.
✓ Branch 1 (40→42) taken 888 times.
|
6120 | if (matchResult == MatchResult::SKIP_MANIFESTATION) |
182 | 5232 | continue; // Leave this manifestation and try the next one | |
183 | |||
184 | // Add to matches | ||
185 |
3/6✓ Branch 0 (42→43) taken 888 times.
✗ Branch 1 (42→70) not taken.
✓ Branch 2 (43→44) taken 888 times.
✗ Branch 3 (43→70) not taken.
✓ Branch 4 (44→45) taken 888 times.
✗ Branch 5 (44→70) not taken.
|
888 | matches.push_back(&matchScope->functions.at(defCodeLocStr).at(signature)); |
186 | |||
187 | 888 | break; // Leave the whole manifestation list to not double-match the manifestation | |
188 |
2/2✓ Branch 0 (47→48) taken 5232 times.
✓ Branch 1 (47→49) taken 25661 times.
|
30893 | } |
189 | 38531 | } | |
190 | |||
191 | // Return the very match or a nullptr | ||
192 |
2/2✓ Branch 0 (57→58) taken 888 times.
✓ Branch 1 (57→60) taken 3964 times.
|
4852 | return !matches.empty() ? matches.front() : nullptr; |
193 | 4852 | } | |
194 | |||
195 | /** | ||
196 | * Check if there is a function in the scope, fulfilling all given requirements and if found, return it. | ||
197 | * If more than one function matches the requirement, an error gets thrown. | ||
198 | * | ||
199 | * @param typeChecker Type Checker | ||
200 | * @param matchScope Scope to match against | ||
201 | * @param reqName Function name requirement | ||
202 | * @param reqThisType This type requirement | ||
203 | * @param reqArgs Argument requirement | ||
204 | * @param templateTypeHints Template type requirement | ||
205 | * @param strictQualifierMatching Match argument and this type qualifiers strictly | ||
206 | * @param callNode Call AST node for printing error messages | ||
207 | * @return Matched function or nullptr | ||
208 | */ | ||
209 | 61196 | Function *FunctionManager::match(TypeChecker *typeChecker, Scope *matchScope, const std::string &reqName, | |
210 | const QualType &reqThisType, const ArgList &reqArgs, const QualTypeList &templateTypeHints, | ||
211 | bool strictQualifierMatching, const ASTNode *callNode) { | ||
212 |
2/4✓ Branch 0 (2→3) taken 61196 times.
✗ Branch 1 (2→174) not taken.
✗ Branch 2 (3→4) not taken.
✓ Branch 3 (3→5) taken 61196 times.
|
61196 | assert(reqThisType.isOneOf({TY_DYN, TY_STRUCT, TY_INTERFACE})); |
213 |
1/2✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 61196 times.
|
61196 | assert(typeChecker != nullptr && "The match() function must be called from the TypeChecker"); |
214 | |||
215 | // Do cache lookup | ||
216 |
1/2✓ Branch 0 (7→8) taken 61196 times.
✗ Branch 1 (7→222) not taken.
|
61196 | const uint64_t cacheKey = getCacheKey(matchScope, reqName, reqThisType, reqArgs, templateTypeHints); |
217 |
3/4✓ Branch 0 (8→9) taken 61196 times.
✗ Branch 1 (8→222) not taken.
✓ Branch 2 (9→10) taken 10132 times.
✓ Branch 3 (9→12) taken 51064 times.
|
61196 | if (lookupCache.contains(cacheKey)) |
218 |
1/2✓ Branch 0 (10→11) taken 10132 times.
✗ Branch 1 (10→222) not taken.
|
10132 | return lookupCache.at(cacheKey); |
219 | |||
220 | // Copy the registry to prevent iterating over items, that are created within the loop | ||
221 |
1/2✓ Branch 0 (12→13) taken 51064 times.
✗ Branch 1 (12→222) not taken.
|
51064 | FunctionRegistry functionRegistry = matchScope->functions; |
222 | // Loop over function registry to find functions, that match the requirements of the call | ||
223 | 51064 | std::vector<Function *> matches; | |
224 |
2/2✓ Branch 0 (139→15) taken 514089 times.
✓ Branch 1 (139→140) taken 51063 times.
|
565152 | for (const auto &[fctId, m] : functionRegistry) { |
225 | // Copy the manifestation list to prevent iterating over items, that are created within the loop | ||
226 |
1/2✓ Branch 0 (18→19) taken 514089 times.
✗ Branch 1 (18→203) not taken.
|
514089 | const FunctionManifestationList manifestations = m; |
227 |
2/2✓ Branch 0 (135→21) taken 544765 times.
✓ Branch 1 (135→136) taken 38955 times.
|
583720 | for (const auto &[signature, presetFunction] : manifestations) { |
228 |
2/4✓ Branch 0 (24→25) taken 544765 times.
✗ Branch 1 (24→199) not taken.
✗ Branch 2 (25→26) not taken.
✓ Branch 3 (25→27) taken 544765 times.
|
544765 | assert(presetFunction.hasSubstantiatedParams()); // No optional params are allowed at this point |
229 | |||
230 | // Skip generic substantiations to prevent double matching of a function | ||
231 |
3/4✓ Branch 0 (27→28) taken 544765 times.
✗ Branch 1 (27→199) not taken.
✓ Branch 2 (28→29) taken 28938 times.
✓ Branch 3 (28→30) taken 515827 times.
|
544765 | if (presetFunction.isGenericSubstantiation()) |
232 | 69631 | continue; | |
233 | |||
234 | // Copy the function to be able to substantiate types | ||
235 |
1/2✓ Branch 0 (30→31) taken 515827 times.
✗ Branch 1 (30→199) not taken.
|
515827 | Function candidate = presetFunction; |
236 | |||
237 | // Prepare type mapping, based on the given initial type mapping | ||
238 | 515827 | TypeMapping &typeMapping = candidate.typeMapping; | |
239 | 515827 | typeMapping.clear(); | |
240 |
2/2✓ Branch 0 (43→33) taken 3046 times.
✓ Branch 1 (43→44) taken 515827 times.
|
518873 | for (size_t i = 0; i < std::min(templateTypeHints.size(), candidate.templateTypes.size()); i++) { |
241 |
2/4✓ Branch 0 (33→34) taken 3046 times.
✗ Branch 1 (33→197) not taken.
✓ Branch 2 (34→35) taken 3046 times.
✗ Branch 3 (34→197) not taken.
|
3046 | const std::string &typeName = candidate.templateTypes.at(i).getSubType(); |
242 |
1/2✓ Branch 0 (35→36) taken 3046 times.
✗ Branch 1 (35→197) not taken.
|
3046 | const QualType &templateType = templateTypeHints.at(i); |
243 |
2/4✓ Branch 0 (36→37) taken 3046 times.
✗ Branch 1 (36→177) not taken.
✓ Branch 2 (37→38) taken 3046 times.
✗ Branch 3 (37→175) not taken.
|
3046 | typeMapping.insert({typeName, templateType}); |
244 | } | ||
245 | |||
246 | 515827 | bool forceSubstantiation = false; | |
247 |
2/2✓ Branch 0 (44→45) taken 515826 times.
✓ Branch 1 (44→197) taken 1 times.
|
515827 | MatchResult matchResult = matchManifestation(candidate, matchScope, reqName, reqThisType, reqArgs, typeMapping, |
248 | strictQualifierMatching, forceSubstantiation, callNode); | ||
249 |
2/2✓ Branch 0 (45→46) taken 473285 times.
✓ Branch 1 (45→47) taken 42541 times.
|
515826 | if (matchResult == MatchResult::SKIP_FUNCTION) |
250 | 473285 | break; // Leave the whole function | |
251 |
2/2✓ Branch 0 (47→48) taken 35801 times.
✓ Branch 1 (47→49) taken 6740 times.
|
42541 | if (matchResult == MatchResult::SKIP_MANIFESTATION) |
252 | 35801 | continue; // Leave this manifestation and try the next one | |
253 | |||
254 | // We found a match! -> Set the actual candidate and its entry to used | ||
255 | 6740 | candidate.used = true; | |
256 | 6740 | candidate.entry->used = true; | |
257 | |||
258 | // Check if the function is generic needs to be substantiated | ||
259 |
6/6✓ Branch 0 (50→51) taken 4895 times.
✓ Branch 1 (50→53) taken 1845 times.
✓ Branch 2 (51→52) taken 4892 times.
✓ Branch 3 (51→53) taken 3 times.
✓ Branch 4 (54→55) taken 4892 times.
✓ Branch 5 (54→67) taken 1848 times.
|
6740 | if (presetFunction.templateTypes.empty() && !forceSubstantiation) { |
260 |
5/10✓ Branch 0 (55→56) taken 4892 times.
✗ Branch 1 (55→197) not taken.
✓ Branch 2 (56→57) taken 4892 times.
✗ Branch 3 (56→61) not taken.
✓ Branch 4 (57→58) taken 4892 times.
✗ Branch 5 (57→197) not taken.
✓ Branch 6 (58→59) taken 4892 times.
✗ Branch 7 (58→197) not taken.
✓ Branch 8 (59→60) taken 4892 times.
✗ Branch 9 (59→61) not taken.
|
4892 | assert(matchScope->functions.contains(fctId) && matchScope->functions.at(fctId).contains(signature)); |
261 |
3/6✓ Branch 0 (62→63) taken 4892 times.
✗ Branch 1 (62→178) not taken.
✓ Branch 2 (63→64) taken 4892 times.
✗ Branch 3 (63→178) not taken.
✓ Branch 4 (64→65) taken 4892 times.
✗ Branch 5 (64→178) not taken.
|
4892 | matches.push_back(&matchScope->functions.at(fctId).at(signature)); |
262 | 4892 | matches.back()->used = true; | |
263 | 4892 | continue; // Match was successful -> match the next function | |
264 | } | ||
265 | |||
266 | // Check if we already have this manifestation and can simply re-use it | ||
267 |
1/2✓ Branch 0 (67→68) taken 1848 times.
✗ Branch 1 (67→197) not taken.
|
1848 | const std::string nonGenericSignature = candidate.getSignature(); |
268 |
4/6✓ Branch 0 (68→69) taken 1848 times.
✗ Branch 1 (68→195) not taken.
✓ Branch 2 (69→70) taken 1848 times.
✗ Branch 3 (69→195) not taken.
✓ Branch 4 (70→71) taken 138 times.
✓ Branch 5 (70→75) taken 1710 times.
|
1848 | if (matchScope->functions.at(fctId).contains(nonGenericSignature)) { |
269 |
3/6✓ Branch 0 (71→72) taken 138 times.
✗ Branch 1 (71→179) not taken.
✓ Branch 2 (72→73) taken 138 times.
✗ Branch 3 (72→179) not taken.
✓ Branch 4 (73→74) taken 138 times.
✗ Branch 5 (73→179) not taken.
|
138 | matches.push_back(&matchScope->functions.at(fctId).at(nonGenericSignature)); |
270 | 138 | break; // Leave the whole manifestation list to not double-match the manifestation | |
271 | } | ||
272 | |||
273 | // Insert the substantiated version if required | ||
274 |
1/2✓ Branch 0 (75→76) taken 1710 times.
✗ Branch 1 (75→195) not taken.
|
1710 | Function *substantiatedFunction = insertSubstantiation(matchScope, candidate, presetFunction.declNode); |
275 |
2/4✓ Branch 0 (76→77) taken 1710 times.
✗ Branch 1 (76→195) not taken.
✓ Branch 2 (77→78) taken 1710 times.
✗ Branch 3 (77→195) not taken.
|
1710 | substantiatedFunction->genericPreset = &matchScope->functions.at(fctId).at(signature); |
276 | 1710 | substantiatedFunction->alreadyTypeChecked = false; | |
277 |
2/4✓ Branch 0 (78→79) taken 1710 times.
✗ Branch 1 (78→195) not taken.
✓ Branch 2 (79→80) taken 1710 times.
✗ Branch 3 (79→195) not taken.
|
1710 | substantiatedFunction->declNode->getFctManifestations(reqName)->push_back(substantiatedFunction); |
278 | |||
279 | // Copy function entry | ||
280 |
1/2✓ Branch 0 (80→81) taken 1710 times.
✗ Branch 1 (80→195) not taken.
|
1710 | const std::string newSignature = substantiatedFunction->getSignature(false); |
281 |
1/2✓ Branch 0 (81→82) taken 1710 times.
✗ Branch 1 (81→193) not taken.
|
1710 | matchScope->lookupStrict(presetFunction.entry->name)->used = true; |
282 |
1/2✓ Branch 0 (84→85) taken 1710 times.
✗ Branch 1 (84→193) not taken.
|
1710 | substantiatedFunction->entry = matchScope->symbolTable.copySymbol(presetFunction.entry->name, newSignature); |
283 |
1/2✗ Branch 0 (85→86) not taken.
✓ Branch 1 (85→87) taken 1710 times.
|
1710 | assert(substantiatedFunction->entry != nullptr); |
284 | |||
285 | // Copy function scope | ||
286 |
1/2✓ Branch 0 (87→88) taken 1710 times.
✗ Branch 1 (87→193) not taken.
|
1710 | const std::string oldSignature = presetFunction.getSignature(false); |
287 |
1/2✓ Branch 0 (88→89) taken 1710 times.
✗ Branch 1 (88→191) not taken.
|
1710 | Scope *childScope = matchScope->copyChildScope(oldSignature, newSignature); |
288 |
1/2✗ Branch 0 (89→90) not taken.
✓ Branch 1 (89→91) taken 1710 times.
|
1710 | assert(childScope != nullptr); |
289 | 1710 | childScope->isGenericScope = false; | |
290 | 1710 | substantiatedFunction->bodyScope = childScope; | |
291 | |||
292 | // Insert symbols for generic type names with concrete types into the child block | ||
293 |
2/2✓ Branch 0 (101→93) taken 2006 times.
✓ Branch 1 (101→102) taken 1710 times.
|
3716 | for (const auto &[typeName, concreteType] : substantiatedFunction->typeMapping) |
294 |
2/4✓ Branch 0 (96→97) taken 2006 times.
✗ Branch 1 (96→182) not taken.
✓ Branch 2 (97→98) taken 2006 times.
✗ Branch 3 (97→180) not taken.
|
2006 | childScope->insertGenericType(typeName, GenericType(concreteType)); |
295 | |||
296 | // Substantiate the 'this' entry in the new function scope | ||
297 |
6/6✓ Branch 0 (105→106) taken 1443 times.
✓ Branch 1 (105→109) taken 267 times.
✓ Branch 2 (107→108) taken 1442 times.
✓ Branch 3 (107→109) taken 1 times.
✓ Branch 4 (110→111) taken 1442 times.
✓ Branch 5 (110→124) taken 268 times.
|
1710 | if (presetFunction.isMethod() && !presetFunction.templateTypes.empty()) { |
298 |
1/2✓ Branch 0 (113→114) taken 1442 times.
✗ Branch 1 (113→186) not taken.
|
4326 | SymbolTableEntry *thisEntry = childScope->lookupStrict(THIS_VARIABLE_NAME); |
299 |
1/2✗ Branch 0 (119→120) not taken.
✓ Branch 1 (119→121) taken 1442 times.
|
1442 | assert(thisEntry != nullptr); |
300 |
2/4✓ Branch 0 (121→122) taken 1442 times.
✗ Branch 1 (121→190) not taken.
✓ Branch 2 (122→123) taken 1442 times.
✗ Branch 3 (122→190) not taken.
|
1442 | thisEntry->updateType(candidate.thisType.toPtr(callNode), /*overwriteExistingType=*/true); |
301 | } | ||
302 | |||
303 | // Add to matched functions | ||
304 |
1/2✓ Branch 0 (124→125) taken 1710 times.
✗ Branch 1 (124→191) not taken.
|
1710 | matches.push_back(substantiatedFunction); |
305 | |||
306 | 1710 | break; // Leave the whole manifestation list to not double-match the manifestation | |
307 |
2/2✓ Branch 0 (131→132) taken 40693 times.
✓ Branch 1 (131→133) taken 475133 times.
|
517675 | } |
308 | 514089 | } | |
309 | |||
310 | // If no matches were found, return a nullptr | ||
311 |
2/2✓ Branch 0 (141→142) taken 44324 times.
✓ Branch 1 (141→143) taken 6739 times.
|
51063 | if (matches.empty()) |
312 | 44324 | return nullptr; | |
313 | |||
314 | // Check if more than one function matches the requirements | ||
315 |
2/2✓ Branch 0 (144→145) taken 1 times.
✓ Branch 1 (144→164) taken 6738 times.
|
6739 | if (matches.size() > 1) { |
316 |
1/2✓ Branch 0 (145→146) taken 1 times.
✗ Branch 1 (145→217) not taken.
|
1 | std::stringstream errorMessage; |
317 |
3/6✓ Branch 0 (146→147) taken 1 times.
✗ Branch 1 (146→215) not taken.
✓ Branch 2 (147→148) taken 1 times.
✗ Branch 3 (147→215) not taken.
✓ Branch 4 (148→149) taken 1 times.
✗ Branch 5 (148→215) not taken.
|
1 | errorMessage << "The function/procedure '" << reqName << "' is ambiguous. All of the following match the requested criteria:"; |
318 |
2/2✓ Branch 0 (158→151) taken 2 times.
✓ Branch 1 (158→159) taken 1 times.
|
3 | for (const Function *match : matches) |
319 |
3/6✓ Branch 0 (152→153) taken 2 times.
✗ Branch 1 (152→208) not taken.
✓ Branch 2 (153→154) taken 2 times.
✗ Branch 3 (153→207) not taken.
✓ Branch 4 (154→155) taken 2 times.
✗ Branch 5 (154→205) not taken.
|
2 | errorMessage << "\n " << match->getSignature(); |
320 |
2/4✓ Branch 0 (160→161) taken 1 times.
✗ Branch 1 (160→212) not taken.
✓ Branch 2 (161→162) taken 1 times.
✗ Branch 3 (161→209) not taken.
|
1 | throw SemanticError(callNode, FUNCTION_AMBIGUITY, errorMessage.str()); |
321 | 1 | } | |
322 | |||
323 | // Insert into cache | ||
324 |
1/2✓ Branch 0 (165→166) taken 6738 times.
✗ Branch 1 (165→218) not taken.
|
6738 | lookupCache[cacheKey] = matches.front(); |
325 | |||
326 | // Trigger revisit in type checker if required | ||
327 |
1/2✓ Branch 0 (167→168) taken 6738 times.
✗ Branch 1 (167→218) not taken.
|
6738 | typeChecker->requestRevisitIfRequired(matches.front()); |
328 | |||
329 | // Return the very match | ||
330 | 6738 | return matches.front(); | |
331 | 51066 | } | |
332 | |||
333 | 546720 | MatchResult FunctionManager::matchManifestation(Function &candidate, Scope *&matchScope, const std::string &reqName, | |
334 | const QualType &reqThisType, const ArgList &reqArgs, TypeMapping &typeMapping, | ||
335 | bool strictQualifierMatching, bool &forceSubstantiation, | ||
336 | const ASTNode *callNode) { | ||
337 | // Check name requirement | ||
338 |
2/2✓ Branch 0 (3→4) taken 498058 times.
✓ Branch 1 (3→5) taken 48662 times.
|
546720 | if (!matchName(candidate, reqName)) |
339 | 498058 | return MatchResult::SKIP_FUNCTION; // Leave the whole manifestation list, because all have the same name | |
340 | |||
341 | // Check 'this' type requirement | ||
342 |
1/2✗ Branch 0 (6→7) not taken.
✓ Branch 1 (6→8) taken 48662 times.
|
48662 | if (!matchThisType(candidate, reqThisType, typeMapping, strictQualifierMatching, callNode)) |
343 | ✗ | return MatchResult::SKIP_MANIFESTATION; // Leave this manifestation and try the next one | |
344 | |||
345 | // Check arg types requirement | ||
346 |
2/2✓ Branch 0 (9→10) taken 41032 times.
✓ Branch 1 (9→11) taken 7629 times.
|
48662 | if (!matchArgTypes(candidate, reqArgs, typeMapping, strictQualifierMatching, forceSubstantiation, callNode)) |
347 | 41032 | return MatchResult::SKIP_MANIFESTATION; // Leave this manifestation and try the next one | |
348 | |||
349 | // Check if there are unresolved generic types | ||
350 |
2/2✓ Branch 0 (13→14) taken 1 times.
✓ Branch 1 (13→15) taken 7628 times.
|
7629 | if (typeMapping.size() < candidate.templateTypes.size()) |
351 | 1 | return MatchResult::SKIP_MANIFESTATION; // Leave this manifestation and try the next one | |
352 | |||
353 | // Substantiate return type | ||
354 | 7628 | substantiateReturnType(candidate, typeMapping, callNode); | |
355 | |||
356 | 7628 | const QualType &thisType = candidate.thisType; | |
357 |
2/2✓ Branch 0 (17→18) taken 4644 times.
✓ Branch 1 (17→28) taken 2984 times.
|
7628 | if (!thisType.is(TY_DYN)) { |
358 | // If we only have the generic struct scope, lookup the concrete manifestation scope | ||
359 |
2/2✓ Branch 0 (18→19) taken 45 times.
✓ Branch 1 (18→26) taken 4599 times.
|
4644 | if (matchScope->isGenericScope) { |
360 | 45 | const std::string &structName = thisType.getSubType(); | |
361 | 45 | Scope *scope = thisType.getBodyScope()->parent; | |
362 | 45 | Struct *spiceStruct = StructManager::match(scope, structName, thisType.getTemplateTypes(), candidate.declNode); | |
363 |
1/2✗ Branch 0 (23→24) not taken.
✓ Branch 1 (23→25) taken 45 times.
|
45 | assert(spiceStruct != nullptr); |
364 | 45 | matchScope = spiceStruct->scope; | |
365 | } | ||
366 |
1/2✓ Branch 0 (26→27) taken 4644 times.
✗ Branch 1 (26→30) not taken.
|
4644 | candidate.thisType = candidate.thisType.getWithBodyScope(matchScope); |
367 | } | ||
368 | |||
369 | 7628 | return MatchResult::MATCHED; | |
370 | } | ||
371 | |||
372 | /** | ||
373 | * Checks if the matching candidate fulfills the name requirement | ||
374 | * | ||
375 | * @param candidate Matching candidate function | ||
376 | * @param reqName Requested function name | ||
377 | * @return Fulfilled or not | ||
378 | */ | ||
379 | 546720 | bool FunctionManager::matchName(const Function &candidate, const std::string &reqName) { return candidate.name == reqName; } | |
380 | |||
381 | /** | ||
382 | * Checks if the matching candidate fulfills the 'this' type requirement | ||
383 | * | ||
384 | * @param candidate Matching candidate function | ||
385 | * @param reqThisType Requested 'this' type | ||
386 | * @param typeMapping Concrete template type mapping | ||
387 | * @param strictQualifierMatching Match qualifiers strictly | ||
388 | * @param callNode Call AST node for printing error messages | ||
389 | * @return Fulfilled or not | ||
390 | */ | ||
391 | 48662 | bool FunctionManager::matchThisType(Function &candidate, const QualType &reqThisType, TypeMapping &typeMapping, | |
392 | bool strictQualifierMatching, const ASTNode *callNode) { | ||
393 | 48662 | QualType &candidateThisType = candidate.thisType; | |
394 | |||
395 | // Shortcut for procedures | ||
396 |
7/10✓ Branch 0 (2→3) taken 48662 times.
✗ Branch 1 (2→23) not taken.
✓ Branch 2 (3→4) taken 33217 times.
✓ Branch 3 (3→7) taken 15445 times.
✓ Branch 4 (4→5) taken 33217 times.
✗ Branch 5 (4→23) not taken.
✓ Branch 6 (5→6) taken 33217 times.
✗ Branch 7 (5→7) not taken.
✓ Branch 8 (8→9) taken 33217 times.
✓ Branch 9 (8→10) taken 15445 times.
|
48662 | if (candidateThisType.is(TY_DYN) && reqThisType.is(TY_DYN)) |
397 | 33217 | return true; | |
398 | |||
399 | // Give the type matcher a way to retrieve instances of GenericType by their name | ||
400 | 33003 | TypeMatcher::ResolverFct genericTypeResolver = [&](const std::string &genericTypeName) { | |
401 | 2113 | return getGenericTypeOfCandidateByName(candidate, genericTypeName); | |
402 | 15445 | }; | |
403 | |||
404 | // Check if the requested 'this' type matches the candidate 'this' type. The type mapping may be extended | ||
405 |
2/4✓ Branch 0 (11→12) taken 15445 times.
✗ Branch 1 (11→21) not taken.
✗ Branch 2 (12→13) not taken.
✓ Branch 3 (12→14) taken 15445 times.
|
15445 | if (!TypeMatcher::matchRequestedToCandidateType(candidateThisType, reqThisType, typeMapping, genericTypeResolver, |
406 | strictQualifierMatching)) | ||
407 | ✗ | return false; | |
408 | |||
409 | // Substantiate the candidate param type, based on the type mapping | ||
410 |
3/4✓ Branch 0 (14→15) taken 15445 times.
✗ Branch 1 (14→21) not taken.
✓ Branch 2 (15→16) taken 2424 times.
✓ Branch 3 (15→17) taken 13021 times.
|
15445 | if (candidateThisType.hasAnyGenericParts()) |
411 |
1/2✓ Branch 0 (16→17) taken 2424 times.
✗ Branch 1 (16→21) not taken.
|
2424 | TypeMatcher::substantiateTypeWithTypeMapping(candidateThisType, typeMapping, callNode); |
412 | |||
413 | 15445 | return true; | |
414 | 15445 | } | |
415 | |||
416 | /** | ||
417 | * Checks if the matching candidate fulfills the argument types requirement | ||
418 | * | ||
419 | * @param candidate Matching candidate function | ||
420 | * @param reqArgs Requested argument types | ||
421 | * @param typeMapping Concrete template type mapping | ||
422 | * @param strictQualifierMatching Match qualifiers strictly | ||
423 | * @param needsSubstantiation Do we want to create a substantiation after successfully matching | ||
424 | * @param callNode Call AST node for printing error messages | ||
425 | * @return Fulfilled or not | ||
426 | */ | ||
427 | 48662 | bool FunctionManager::matchArgTypes(Function &candidate, const ArgList &reqArgs, TypeMapping &typeMapping, | |
428 | bool strictQualifierMatching, bool &needsSubstantiation, const ASTNode *callNode) { | ||
429 | 48662 | std::vector<Param> &candidateParamList = candidate.paramList; | |
430 | |||
431 | // If the number of arguments does not match with the number of params, the matching fails | ||
432 |
2/2✓ Branch 0 (4→5) taken 6459 times.
✓ Branch 1 (4→6) taken 42203 times.
|
48662 | if (reqArgs.size() != candidateParamList.size()) |
433 | 6459 | return false; | |
434 | |||
435 | // Give the type matcher a way to retrieve instances of GenericType by their name | ||
436 | 88061 | TypeMatcher::ResolverFct genericTypeResolver = [&](const std::string &genericTypeName) { | |
437 | 3655 | return getGenericTypeOfCandidateByName(candidate, genericTypeName); | |
438 | 42203 | }; | |
439 | |||
440 | // Loop over all parameters | ||
441 |
2/2✓ Branch 0 (45→8) taken 45086 times.
✓ Branch 1 (45→46) taken 7629 times.
|
52715 | for (size_t i = 0; i < reqArgs.size(); i++) { |
442 | // Retrieve actual and requested types | ||
443 |
2/4✓ Branch 0 (8→9) taken 45086 times.
✗ Branch 1 (8→62) not taken.
✗ Branch 2 (9→10) not taken.
✓ Branch 3 (9→11) taken 45086 times.
|
45086 | assert(!candidateParamList.at(i).isOptional); |
444 |
1/2✓ Branch 0 (11→12) taken 45086 times.
✗ Branch 1 (11→62) not taken.
|
45086 | QualType &candidateParamType = candidateParamList.at(i).qualType; |
445 |
1/2✓ Branch 0 (12→13) taken 45086 times.
✗ Branch 1 (12→62) not taken.
|
45086 | const auto &[requestedType, isArgTemporary] = reqArgs.at(i); |
446 | |||
447 | // Check if the requested param type matches the candidate param type. The type mapping may be extended | ||
448 |
3/4✓ Branch 0 (15→16) taken 45086 times.
✗ Branch 1 (15→62) not taken.
✓ Branch 2 (16→17) taken 34573 times.
✓ Branch 3 (16→18) taken 10513 times.
|
45086 | if (!TypeMatcher::matchRequestedToCandidateType(candidateParamType, requestedType, typeMapping, genericTypeResolver, |
449 | strictQualifierMatching)) | ||
450 | 34573 | return false; | |
451 | |||
452 | // Substantiate the candidate param type, based on the type mapping | ||
453 |
3/4✓ Branch 0 (18→19) taken 10513 times.
✗ Branch 1 (18→62) not taken.
✓ Branch 2 (19→20) taken 1611 times.
✓ Branch 3 (19→21) taken 8902 times.
|
10513 | if (candidateParamType.hasAnyGenericParts()) |
454 |
1/2✓ Branch 0 (20→21) taken 1611 times.
✗ Branch 1 (20→62) not taken.
|
1611 | TypeMatcher::substantiateTypeWithTypeMapping(candidateParamType, typeMapping, callNode); |
455 | |||
456 | // Check if we try to bind a non-ref temporary to a non-const ref parameter | ||
457 |
3/4✓ Branch 0 (21→22) taken 10513 times.
✗ Branch 1 (21→62) not taken.
✓ Branch 2 (22→23) taken 1 times.
✓ Branch 3 (22→33) taken 10512 times.
|
10513 | if (!candidateParamType.canBind(requestedType, isArgTemporary)) { |
458 |
1/2✓ Branch 0 (23→24) taken 1 times.
✗ Branch 1 (23→32) not taken.
|
1 | if (callNode) |
459 |
2/4✓ Branch 0 (27→28) taken 1 times.
✗ Branch 1 (27→53) not taken.
✓ Branch 2 (28→29) taken 1 times.
✗ Branch 3 (28→50) not taken.
|
3 | throw SemanticError(callNode, TEMP_TO_NON_CONST_REF, "Temporary values can only be bound to const reference parameters"); |
460 | ✗ | return false; | |
461 | } | ||
462 | |||
463 | // If we have a function/procedure type we need to take care of the information, if it takes captures | ||
464 |
9/12✓ Branch 0 (33→34) taken 10512 times.
✗ Branch 1 (33→59) not taken.
✓ Branch 2 (34→35) taken 10512 times.
✗ Branch 3 (34→59) not taken.
✓ Branch 4 (35→36) taken 41 times.
✓ Branch 5 (35→39) taken 10471 times.
✓ Branch 6 (36→37) taken 41 times.
✗ Branch 7 (36→59) not taken.
✓ Branch 8 (37→38) taken 4 times.
✓ Branch 9 (37→39) taken 37 times.
✓ Branch 10 (40→41) taken 4 times.
✓ Branch 11 (40→43) taken 10508 times.
|
10512 | if (requestedType.getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE}) && requestedType.hasLambdaCaptures()) { |
465 |
1/2✓ Branch 0 (41→42) taken 4 times.
✗ Branch 1 (41→61) not taken.
|
4 | candidateParamType = candidateParamType.getWithLambdaCaptures(); |
466 | 4 | needsSubstantiation = true; | |
467 | } | ||
468 | } | ||
469 | |||
470 | 7629 | return true; | |
471 | 42203 | } | |
472 | |||
473 | /** | ||
474 | * Substantiates the candidate return type, based on the given type mapping | ||
475 | * | ||
476 | * @param candidate Matching candidate function | ||
477 | * @param typeMapping Concrete template type mapping | ||
478 | * @param callNode AST node for error messages | ||
479 | */ | ||
480 | 7628 | void FunctionManager::substantiateReturnType(Function &candidate, const TypeMapping &typeMapping, const ASTNode *callNode) { | |
481 |
2/2✓ Branch 0 (3→4) taken 532 times.
✓ Branch 1 (3→5) taken 7096 times.
|
7628 | if (candidate.returnType.hasAnyGenericParts()) |
482 | 532 | TypeMatcher::substantiateTypeWithTypeMapping(candidate.returnType, typeMapping, callNode); | |
483 | 7628 | } | |
484 | |||
485 | /** | ||
486 | * Searches the candidate template types for a generic type object with a certain name and return it | ||
487 | * | ||
488 | * @param candidate Matching candidate function | ||
489 | * @param templateTypeName Template type name | ||
490 | * @return Generic type object | ||
491 | */ | ||
492 | 5768 | const GenericType *FunctionManager::getGenericTypeOfCandidateByName(const Function &candidate, | |
493 | const std::string &templateTypeName) { | ||
494 |
1/2✓ Branch 0 (11→4) taken 6143 times.
✗ Branch 1 (11→12) not taken.
|
6143 | for (const GenericType &templateType : candidate.templateTypes) { |
495 |
3/4✓ Branch 0 (5→6) taken 6143 times.
✗ Branch 1 (5→14) not taken.
✓ Branch 2 (7→8) taken 5768 times.
✓ Branch 3 (7→9) taken 375 times.
|
6143 | if (templateType.getSubType() == templateTypeName) |
496 | 5768 | return &templateType; | |
497 | } | ||
498 | ✗ | return nullptr; | |
499 | } | ||
500 | |||
501 | /** | ||
502 | * Calculate the cache key for the function lookup cache | ||
503 | * | ||
504 | * @param scope Scope to match against | ||
505 | * @param name Function name requirement | ||
506 | * @param thisType This type requirement | ||
507 | * @param args Argument requirement | ||
508 | * @param templateTypes Template type requirement | ||
509 | * @return Cache key | ||
510 | */ | ||
511 | 67915 | uint64_t FunctionManager::getCacheKey(Scope *scope, const std::string &name, const QualType &thisType, const ArgList &args, | |
512 | const QualTypeList &templateTypes) { | ||
513 | 104805 | const auto pred1 = [](size_t acc, const Arg &val) { | |
514 | // Combine the previous hash value with the current element's hash, adjusted by a prime number to reduce collisions | ||
515 | 104805 | const uint64_t typeHash = std::hash<QualType>{}(val.first); | |
516 | 104805 | const uint64_t temporaryHash = std::hash<bool>{}(val.second); | |
517 | 104805 | const uint64_t newHash = typeHash ^ (temporaryHash << 1); | |
518 | 104805 | return acc * 31 + newHash; | |
519 | }; | ||
520 | 602 | const auto pred2 = [](size_t acc, const QualType &val) { | |
521 | // Combine the previous hash value with the current element's hash, adjusted by a prime number to reduce collisions | ||
522 | 602 | return acc * 31 + std::hash<QualType>{}(val); | |
523 | }; | ||
524 | // Calculate the cache key | ||
525 | 67915 | const uint64_t scopeHash = std::hash<Scope *>{}(scope); | |
526 | 67915 | const uint64_t hashName = std::hash<std::string>{}(name); | |
527 | 67915 | const uint64_t hashThisType = std::hash<QualType>{}(thisType); | |
528 | 67915 | const uint64_t hashArgs = std::accumulate(args.begin(), args.end(), 0u, pred1); | |
529 | 67915 | const uint64_t hashTemplateTypes = std::accumulate(templateTypes.begin(), templateTypes.end(), 0u, pred2); | |
530 | 67915 | return scopeHash ^ (hashName << 1) ^ (hashThisType << 2) ^ (hashArgs << 3) ^ (hashTemplateTypes << 4); | |
531 | } | ||
532 | |||
533 | /** | ||
534 | * Clear all statics | ||
535 | */ | ||
536 | 401 | void FunctionManager::clear() { lookupCache.clear(); } | |
537 | |||
538 | } // namespace spice::compiler | ||
539 |