Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2024 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 | 8071 | 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 1 taken 8071 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8071 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8071 times.
✗ Branch 8 not taken.
|
8071 | const std::string fctId = baseFunction.name + ":" + baseFunction.declNode->codeLoc.toPrettyLineAndColumn(); |
23 |
2/4✓ Branch 2 taken 8071 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8071 times.
✗ Branch 6 not taken.
|
8071 | insertScope->functions.insert({fctId, FunctionManifestationList()}); |
24 | |||
25 | // Collect substantiations | ||
26 | 8071 | std::vector<Function> manifestations; | |
27 |
1/2✓ Branch 1 taken 8071 times.
✗ Branch 2 not taken.
|
8071 | substantiateOptionalParams(baseFunction, manifestations); |
28 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8071 times.
|
8071 | assert(!manifestations.empty()); |
29 | |||
30 | // Save substantiations in declaration node | ||
31 | 8071 | Function *manifestationPtr = nullptr; | |
32 |
2/2✓ Branch 5 taken 8731 times.
✓ Branch 6 taken 8069 times.
|
16800 | for (const Function &manifestation : manifestations) { |
33 |
2/2✓ Branch 1 taken 8729 times.
✓ Branch 2 taken 2 times.
|
8731 | manifestationPtr = insertSubstantiation(insertScope, manifestation, baseFunction.declNode); |
34 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8729 times.
|
8729 | assert(manifestationPtr != nullptr); |
35 |
1/2✓ Branch 0 taken 8729 times.
✗ Branch 1 not taken.
|
8729 | if (nodeFunctionList) |
36 |
1/2✓ Branch 1 taken 8729 times.
✗ Branch 2 not taken.
|
8729 | nodeFunctionList->push_back(manifestationPtr); |
37 | } | ||
38 | |||
39 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8069 times.
|
8069 | if (!nodeFunctionList) |
40 | ✗ | return manifestationPtr; | |
41 | |||
42 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8069 times.
|
8069 | assert(!nodeFunctionList->empty()); |
43 | 8069 | return nodeFunctionList->front(); | |
44 | 8073 | } | |
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 | 8071 | 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 1 taken 2322 times.
✓ Branch 2 taken 5749 times.
|
8071 | if (baseFunction.paramList.empty()) { |
65 |
1/2✓ Branch 1 taken 2322 times.
✗ Branch 2 not taken.
|
2322 | manifestations.push_back(baseFunction); |
66 | 2322 | return; | |
67 | } | ||
68 | |||
69 | 5749 | ParamList currentFunctionParamTypes; | |
70 |
1/2✓ Branch 2 taken 5749 times.
✗ Branch 3 not taken.
|
5749 | currentFunctionParamTypes.reserve(baseFunction.paramList.size()); |
71 | 5749 | bool metFirstOptionalParam = false; | |
72 |
1/2✓ Branch 1 taken 5749 times.
✗ Branch 2 not taken.
|
5749 | Function manifestation = baseFunction; |
73 | |||
74 | // Loop over all parameters | ||
75 |
2/2✓ Branch 5 taken 9198 times.
✓ Branch 6 taken 5749 times.
|
14947 | for (const auto &[qualType, isOptional] : baseFunction.paramList) { |
76 | // Check if we have a mandatory parameter | ||
77 |
2/2✓ Branch 0 taken 8538 times.
✓ Branch 1 taken 660 times.
|
9198 | if (!isOptional) { |
78 |
1/2✓ Branch 1 taken 8538 times.
✗ Branch 2 not taken.
|
8538 | currentFunctionParamTypes.push_back({qualType, /*optional=*/false}); |
79 | 8538 | continue; | |
80 | } | ||
81 | |||
82 | // Add substantiation without the optional parameter | ||
83 |
2/2✓ Branch 0 taken 656 times.
✓ Branch 1 taken 4 times.
|
660 | if (!metFirstOptionalParam) { |
84 |
1/2✓ Branch 1 taken 656 times.
✗ Branch 2 not taken.
|
656 | manifestation.paramList = currentFunctionParamTypes; |
85 |
1/2✓ Branch 1 taken 656 times.
✗ Branch 2 not taken.
|
656 | manifestations.push_back(manifestation); |
86 | // Now we cannot accept mandatory parameters anymore | ||
87 | 656 | metFirstOptionalParam = true; | |
88 | } | ||
89 | |||
90 | // Add substantiation with the optional parameter | ||
91 |
1/2✓ Branch 1 taken 660 times.
✗ Branch 2 not taken.
|
660 | currentFunctionParamTypes.push_back({qualType, /*optional=*/false}); |
92 |
1/2✓ Branch 1 taken 660 times.
✗ Branch 2 not taken.
|
660 | manifestation.paramList = currentFunctionParamTypes; |
93 |
1/2✓ Branch 1 taken 660 times.
✗ Branch 2 not taken.
|
660 | manifestations.push_back(manifestation); |
94 | } | ||
95 | |||
96 | // Ensure at least once manifestation | ||
97 |
2/2✓ Branch 1 taken 5093 times.
✓ Branch 2 taken 656 times.
|
5749 | if (manifestations.empty()) |
98 |
1/2✓ Branch 1 taken 5093 times.
✗ Branch 2 not taken.
|
5093 | manifestations.push_back(baseFunction); |
99 | 5749 | } | |
100 | |||
101 | 2 | Function FunctionManager::createMainFunction(SymbolTableEntry *entry, const QualTypeList ¶mTypes, ASTNode *declNode) { | |
102 | 2 | ParamList paramList; | |
103 |
2/2✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
|
4 | for (const QualType ¶mType : paramTypes) |
104 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | paramList.push_back({paramType, false}); |
105 |
4/8✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
|
4 | return {MAIN_FUNCTION_NAME, entry, QualType(TY_DYN), QualType(TY_INT), paramList, {}, declNode}; |
106 | 2 | } | |
107 | |||
108 | 10211 | Function *FunctionManager::insertSubstantiation(Scope *insertScope, const Function &newManifestation, const ASTNode *declNode) { | |
109 |
2/4✓ Branch 1 taken 10211 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10211 times.
|
10211 | assert(newManifestation.hasSubstantiatedParams()); |
110 | |||
111 |
1/2✓ Branch 1 taken 10211 times.
✗ Branch 2 not taken.
|
10211 | const std::string signature = newManifestation.getSignature(); |
112 | |||
113 | // Check if the function exists already | ||
114 |
5/8✓ Branch 1 taken 10211 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10211 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10211 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 113245 times.
✓ Branch 13 taken 10209 times.
|
123454 | for (const auto &manifestations : insertScope->functions | std::views::values) { |
115 |
3/4✓ Branch 1 taken 113245 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 113243 times.
|
113245 | if (manifestations.contains(signature)) { |
116 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (newManifestation.isFunction()) |
117 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(declNode, FUNCTION_DECLARED_TWICE, "'" + signature + "' is declared twice"); |
118 | else | ||
119 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 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 1 taken 10209 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10209 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10209 times.
✗ Branch 8 not taken.
|
10209 | const std::string fctId = newManifestation.name + ":" + declNode->codeLoc.toPrettyLineAndColumn(); |
125 |
2/4✓ Branch 1 taken 10209 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10209 times.
|
10209 | assert(insertScope->functions.contains(fctId)); |
126 |
1/2✓ Branch 1 taken 10209 times.
✗ Branch 2 not taken.
|
10209 | FunctionManifestationList &manifestationList = insertScope->functions.at(fctId); |
127 | |||
128 | // Add substantiated function | ||
129 |
1/2✓ Branch 1 taken 10209 times.
✗ Branch 2 not taken.
|
10209 | manifestationList.emplace(signature, newManifestation); |
130 |
1/2✓ Branch 1 taken 10209 times.
✗ Branch 2 not taken.
|
20418 | return &manifestationList.at(signature); |
131 | 10211 | } | |
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 strictSpecifierMatching Match argument and this type specifiers strictly | ||
141 | * @return Found function or nullptr | ||
142 | */ | ||
143 | 16669 | const Function *FunctionManager::lookup(Scope *matchScope, const std::string &reqName, const QualType &reqThisType, | |
144 | const ArgList &reqArgs, bool strictSpecifierMatching) { | ||
145 |
2/4✓ Branch 1 taken 16669 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 16669 times.
|
16669 | assert(reqThisType.isOneOf({TY_DYN, TY_STRUCT})); |
146 | |||
147 | // Do cache lookup | ||
148 |
1/2✓ Branch 2 taken 16669 times.
✗ Branch 3 not taken.
|
16669 | const uint64_t cacheKey = getCacheKey(matchScope, reqName, reqThisType, reqArgs, {}); |
149 |
3/4✓ Branch 1 taken 16669 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3416 times.
✓ Branch 4 taken 13253 times.
|
16669 | if (lookupCache.contains(cacheKey)) |
150 |
1/2✓ Branch 1 taken 3416 times.
✗ Branch 2 not taken.
|
3416 | return lookupCache.at(cacheKey); |
151 | |||
152 | 5190 | const auto pred = [&](const Arg &arg) { return arg.first.hasAnyGenericParts(); }; | |
153 |
5/8✓ Branch 1 taken 13253 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13082 times.
✓ Branch 4 taken 171 times.
✓ Branch 6 taken 13082 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13082 times.
✗ Branch 9 not taken.
|
13253 | 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 1 taken 13253 times.
✗ Branch 2 not taken.
|
13253 | FunctionRegistry functionRegistry = matchScope->functions; |
157 | // Loop over function registry to find functions, that match the requirements of the call | ||
158 | 13253 | std::vector<const Function *> matches; | |
159 |
2/2✓ Branch 7 taken 92455 times.
✓ Branch 8 taken 13253 times.
|
105708 | 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 1 taken 92455 times.
✗ Branch 2 not taken.
|
92455 | const FunctionManifestationList manifestations = m; |
162 |
2/2✓ Branch 6 taken 100191 times.
✓ Branch 7 taken 41649 times.
|
141840 | for (const auto &[signature, presetFunction] : manifestations) { |
163 |
2/4✓ Branch 1 taken 100191 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 100191 times.
|
100191 | 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 1 taken 100191 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 35087 times.
✓ Branch 4 taken 65104 times.
|
100191 | if (presetFunction.isFullySubstantiated() != requestedFullySubstantiated) |
168 | 49385 | continue; | |
169 | |||
170 | // Copy the function to be able to substantiate types | ||
171 |
1/2✓ Branch 1 taken 65104 times.
✗ Branch 2 not taken.
|
65104 | Function candidate = presetFunction; |
172 | |||
173 | // Create empty type mapping | ||
174 | 65104 | TypeMapping &typeMapping = candidate.typeMapping; | |
175 | |||
176 | 65104 | bool forceSubstantiation = false; | |
177 |
1/2✓ Branch 1 taken 65104 times.
✗ Branch 2 not taken.
|
65104 | const MatchResult matchResult = matchManifestation(candidate, matchScope, reqName, reqThisType, reqArgs, typeMapping, |
178 | strictSpecifierMatching, forceSubstantiation, nullptr); | ||
179 |
2/2✓ Branch 0 taken 48958 times.
✓ Branch 1 taken 16146 times.
|
65104 | if (matchResult == MatchResult::SKIP_FUNCTION) |
180 | 48958 | break; // Leave the whole function | |
181 |
2/2✓ Branch 0 taken 14298 times.
✓ Branch 1 taken 1848 times.
|
16146 | if (matchResult == MatchResult::SKIP_MANIFESTATION) |
182 | 14298 | continue; // Leave this manifestation and try the next one | |
183 | |||
184 | // Add to matches | ||
185 |
3/6✓ Branch 1 taken 1848 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1848 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1848 times.
✗ Branch 8 not taken.
|
1848 | matches.push_back(&matchScope->functions.at(defCodeLocStr).at(signature)); |
186 | |||
187 | 1848 | break; // Leave the whole manifestation list to not double-match the manifestation | |
188 |
2/2✓ Branch 1 taken 14298 times.
✓ Branch 2 taken 50806 times.
|
65104 | } |
189 | 92455 | } | |
190 | |||
191 | // Return the very match or a nullptr | ||
192 |
2/2✓ Branch 1 taken 1848 times.
✓ Branch 2 taken 11405 times.
|
13253 | return !matches.empty() ? matches.front() : nullptr; |
193 | 13253 | } | |
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 strictSpecifierMatching Match argument and this type specifiers strictly | ||
206 | * @param callNode Call AST node for printing error messages | ||
207 | * @return Matched function or nullptr | ||
208 | */ | ||
209 | 42480 | Function *FunctionManager::match(TypeChecker *typeChecker, Scope *matchScope, const std::string &reqName, | |
210 | const QualType &reqThisType, const ArgList &reqArgs, const QualTypeList &templateTypeHints, | ||
211 | bool strictSpecifierMatching, const ASTNode *callNode) { | ||
212 |
2/4✓ Branch 1 taken 42480 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 42480 times.
|
42480 | assert(reqThisType.isOneOf({TY_DYN, TY_STRUCT, TY_INTERFACE})); |
213 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42480 times.
|
42480 | assert(typeChecker != nullptr && "The match() function must be called from the TypeChecker"); |
214 | |||
215 | // Do cache lookup | ||
216 |
1/2✓ Branch 1 taken 42480 times.
✗ Branch 2 not taken.
|
42480 | const uint64_t cacheKey = getCacheKey(matchScope, reqName, reqThisType, reqArgs, templateTypeHints); |
217 |
3/4✓ Branch 1 taken 42480 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8555 times.
✓ Branch 4 taken 33925 times.
|
42480 | if (lookupCache.contains(cacheKey)) |
218 |
1/2✓ Branch 1 taken 8555 times.
✗ Branch 2 not taken.
|
8555 | return lookupCache.at(cacheKey); |
219 | |||
220 | // Copy the registry to prevent iterating over items, that are created within the loop | ||
221 |
1/2✓ Branch 1 taken 33925 times.
✗ Branch 2 not taken.
|
33925 | FunctionRegistry functionRegistry = matchScope->functions; |
222 | // Loop over function registry to find functions, that match the requirements of the call | ||
223 | 33925 | std::vector<Function *> matches; | |
224 |
2/2✓ Branch 7 taken 300686 times.
✓ Branch 8 taken 33924 times.
|
334610 | 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 1 taken 300686 times.
✗ Branch 2 not taken.
|
300686 | const FunctionManifestationList manifestations = m; |
227 |
2/2✓ Branch 6 taken 321965 times.
✓ Branch 7 taken 25936 times.
|
347901 | for (const auto &[signature, presetFunction] : manifestations) { |
228 |
2/4✓ Branch 1 taken 321965 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 321965 times.
|
321965 | 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 1 taken 321965 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19740 times.
✓ Branch 4 taken 302225 times.
|
321965 | if (presetFunction.isGenericSubstantiation()) |
232 | 47215 | continue; | |
233 | |||
234 | // Copy the function to be able to substantiate types | ||
235 |
1/2✓ Branch 1 taken 302225 times.
✗ Branch 2 not taken.
|
302225 | Function candidate = presetFunction; |
236 | |||
237 | // Prepare type mapping, based on the given initial type mapping | ||
238 | 302225 | TypeMapping &typeMapping = candidate.typeMapping; | |
239 | 302225 | typeMapping.clear(); | |
240 |
2/2✓ Branch 3 taken 2694 times.
✓ Branch 4 taken 302225 times.
|
304919 | for (size_t i = 0; i < std::min(templateTypeHints.size(), candidate.templateTypes.size()); i++) { |
241 |
2/4✓ Branch 1 taken 2694 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2694 times.
✗ Branch 5 not taken.
|
2694 | const std::string &typeName = candidate.templateTypes.at(i).getSubType(); |
242 |
1/2✓ Branch 1 taken 2694 times.
✗ Branch 2 not taken.
|
2694 | const QualType &templateType = templateTypeHints.at(i); |
243 |
2/4✓ Branch 1 taken 2694 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2694 times.
✗ Branch 5 not taken.
|
2694 | typeMapping.insert({typeName, templateType}); |
244 | } | ||
245 | |||
246 | 302225 | bool forceSubstantiation = false; | |
247 |
2/2✓ Branch 1 taken 302224 times.
✓ Branch 2 taken 1 times.
|
302225 | MatchResult matchResult = matchManifestation(candidate, matchScope, reqName, reqThisType, reqArgs, typeMapping, |
248 | strictSpecifierMatching, forceSubstantiation, callNode); | ||
249 |
2/2✓ Branch 0 taken 273178 times.
✓ Branch 1 taken 29046 times.
|
302224 | if (matchResult == MatchResult::SKIP_FUNCTION) |
250 | 273178 | break; // Leave the whole function | |
251 |
2/2✓ Branch 0 taken 23791 times.
✓ Branch 1 taken 5255 times.
|
29046 | if (matchResult == MatchResult::SKIP_MANIFESTATION) |
252 | 23791 | 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 | 5255 | candidate.used = true; | |
256 | 5255 | candidate.entry->used = true; | |
257 | |||
258 | // Check if the function is generic needs to be substantiated | ||
259 |
6/6✓ Branch 1 taken 3687 times.
✓ Branch 2 taken 1568 times.
✓ Branch 3 taken 3684 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3684 times.
✓ Branch 6 taken 1571 times.
|
5255 | if (presetFunction.templateTypes.empty() && !forceSubstantiation) { |
260 |
5/10✓ Branch 1 taken 3684 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3684 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3684 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3684 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3684 times.
✗ Branch 12 not taken.
|
3684 | assert(matchScope->functions.contains(fctId) && matchScope->functions.at(fctId).contains(signature)); |
261 |
3/6✓ Branch 1 taken 3684 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3684 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3684 times.
✗ Branch 8 not taken.
|
3684 | matches.push_back(&matchScope->functions.at(fctId).at(signature)); |
262 | 3684 | matches.back()->used = true; | |
263 | 3684 | 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 1 taken 1571 times.
✗ Branch 2 not taken.
|
1571 | const std::string nonGenericSignature = candidate.getSignature(); |
268 |
4/6✓ Branch 1 taken 1571 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1571 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 91 times.
✓ Branch 7 taken 1480 times.
|
1571 | if (matchScope->functions.at(fctId).contains(nonGenericSignature)) { |
269 |
3/6✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 91 times.
✗ Branch 8 not taken.
|
91 | matches.push_back(&matchScope->functions.at(fctId).at(nonGenericSignature)); |
270 | 91 | 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 1 taken 1480 times.
✗ Branch 2 not taken.
|
1480 | Function *substantiatedFunction = insertSubstantiation(matchScope, candidate, presetFunction.declNode); |
275 |
2/4✓ Branch 1 taken 1480 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1480 times.
✗ Branch 5 not taken.
|
1480 | substantiatedFunction->genericPreset = &matchScope->functions.at(fctId).at(signature); |
276 | 1480 | substantiatedFunction->alreadyTypeChecked = false; | |
277 |
2/4✓ Branch 1 taken 1480 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1480 times.
✗ Branch 5 not taken.
|
1480 | substantiatedFunction->declNode->getFctManifestations(reqName)->push_back(substantiatedFunction); |
278 | |||
279 | // Copy function entry | ||
280 |
1/2✓ Branch 1 taken 1480 times.
✗ Branch 2 not taken.
|
1480 | const std::string newSignature = substantiatedFunction->getSignature(false); |
281 |
1/2✓ Branch 1 taken 1480 times.
✗ Branch 2 not taken.
|
1480 | matchScope->lookupStrict(presetFunction.entry->name)->used = true; |
282 |
1/2✓ Branch 1 taken 1480 times.
✗ Branch 2 not taken.
|
1480 | substantiatedFunction->entry = matchScope->symbolTable.copySymbol(presetFunction.entry->name, newSignature); |
283 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1480 times.
|
1480 | assert(substantiatedFunction->entry != nullptr); |
284 | |||
285 | // Copy function scope | ||
286 |
1/2✓ Branch 1 taken 1480 times.
✗ Branch 2 not taken.
|
1480 | const std::string oldSignature = presetFunction.getSignature(false); |
287 |
1/2✓ Branch 1 taken 1480 times.
✗ Branch 2 not taken.
|
1480 | Scope *childScope = matchScope->copyChildScope(oldSignature, newSignature); |
288 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1480 times.
|
1480 | assert(childScope != nullptr); |
289 | 1480 | childScope->isGenericScope = false; | |
290 | 1480 | substantiatedFunction->bodyScope = childScope; | |
291 | |||
292 | // Insert symbols for generic type names with concrete types into the child block | ||
293 |
2/2✓ Branch 6 taken 1767 times.
✓ Branch 7 taken 1480 times.
|
3247 | for (const auto &[typeName, concreteType] : substantiatedFunction->typeMapping) |
294 |
2/4✓ Branch 1 taken 1767 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1767 times.
✗ Branch 5 not taken.
|
1767 | childScope->insertGenericType(typeName, GenericType(concreteType)); |
295 | |||
296 | // Substantiate the 'this' entry in the new function scope | ||
297 |
6/6✓ Branch 0 taken 1229 times.
✓ Branch 1 taken 251 times.
✓ Branch 3 taken 1228 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1228 times.
✓ Branch 6 taken 252 times.
|
1480 | if (presetFunction.isMethod() && !presetFunction.templateTypes.empty()) { |
298 |
1/2✓ Branch 1 taken 1228 times.
✗ Branch 2 not taken.
|
3684 | SymbolTableEntry *thisEntry = childScope->lookupStrict(THIS_VARIABLE_NAME); |
299 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1228 times.
|
1228 | assert(thisEntry != nullptr); |
300 |
2/4✓ Branch 1 taken 1228 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1228 times.
✗ Branch 5 not taken.
|
1228 | thisEntry->updateType(candidate.thisType.toPtr(callNode), /*overwriteExistingType=*/true); |
301 | } | ||
302 | |||
303 | // Add to matched functions | ||
304 |
1/2✓ Branch 1 taken 1480 times.
✗ Branch 2 not taken.
|
1480 | matches.push_back(substantiatedFunction); |
305 | |||
306 | 1480 | break; // Leave the whole manifestation list to not double-match the manifestation | |
307 |
2/2✓ Branch 4 taken 27475 times.
✓ Branch 5 taken 274749 times.
|
303796 | } |
308 | 300686 | } | |
309 | |||
310 | // If no matches were found, return a nullptr | ||
311 |
2/2✓ Branch 1 taken 28670 times.
✓ Branch 2 taken 5254 times.
|
33924 | if (matches.empty()) |
312 | 28670 | return nullptr; | |
313 | |||
314 | // Check if more than one function matches the requirements | ||
315 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5253 times.
|
5254 | if (matches.size() > 1) { |
316 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | std::stringstream errorMessage; |
317 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
1 | errorMessage << "The function/procedure '" << reqName << "' is ambiguous. All of the following match the requested criteria:"; |
318 |
2/2✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
|
3 | for (const Function *match : matches) |
319 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
2 | errorMessage << "\n " << match->getSignature(); |
320 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | throw SemanticError(callNode, FUNCTION_AMBIGUITY, errorMessage.str()); |
321 | 1 | } | |
322 | |||
323 | // Insert into cache | ||
324 |
1/2✓ Branch 2 taken 5253 times.
✗ Branch 3 not taken.
|
5253 | lookupCache[cacheKey] = matches.front(); |
325 | |||
326 | // Trigger revisit in type checker if required | ||
327 |
1/2✓ Branch 2 taken 5253 times.
✗ Branch 3 not taken.
|
5253 | typeChecker->requestRevisitIfRequired(matches.front()); |
328 | |||
329 | // Return the very match | ||
330 | 5253 | return matches.front(); | |
331 | 33927 | } | |
332 | |||
333 | 367329 | MatchResult FunctionManager::matchManifestation(Function &candidate, Scope *&matchScope, const std::string &reqName, | |
334 | const QualType &reqThisType, const ArgList &reqArgs, TypeMapping &typeMapping, | ||
335 | bool strictSpecifierMatching, bool &forceSubstantiation, | ||
336 | const ASTNode *callNode) { | ||
337 | // Check name requirement | ||
338 |
2/2✓ Branch 1 taken 322136 times.
✓ Branch 2 taken 45193 times.
|
367329 | if (!matchName(candidate, reqName)) |
339 | 322136 | return MatchResult::SKIP_FUNCTION; // Leave the whole manifestation list, because all have the same name | |
340 | |||
341 | // Check 'this' type requirement | ||
342 |
2/2✓ Branch 1 taken 296 times.
✓ Branch 2 taken 44897 times.
|
45193 | if (!matchThisType(candidate, reqThisType, typeMapping, strictSpecifierMatching, callNode)) |
343 | 296 | return MatchResult::SKIP_MANIFESTATION; // Leave this manifestation and try the next one | |
344 | |||
345 | // Check arg types requirement | ||
346 |
2/2✓ Branch 1 taken 37792 times.
✓ Branch 2 taken 7104 times.
|
44897 | if (!matchArgTypes(candidate, reqArgs, typeMapping, strictSpecifierMatching, forceSubstantiation, callNode)) |
347 | 37792 | 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 2 taken 1 times.
✓ Branch 3 taken 7103 times.
|
7104 | 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 | 7103 | substantiateReturnType(candidate, typeMapping, callNode); | |
355 | |||
356 | 7103 | const QualType &thisType = candidate.thisType; | |
357 |
2/2✓ Branch 1 taken 5017 times.
✓ Branch 2 taken 2086 times.
|
7103 | if (!thisType.is(TY_DYN)) { |
358 | // If we only have the generic struct scope, lookup the concrete manifestation scope | ||
359 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 4974 times.
|
5017 | if (matchScope->isGenericScope) { |
360 | 43 | const std::string &structName = thisType.getSubType(); | |
361 | 43 | Scope *scope = thisType.getBodyScope()->parent; | |
362 | 43 | Struct *spiceStruct = StructManager::match(scope, structName, thisType.getTemplateTypes(), candidate.declNode); | |
363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | assert(spiceStruct != nullptr); |
364 | 43 | matchScope = spiceStruct->scope; | |
365 | } | ||
366 |
1/2✓ Branch 1 taken 5017 times.
✗ Branch 2 not taken.
|
5017 | candidate.thisType = candidate.thisType.getWithBodyScope(matchScope); |
367 | } | ||
368 | |||
369 | 7103 | 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 | 367329 | 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 strictSpecifierMatching Match specifiers strictly | ||
388 | * @param callNode Call AST node for printing error messages | ||
389 | * @return Fulfilled or not | ||
390 | */ | ||
391 | 45193 | bool FunctionManager::matchThisType(Function &candidate, const QualType &reqThisType, TypeMapping &typeMapping, | |
392 | bool strictSpecifierMatching, const ASTNode *callNode) { | ||
393 | 45193 | QualType &candidateThisType = candidate.thisType; | |
394 | |||
395 | // Shortcut for procedures | ||
396 |
7/10✓ Branch 1 taken 45193 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21108 times.
✓ Branch 4 taken 24085 times.
✓ Branch 6 taken 21108 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 21108 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 21108 times.
✓ Branch 11 taken 24085 times.
|
45193 | if (candidateThisType.is(TY_DYN) && reqThisType.is(TY_DYN)) |
397 | 21108 | return true; | |
398 | |||
399 | // Give the type matcher a way to retrieve instances of GenericType by their name | ||
400 | 50142 | TypeMatcher::ResolverFct genericTypeResolver = [&](const std::string &genericTypeName) { | |
401 | 1972 | return getGenericTypeOfCandidateByName(candidate, genericTypeName); | |
402 | 24085 | }; | |
403 | |||
404 | // Check if the requested 'this' type matches the candidate 'this' type. The type mapping may be extended | ||
405 |
3/4✓ Branch 1 taken 24085 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 296 times.
✓ Branch 4 taken 23789 times.
|
24085 | if (!TypeMatcher::matchRequestedToCandidateType(candidateThisType, reqThisType, typeMapping, genericTypeResolver, |
406 | strictSpecifierMatching)) | ||
407 | 296 | return false; | |
408 | |||
409 | // Substantiate the candidate param type, based on the type mapping | ||
410 |
3/4✓ Branch 1 taken 23789 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2214 times.
✓ Branch 4 taken 21575 times.
|
23789 | if (candidateThisType.hasAnyGenericParts()) |
411 |
1/2✓ Branch 1 taken 2214 times.
✗ Branch 2 not taken.
|
2214 | TypeMatcher::substantiateTypeWithTypeMapping(candidateThisType, typeMapping, callNode); |
412 | |||
413 | 23789 | return true; | |
414 | 24085 | } | |
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 strictSpecifierMatching Match specifiers 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 | 44897 | bool FunctionManager::matchArgTypes(Function &candidate, const ArgList &reqArgs, TypeMapping &typeMapping, | |
428 | bool strictSpecifierMatching, bool &needsSubstantiation, const ASTNode *callNode) { | ||
429 | 44897 | 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 2 taken 12474 times.
✓ Branch 3 taken 32423 times.
|
44897 | if (reqArgs.size() != candidateParamList.size()) |
433 | 12474 | return false; | |
434 | |||
435 | // Give the type matcher a way to retrieve instances of GenericType by their name | ||
436 | 67897 | TypeMatcher::ResolverFct genericTypeResolver = [&](const std::string &genericTypeName) { | |
437 | 3051 | return getGenericTypeOfCandidateByName(candidate, genericTypeName); | |
438 | 32423 | }; | |
439 | |||
440 | // Loop over all parameters | ||
441 |
2/2✓ Branch 1 taken 34141 times.
✓ Branch 2 taken 7104 times.
|
41245 | for (size_t i = 0; i < reqArgs.size(); i++) { |
442 | // Retrieve actual and requested types | ||
443 |
2/4✓ Branch 1 taken 34141 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 34141 times.
|
34141 | assert(!candidateParamList.at(i).isOptional); |
444 |
1/2✓ Branch 1 taken 34141 times.
✗ Branch 2 not taken.
|
34141 | QualType &candidateParamType = candidateParamList.at(i).qualType; |
445 |
1/2✓ Branch 1 taken 34141 times.
✗ Branch 2 not taken.
|
34141 | 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 1 taken 34141 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25318 times.
✓ Branch 4 taken 8823 times.
|
34141 | if (!TypeMatcher::matchRequestedToCandidateType(candidateParamType, requestedType, typeMapping, genericTypeResolver, |
449 | strictSpecifierMatching)) | ||
450 | 25318 | return false; | |
451 | |||
452 | // Substantiate the candidate param type, based on the type mapping | ||
453 |
3/4✓ Branch 1 taken 8823 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1349 times.
✓ Branch 4 taken 7474 times.
|
8823 | if (candidateParamType.hasAnyGenericParts()) |
454 |
1/2✓ Branch 1 taken 1349 times.
✗ Branch 2 not taken.
|
1349 | 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 1 taken 8823 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 8822 times.
|
8823 | if (!candidateParamType.canBind(requestedType, isArgTemporary)) { |
458 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (callNode) |
459 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 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 1 taken 8822 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8822 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 29 times.
✓ Branch 7 taken 8793 times.
✓ Branch 9 taken 29 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 25 times.
✓ Branch 13 taken 4 times.
✓ Branch 14 taken 8818 times.
|
8822 | if (requestedType.getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE}) && requestedType.hasLambdaCaptures()) { |
465 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | candidateParamType = candidateParamType.getWithLambdaCaptures(); |
466 | 4 | needsSubstantiation = true; | |
467 | } | ||
468 | } | ||
469 | |||
470 | 7104 | return true; | |
471 | 32423 | } | |
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 | 7103 | void FunctionManager::substantiateReturnType(Function &candidate, const TypeMapping &typeMapping, const ASTNode *callNode) { | |
481 |
2/2✓ Branch 1 taken 493 times.
✓ Branch 2 taken 6610 times.
|
7103 | if (candidate.returnType.hasAnyGenericParts()) |
482 | 493 | TypeMatcher::substantiateTypeWithTypeMapping(candidate.returnType, typeMapping, callNode); | |
483 | 7103 | } | |
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 | 5023 | const GenericType *FunctionManager::getGenericTypeOfCandidateByName(const Function &candidate, | |
493 | const std::string &templateTypeName) { | ||
494 |
1/2✓ Branch 5 taken 5380 times.
✗ Branch 6 not taken.
|
5380 | for (const GenericType &templateType : candidate.templateTypes) { |
495 |
3/4✓ Branch 1 taken 5380 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5023 times.
✓ Branch 5 taken 357 times.
|
5380 | if (templateType.getSubType() == templateTypeName) |
496 | 5023 | 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 | 59149 | uint64_t FunctionManager::getCacheKey(Scope *scope, const std::string &name, const QualType &thisType, const ArgList &args, | |
512 | const QualTypeList &templateTypes) { | ||
513 | 72203 | 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 | 72203 | const uint64_t typeHash = std::hash<QualType>{}(val.first); | |
516 | 72203 | const uint64_t temporaryHash = std::hash<bool>{}(val.second); | |
517 | 72203 | const uint64_t newHash = typeHash ^ (temporaryHash << 1); | |
518 | 72203 | return acc * 31 + newHash; | |
519 | }; | ||
520 | 499 | 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 | 499 | return acc * 31 + std::hash<QualType>{}(val); | |
523 | }; | ||
524 | // Calculate the cache key | ||
525 | 59149 | const uint64_t scopeHash = std::hash<Scope *>{}(scope); | |
526 | 59149 | const uint64_t hashName = std::hash<std::string>{}(name); | |
527 | 59149 | const uint64_t hashThisType = std::hash<QualType>{}(thisType); | |
528 | 59149 | const uint64_t hashArgs = std::accumulate(args.begin(), args.end(), 0u, pred1); | |
529 | 59149 | const uint64_t hashTemplateTypes = std::accumulate(templateTypes.begin(), templateTypes.end(), 0u, pred2); | |
530 | 59149 | return scopeHash ^ (hashName << 1) ^ (hashThisType << 2) ^ (hashArgs << 3) ^ (hashTemplateTypes << 4); | |
531 | } | ||
532 | |||
533 | /** | ||
534 | * Clear all statics | ||
535 | */ | ||
536 | 390 | void FunctionManager::clear() { lookupCache.clear(); } | |
537 | |||
538 | } // namespace spice::compiler | ||
539 |