Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2024 ChilliBits. All rights reserved. | ||
2 | |||
3 | #include "StructManager.h" | ||
4 | |||
5 | #include <ast/ASTNodes.h> | ||
6 | #include <exception/SemanticError.h> | ||
7 | #include <symboltablebuilder/Scope.h> | ||
8 | #include <symboltablebuilder/SymbolTableBuilder.h> | ||
9 | #include <typechecker/TypeMatcher.h> | ||
10 | #include <util/CodeLoc.h> | ||
11 | #include <util/CustomHashFunctions.h> | ||
12 | |||
13 | namespace spice::compiler { | ||
14 | |||
15 | // Static member initialization | ||
16 | std::unordered_map<uint64_t, Struct *> StructManager::lookupCache = {}; | ||
17 | |||
18 | 540 | Struct *StructManager::insert(Scope *insertScope, Struct &spiceStruct, std::vector<Struct *> *nodeStructList) { | |
19 | // Open a new manifestation list. Which gets filled by the substantiated manifestations of the struct | ||
20 |
3/6✓ Branch 1 taken 540 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 540 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 540 times.
✗ Branch 8 not taken.
|
540 | const std::string structId = spiceStruct.name + ":" + spiceStruct.declNode->codeLoc.toPrettyLineAndColumn(); |
21 |
2/4✓ Branch 2 taken 540 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 540 times.
✗ Branch 6 not taken.
|
540 | insertScope->structs.insert({structId, StructManifestationList()}); |
22 | |||
23 | // Save substantiation in declaration node | ||
24 |
1/2✓ Branch 1 taken 540 times.
✗ Branch 2 not taken.
|
540 | Struct *substantiation = insertSubstantiation(insertScope, spiceStruct, spiceStruct.declNode); |
25 |
1/2✓ Branch 1 taken 540 times.
✗ Branch 2 not taken.
|
540 | nodeStructList->push_back(substantiation); |
26 | |||
27 | 540 | return substantiation; | |
28 | 540 | } | |
29 | |||
30 | 854 | Struct *StructManager::insertSubstantiation(Scope *insertScope, Struct &newManifestation, const ASTNode *declNode) { | |
31 |
1/2✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
|
854 | const std::string signature = newManifestation.getSignature(); |
32 | |||
33 | #ifndef NDEBUG | ||
34 | // Make sure that the manifestation does not exist already | ||
35 |
5/8✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 854 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 854 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 1204 times.
✓ Branch 13 taken 854 times.
|
2058 | for (const auto &val : insertScope->structs | std::views::values) |
36 |
2/4✓ Branch 1 taken 1204 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1204 times.
|
1204 | assert(!val.contains(signature)); |
37 | #endif | ||
38 | |||
39 | // Retrieve the matching manifestation list of the scope | ||
40 |
3/6✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 854 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 854 times.
✗ Branch 8 not taken.
|
854 | const std::string structId = newManifestation.name + ":" + declNode->codeLoc.toPrettyLineAndColumn(); |
41 |
2/4✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 854 times.
|
854 | assert(insertScope->structs.contains(structId)); |
42 |
1/2✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
|
854 | StructManifestationList &manifestationList = insertScope->structs.at(structId); |
43 | |||
44 | // Add substantiated struct | ||
45 | 854 | newManifestation.manifestationIndex = manifestationList.size(); | |
46 |
1/2✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
|
854 | manifestationList.emplace(signature, newManifestation); |
47 |
1/2✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
|
1708 | return &manifestationList.at(signature); |
48 | 854 | } | |
49 | |||
50 | /** | ||
51 | * Check if there is a struct in this scope, fulfilling all given requirements and if found, return it. | ||
52 | * If more than one struct matches the requirement, an error gets thrown | ||
53 | * | ||
54 | * @param matchScope Scope to match against | ||
55 | * @param qt Struct name requirement | ||
56 | * @param reqTemplateTypes Template types to substantiate generic types | ||
57 | * @param node Instantiation AST node for printing error messages | ||
58 | * @return Matched struct or nullptr | ||
59 | */ | ||
60 | 16465 | Struct *StructManager::match(Scope *matchScope, const std::string &qt, const QualTypeList &reqTemplateTypes, | |
61 | const ASTNode *node) { | ||
62 | // Do cache lookup | ||
63 |
1/2✓ Branch 1 taken 16465 times.
✗ Branch 2 not taken.
|
16465 | const uint64_t cacheKey = getCacheKey(matchScope, qt, reqTemplateTypes); |
64 |
3/4✓ Branch 1 taken 16465 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15536 times.
✓ Branch 4 taken 929 times.
|
16465 | if (lookupCache.contains(cacheKey)) |
65 |
1/2✓ Branch 1 taken 15536 times.
✗ Branch 2 not taken.
|
15536 | return lookupCache.at(cacheKey); |
66 | |||
67 | // Copy the registry to prevent iterating over items, that are created within the loop | ||
68 |
1/2✓ Branch 1 taken 929 times.
✗ Branch 2 not taken.
|
929 | StructRegistry structRegistry = matchScope->structs; |
69 | // Loop over struct registry to find structs, that match the requirements of the instantiation | ||
70 | 929 | std::vector<Struct *> matches; | |
71 |
2/2✓ Branch 7 taken 1329 times.
✓ Branch 8 taken 929 times.
|
2258 | for (const auto &[structId, m] : structRegistry) { |
72 | // Copy the manifestation list to prevent iterating over items, that are created within the loop | ||
73 |
1/2✓ Branch 1 taken 1329 times.
✗ Branch 2 not taken.
|
1329 | const StructManifestationList manifestations = m; |
74 |
2/2✓ Branch 7 taken 1897 times.
✓ Branch 8 taken 679 times.
|
2576 | for (const auto &[mangledName, presetStruct] : manifestations) { |
75 | // Skip generic substantiations to prevent double matching of a struct | ||
76 |
3/4✓ Branch 1 taken 1897 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 568 times.
✓ Branch 4 taken 1329 times.
|
1897 | if (presetStruct.isGenericSubstantiation()) |
77 | 933 | continue; | |
78 | |||
79 | // Copy the struct to be able to substantiate types | ||
80 |
1/2✓ Branch 1 taken 1329 times.
✗ Branch 2 not taken.
|
1329 | Struct candidate = presetStruct; |
81 | |||
82 | // Check name requirement | ||
83 |
2/2✓ Branch 1 taken 436 times.
✓ Branch 2 taken 893 times.
|
1329 | if (!matchName(candidate, qt)) |
84 | 436 | break; // Leave the whole manifestation list, because all manifestations in this list have the same name | |
85 | |||
86 | // Prepare mapping table from generic type name to concrete type | ||
87 | 893 | TypeMapping &typeMapping = candidate.typeMapping; | |
88 | 893 | typeMapping.clear(); | |
89 |
1/2✓ Branch 2 taken 893 times.
✗ Branch 3 not taken.
|
893 | typeMapping.reserve(candidate.templateTypes.size()); |
90 | |||
91 | // Check template types requirement | ||
92 |
3/4✓ Branch 1 taken 893 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 892 times.
|
893 | if (!matchTemplateTypes(candidate, reqTemplateTypes, typeMapping, node)) |
93 | 1 | continue; // Leave this manifestation and continue with the next one | |
94 | |||
95 | // Map field types from generic to concrete | ||
96 |
1/2✓ Branch 1 taken 892 times.
✗ Branch 2 not taken.
|
892 | substantiateFieldTypes(candidate, typeMapping, node); |
97 | |||
98 | // We found a match! -> Set the actual candidate and its entry to used | ||
99 | 892 | candidate.used = true; | |
100 | 892 | candidate.entry->used = true; | |
101 | |||
102 | // Check if it needs to be substantiated | ||
103 |
2/2✓ Branch 1 taken 364 times.
✓ Branch 2 taken 528 times.
|
892 | if (presetStruct.templateTypes.empty()) { |
104 |
5/10✓ Branch 1 taken 364 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 364 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 364 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 364 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 364 times.
✗ Branch 12 not taken.
|
364 | assert(matchScope->structs.contains(structId) && matchScope->structs.at(structId).contains(mangledName)); |
105 |
3/6✓ Branch 1 taken 364 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 364 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 364 times.
✗ Branch 8 not taken.
|
364 | matches.push_back(&matchScope->structs.at(structId).at(mangledName)); |
106 | 364 | matches.back()->used = true; | |
107 | 364 | continue; // Match was successful -> match the next struct | |
108 | } | ||
109 | |||
110 | // Check if we already have this manifestation and can simply re-use it | ||
111 |
4/6✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 528 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 214 times.
✓ Branch 8 taken 314 times.
|
528 | if (manifestations.contains(candidate.getSignature())) { |
112 |
4/8✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 214 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 214 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 214 times.
✗ Branch 11 not taken.
|
214 | matches.push_back(&matchScope->structs.at(structId).at(candidate.getSignature())); |
113 | 214 | break; // Leave the whole manifestation list to not double-match the manifestation | |
114 | } | ||
115 | |||
116 | // Insert the substantiated version if required | ||
117 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | Struct *substantiatedStruct = insertSubstantiation(matchScope, candidate, presetStruct.declNode); |
118 |
2/4✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 314 times.
✗ Branch 5 not taken.
|
314 | substantiatedStruct->genericPreset = &matchScope->structs.at(structId).at(mangledName); |
119 |
2/4✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 314 times.
✗ Branch 5 not taken.
|
314 | substantiatedStruct->declNode->getStructManifestations()->push_back(substantiatedStruct); |
120 | |||
121 | // Copy struct entry | ||
122 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | const std::string newSignature = substantiatedStruct->getSignature(); |
123 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | matchScope->lookupStrict(substantiatedStruct->name)->used = true; |
124 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | substantiatedStruct->entry = matchScope->symbolTable.copySymbol(substantiatedStruct->name, newSignature); |
125 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 314 times.
|
314 | assert(substantiatedStruct->entry != nullptr); |
126 | |||
127 | // Copy struct scope | ||
128 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | const std::string oldScopeName = STRUCT_SCOPE_PREFIX + presetStruct.name; |
129 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | const std::string newScopeName = STRUCT_SCOPE_PREFIX + newSignature; |
130 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | substantiatedStruct->scope = matchScope->copyChildScope(oldScopeName, newScopeName); |
131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 314 times.
|
314 | assert(substantiatedStruct->scope != nullptr); |
132 | 314 | substantiatedStruct->scope->isGenericScope = false; | |
133 | |||
134 | // Attach the template types to the new struct entry | ||
135 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | QualType entryType = substantiatedStruct->entry->getQualType() |
136 |
2/4✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 314 times.
✗ Branch 5 not taken.
|
628 | .getWithTemplateTypes(substantiatedStruct->getTemplateTypes()) |
137 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | .getWithBodyScope(substantiatedStruct->scope); |
138 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | substantiatedStruct->entry->updateType(entryType, true); |
139 | |||
140 | // Replace symbol types of field entries with concrete types | ||
141 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 314 times.
|
314 | assert(substantiatedStruct->scope != nullptr); |
142 | 314 | const size_t fieldCount = substantiatedStruct->fieldTypes.size(); | |
143 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | const size_t explicitFieldsStartIdx = substantiatedStruct->scope->getFieldCount() - fieldCount; |
144 |
2/2✓ Branch 0 taken 738 times.
✓ Branch 1 taken 314 times.
|
1052 | for (size_t i = 0; i < fieldCount; i++) { |
145 | // Replace field type with concrete template type | ||
146 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 738 times.
|
738 | SymbolTableEntry *fieldEntry = substantiatedStruct->scope->lookupField(explicitFieldsStartIdx + i); |
147 |
3/6✓ Branch 0 taken 738 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 738 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 738 times.
✗ Branch 6 not taken.
|
738 | assert(fieldEntry != nullptr && fieldEntry->isField()); |
148 |
1/2✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
|
738 | QualType &fieldType = substantiatedStruct->fieldTypes.at(i); |
149 |
1/2✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
|
738 | QualType baseType = fieldType.getBase(); |
150 | |||
151 | // Set the body scope of fields that are of type <candidate-struct>* | ||
152 |
4/6✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 738 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 720 times.
|
738 | if (baseType.matches(substantiatedStruct->entry->getQualType(), false, true, true)) |
153 |
2/4✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | fieldType = fieldType.replaceBaseType(baseType.getWithBodyScope(substantiatedStruct->scope)); |
154 | |||
155 |
1/2✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
|
738 | fieldEntry->updateType(fieldType, /*overwriteExistingType=*/true); |
156 | |||
157 | // Instantiate structs | ||
158 |
3/4✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 254 times.
✓ Branch 4 taken 484 times.
|
738 | if (baseType.is(TY_STRUCT)) |
159 |
1/2✓ Branch 1 taken 254 times.
✗ Branch 2 not taken.
|
254 | baseType.getStruct(node); |
160 | } | ||
161 | |||
162 | // Instantiate implemented interfaces if required | ||
163 |
2/2✓ Branch 5 taken 102 times.
✓ Branch 6 taken 314 times.
|
416 | for (QualType &interfaceType : substantiatedStruct->interfaceTypes) { |
164 | // Skip non-generic interfaces | ||
165 |
2/4✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 102 times.
|
102 | if (!interfaceType.hasAnyGenericParts()) |
166 | ✗ | continue; | |
167 | |||
168 | // Build template types | ||
169 |
2/4✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
|
102 | QualTypeList templateTypes = interfaceType.getTemplateTypes(); |
170 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | TypeMatcher::substantiateTypesWithTypeMapping(templateTypes, typeMapping, node); |
171 | |||
172 | // Instantiate interface | ||
173 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | Scope *interfaceMatchScope = interfaceType.getBodyScope()->parent; |
174 |
2/4✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
|
102 | Interface *spiceInterface = InterfaceManager::match(interfaceMatchScope, interfaceType.getSubType(), templateTypes, node); |
175 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | assert(spiceInterface != nullptr); |
176 | |||
177 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | interfaceType = spiceInterface->entry->getQualType(); |
178 | 102 | } | |
179 | |||
180 | // Add to matched structs | ||
181 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | matches.push_back(substantiatedStruct); |
182 |
3/3✓ Branch 4 taken 314 times.
✓ Branch 5 taken 365 times.
✓ Branch 6 taken 650 times.
|
1329 | } |
183 | 1329 | } | |
184 | |||
185 | // If no matches were found, return a nullptr | ||
186 |
2/2✓ Branch 1 taken 37 times.
✓ Branch 2 taken 892 times.
|
929 | if (matches.empty()) |
187 | 37 | return nullptr; | |
188 | |||
189 | // Check if more than one struct matches the requirements | ||
190 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 892 times.
|
892 | if (matches.size() > 1) |
191 | ✗ | throw SemanticError(node, STRUCT_AMBIGUITY, "Multiple structs match the requested signature"); | |
192 | |||
193 | // Insert into cache | ||
194 |
1/2✓ Branch 2 taken 892 times.
✗ Branch 3 not taken.
|
892 | lookupCache[cacheKey] = matches.front(); |
195 | |||
196 | 892 | return matches.front(); | |
197 | 929 | } | |
198 | |||
199 | /** | ||
200 | * Checks if the matching candidate fulfills the name requirement | ||
201 | * | ||
202 | * @param candidate Matching candidate struct | ||
203 | * @param reqName Requested struct name | ||
204 | * @return Fulfilled or not | ||
205 | */ | ||
206 | 1329 | bool StructManager::matchName(const Struct &candidate, const std::string &reqName) { return candidate.name == reqName; } | |
207 | |||
208 | /** | ||
209 | * Checks if the matching candidate fulfills the template types requirement | ||
210 | * | ||
211 | * @param candidate Matching candidate struct | ||
212 | * @param reqTemplateTypes Requested struct template types | ||
213 | * @param typeMapping Generic type mapping | ||
214 | * @param node Instantiation AST node for printing error messages | ||
215 | * @return Fulfilled or not | ||
216 | */ | ||
217 | 893 | bool StructManager::matchTemplateTypes(Struct &candidate, const QualTypeList &reqTemplateTypes, TypeMapping &typeMapping, | |
218 | const ASTNode *node) { | ||
219 | // Check if the number of types match | ||
220 | 893 | const size_t typeCount = reqTemplateTypes.size(); | |
221 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 892 times.
|
893 | if (typeCount != candidate.templateTypes.size()) |
222 | 1 | return false; | |
223 | |||
224 | // Give the type matcher a way to retrieve instances of GenericType by their name | ||
225 | 2540 | TypeMatcher::ResolverFct genericTypeResolver = [&](const std::string &genericTypeName) { | |
226 | 756 | return getGenericTypeOfCandidateByName(candidate, genericTypeName); | |
227 | 892 | }; | |
228 | |||
229 | // Loop over all template types | ||
230 |
2/2✓ Branch 0 taken 756 times.
✓ Branch 1 taken 892 times.
|
1648 | for (size_t i = 0; i < typeCount; i++) { |
231 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | const QualType &reqType = reqTemplateTypes.at(i); |
232 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | QualType &candidateType = candidate.templateTypes.at(i); |
233 | |||
234 | // Check if the requested template type matches the candidate template type. The type mapping may be extended | ||
235 |
2/4✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 756 times.
|
756 | if (!TypeMatcher::matchRequestedToCandidateType(candidateType, reqType, typeMapping, genericTypeResolver, false)) |
236 | ✗ | return false; | |
237 | |||
238 | // Substantiate the candidate param type, based on the type mapping | ||
239 |
2/4✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 756 times.
✗ Branch 4 not taken.
|
756 | if (candidateType.hasAnyGenericParts()) |
240 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | TypeMatcher::substantiateTypeWithTypeMapping(candidateType, typeMapping, node); |
241 | } | ||
242 | |||
243 | 892 | return true; | |
244 | 892 | } | |
245 | |||
246 | /** | ||
247 | * Come up with the concrete field types, by applying the type mapping onto the generic field types | ||
248 | * | ||
249 | * @param candidate Candidate struct | ||
250 | * @param typeMapping Generic type mapping | ||
251 | * @param node Instantiation AST node for printing error messages | ||
252 | */ | ||
253 | 892 | void StructManager::substantiateFieldTypes(Struct &candidate, const TypeMapping &typeMapping, const ASTNode *node) { | |
254 | // Loop over all implicit fields and substantiate the generic ones | ||
255 | 892 | const size_t fieldCount = candidate.scope->getFieldCount() - candidate.fieldTypes.size(); | |
256 |
2/2✓ Branch 0 taken 194 times.
✓ Branch 1 taken 892 times.
|
1086 | for (size_t i = 0; i < fieldCount; i++) { |
257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 194 times.
|
194 | SymbolTableEntry *fieldEntry = candidate.scope->lookupField(i); |
258 |
1/2✓ Branch 1 taken 194 times.
✗ Branch 2 not taken.
|
194 | QualType fieldType = fieldEntry->getQualType(); |
259 |
3/4✓ Branch 1 taken 194 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 148 times.
✓ Branch 4 taken 46 times.
|
194 | if (fieldType.hasAnyGenericParts()) { |
260 |
1/2✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
|
148 | TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, node); |
261 |
1/2✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
|
148 | fieldEntry->updateType(fieldType, true); |
262 | } | ||
263 | } | ||
264 | |||
265 | // Loop over all explicit field types and substantiate the generic ones | ||
266 |
2/2✓ Branch 5 taken 2016 times.
✓ Branch 6 taken 892 times.
|
2908 | for (QualType &fieldType : candidate.fieldTypes) |
267 |
3/4✓ Branch 1 taken 2016 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 836 times.
✓ Branch 4 taken 1180 times.
|
2016 | if (fieldType.hasAnyGenericParts()) |
268 |
1/2✓ Branch 1 taken 836 times.
✗ Branch 2 not taken.
|
836 | TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, node); |
269 | 892 | } | |
270 | |||
271 | /** | ||
272 | * Searches the candidate template types for a generic type object with a certain name and return it | ||
273 | * | ||
274 | * @param candidate Matching candidate struct | ||
275 | * @param templateTypeName Template type name | ||
276 | * @return Generic type object | ||
277 | */ | ||
278 | 756 | const GenericType *StructManager::getGenericTypeOfCandidateByName(const Struct &candidate, const std::string &templateTypeName) { | |
279 |
1/2✓ Branch 5 taken 986 times.
✗ Branch 6 not taken.
|
986 | for (const GenericType &templateType : candidate.templateTypes) { |
280 |
3/4✓ Branch 1 taken 986 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✓ Branch 4 taken 830 times.
|
986 | if (!templateType.is(TY_GENERIC)) |
281 | 156 | continue; | |
282 |
3/4✓ Branch 1 taken 830 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✓ Branch 5 taken 74 times.
|
830 | if (templateType.getSubType() == templateTypeName) |
283 | 756 | return &templateType; | |
284 | } | ||
285 | ✗ | return nullptr; | |
286 | } | ||
287 | |||
288 | /** | ||
289 | * Calculate the cache key for the struct lookup cache | ||
290 | * | ||
291 | * @param scope Scope to match against | ||
292 | * @param name Struct name requirement | ||
293 | * @param templateTypes Template types to substantiate generic types | ||
294 | * @return Cache key | ||
295 | */ | ||
296 | 16465 | uint64_t StructManager::getCacheKey(Scope *scope, const std::string &name, const QualTypeList &templateTypes) { | |
297 | 9820 | const auto pred = [](size_t acc, const QualType &val) { | |
298 | // Combine the previous hash value with the current element's hash, adjusted by a prime number to reduce collisions | ||
299 | 9820 | return acc * 31 + std::hash<QualType>{}(val); | |
300 | }; | ||
301 | // Calculate the cache key | ||
302 | 16465 | const uint64_t scopeHash = std::hash<Scope *>{}(scope); | |
303 | 16465 | const uint64_t hashName = std::hash<std::string>{}(name); | |
304 | 16465 | const uint64_t hashTemplateTypes = std::accumulate(templateTypes.begin(), templateTypes.end(), 0u, pred); | |
305 | 16465 | return scopeHash ^ (hashName << 1) ^ (hashTemplateTypes << 2); | |
306 | } | ||
307 | |||
308 | /** | ||
309 | * Clear all statics | ||
310 | */ | ||
311 | 390 | void StructManager::clear() { lookupCache.clear(); } | |
312 | |||
313 | } // namespace spice::compiler | ||
314 |