GCC Code Coverage Report


Directory: ../
File: src/typechecker/StructManager.cpp
Date: 2025-03-05 01:50:32
Exec Total Coverage
Lines: 150 154 97.4%
Functions: 12 12 100.0%
Branches: 166 289 57.4%

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