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 | 664 | 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 2 → 3 taken 664 times.
✗ Branch 2 → 22 not taken.
✓ Branch 3 → 4 taken 664 times.
✗ Branch 3 → 19 not taken.
✓ Branch 4 → 5 taken 664 times.
✗ Branch 4 → 17 not taken.
|
664 | const std::string structId = spiceStruct.name + ":" + spiceStruct.declNode->codeLoc.toPrettyLineAndColumn(); |
23 |
2/4✓ Branch 8 → 9 taken 664 times.
✗ Branch 8 → 25 not taken.
✓ Branch 9 → 10 taken 664 times.
✗ Branch 9 → 23 not taken.
|
664 | insertScope->structs.insert({structId, StructManifestationList()}); |
24 | |||
25 | // Save substantiation in declaration node | ||
26 |
1/2✓ Branch 12 → 13 taken 664 times.
✗ Branch 12 → 29 not taken.
|
664 | Struct *substantiation = insertSubstantiation(insertScope, spiceStruct, spiceStruct.declNode); |
27 |
1/2✓ Branch 13 → 14 taken 664 times.
✗ Branch 13 → 29 not taken.
|
664 | nodeStructList->push_back(substantiation); |
28 | |||
29 | 664 | return substantiation; | |
30 | 664 | } | |
31 | |||
32 | 1099 | Struct *StructManager::insertSubstantiation(Scope *insertScope, Struct &newManifestation, const ASTNode *declNode) { | |
33 |
1/2✓ Branch 2 → 3 taken 1099 times.
✗ Branch 2 → 42 not taken.
|
1099 | const std::string signature = newManifestation.getSignature(); |
34 | |||
35 | #ifndef NDEBUG | ||
36 | // Make sure that the manifestation does not exist already | ||
37 |
5/8✓ Branch 3 → 4 taken 1099 times.
✗ Branch 3 → 31 not taken.
✓ Branch 4 → 5 taken 1099 times.
✗ Branch 4 → 31 not taken.
✓ Branch 5 → 6 taken 1099 times.
✗ Branch 5 → 31 not taken.
✓ Branch 13 → 7 taken 1693 times.
✓ Branch 13 → 14 taken 1099 times.
|
2792 | for (const auto &val : insertScope->structs | std::views::values) |
38 |
2/4✓ Branch 8 → 9 taken 1693 times.
✗ Branch 8 → 31 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 1693 times.
|
1693 | assert(!val.contains(signature)); |
39 | #endif | ||
40 | |||
41 | // Retrieve the matching manifestation list of the scope | ||
42 |
3/6✓ Branch 14 → 15 taken 1099 times.
✗ Branch 14 → 37 not taken.
✓ Branch 15 → 16 taken 1099 times.
✗ Branch 15 → 34 not taken.
✓ Branch 16 → 17 taken 1099 times.
✗ Branch 16 → 32 not taken.
|
1099 | const std::string structId = newManifestation.name + ":" + declNode->codeLoc.toPrettyLineAndColumn(); |
43 |
2/4✓ Branch 19 → 20 taken 1099 times.
✗ Branch 19 → 38 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 1099 times.
|
1099 | assert(insertScope->structs.contains(structId)); |
44 |
1/2✓ Branch 22 → 23 taken 1099 times.
✗ Branch 22 → 38 not taken.
|
1099 | StructManifestationList &manifestationList = insertScope->structs.at(structId); |
45 | |||
46 | // Add substantiated struct | ||
47 | 1099 | newManifestation.manifestationIndex = manifestationList.size(); | |
48 |
1/2✓ Branch 24 → 25 taken 1099 times.
✗ Branch 24 → 38 not taken.
|
1099 | manifestationList.emplace(signature, newManifestation); |
49 |
1/2✓ Branch 25 → 26 taken 1099 times.
✗ Branch 25 → 38 not taken.
|
2198 | return &manifestationList.at(signature); |
50 | 1099 | } | |
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 | 23860 | Struct *StructManager::match(Scope *matchScope, const std::string &qt, const QualTypeList &reqTemplateTypes, | |
63 | const ASTNode *node) { | ||
64 | // Do cache lookup | ||
65 |
1/2✓ Branch 2 → 3 taken 23860 times.
✗ Branch 2 → 212 not taken.
|
23860 | const uint64_t cacheKey = getCacheKey(matchScope, qt, reqTemplateTypes); |
66 |
3/4✓ Branch 3 → 4 taken 23860 times.
✗ Branch 3 → 212 not taken.
✓ Branch 4 → 5 taken 22618 times.
✓ Branch 4 → 7 taken 1242 times.
|
23860 | if (lookupCache.contains(cacheKey)) { |
67 | 22618 | lookupCacheHits++; | |
68 |
1/2✓ Branch 5 → 6 taken 22618 times.
✗ Branch 5 → 212 not taken.
|
22618 | return lookupCache.at(cacheKey); |
69 | } | ||
70 | 1242 | lookupCacheMisses++; | |
71 | |||
72 | // Copy the registry to prevent iterating over items, that are created within the loop | ||
73 |
1/2✓ Branch 7 → 8 taken 1242 times.
✗ Branch 7 → 212 not taken.
|
1242 | StructRegistry structRegistry = matchScope->structs; |
74 | // Loop over struct registry to find structs, that match the requirements of the instantiation | ||
75 | 1242 | std::vector<Struct *> matches; | |
76 |
2/2✓ Branch 144 → 10 taken 1965 times.
✓ Branch 144 → 145 taken 1242 times.
|
3207 | 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 13 → 14 taken 1965 times.
✗ Branch 13 → 197 not taken.
|
1965 | const StructManifestationList manifestations = m; |
79 |
2/2✓ Branch 140 → 16 taken 2856 times.
✓ Branch 140 → 141 taken 856 times.
|
3712 | for (const auto &[mangledName, presetStruct] : manifestations) { |
80 | // Skip generic substantiations to prevent double matching of a struct | ||
81 |
3/4✓ Branch 19 → 20 taken 2856 times.
✗ Branch 19 → 193 not taken.
✓ Branch 20 → 21 taken 891 times.
✓ Branch 20 → 22 taken 1965 times.
|
2856 | if (presetStruct.isGenericSubstantiation()) |
82 | 1312 | continue; | |
83 | |||
84 | // Copy the struct to be able to substantiate types | ||
85 |
1/2✓ Branch 22 → 23 taken 1965 times.
✗ Branch 22 → 193 not taken.
|
1965 | Struct candidate = presetStruct; |
86 | |||
87 | // Check name requirement | ||
88 |
2/2✓ Branch 24 → 25 taken 775 times.
✓ Branch 24 → 26 taken 1190 times.
|
1965 | if (!matchName(candidate, qt)) |
89 | 775 | 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 | 1190 | TypeMapping &typeMapping = candidate.typeMapping; | |
93 | 1190 | typeMapping.clear(); | |
94 |
1/2✓ Branch 28 → 29 taken 1190 times.
✗ Branch 28 → 191 not taken.
|
1190 | typeMapping.reserve(candidate.templateTypes.size()); |
95 | |||
96 | // Check template types requirement | ||
97 |
3/4✓ Branch 29 → 30 taken 1190 times.
✗ Branch 29 → 191 not taken.
✓ Branch 30 → 31 taken 1 time.
✓ Branch 30 → 32 taken 1189 times.
|
1190 | 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 32 → 33 taken 1189 times.
✗ Branch 32 → 191 not taken.
|
1189 | substantiateFieldTypes(candidate, typeMapping, node); |
102 | |||
103 | // We found a match! -> Set the actual candidate and its entry to used | ||
104 | 1189 | candidate.used = true; | |
105 | 1189 | candidate.entry->used = true; | |
106 | |||
107 | // Check if it needs to be substantiated | ||
108 |
2/2✓ Branch 34 → 35 taken 420 times.
✓ Branch 34 → 47 taken 769 times.
|
1189 | if (presetStruct.templateTypes.empty()) { |
109 |
5/10✓ Branch 35 → 36 taken 420 times.
✗ Branch 35 → 191 not taken.
✓ Branch 36 → 37 taken 420 times.
✗ Branch 36 → 41 not taken.
✓ Branch 37 → 38 taken 420 times.
✗ Branch 37 → 191 not taken.
✓ Branch 38 → 39 taken 420 times.
✗ Branch 38 → 191 not taken.
✓ Branch 39 → 40 taken 420 times.
✗ Branch 39 → 41 not taken.
|
420 | assert(matchScope->structs.contains(structId) && matchScope->structs.at(structId).contains(mangledName)); |
110 |
3/6✓ Branch 42 → 43 taken 420 times.
✗ Branch 42 → 166 not taken.
✓ Branch 43 → 44 taken 420 times.
✗ Branch 43 → 166 not taken.
✓ Branch 44 → 45 taken 420 times.
✗ Branch 44 → 166 not taken.
|
420 | matches.push_back(&matchScope->structs.at(structId).at(mangledName)); |
111 | 420 | matches.back()->used = true; | |
112 | 420 | 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 47 → 48 taken 769 times.
✗ Branch 47 → 169 not taken.
✓ Branch 48 → 49 taken 769 times.
✗ Branch 48 → 167 not taken.
✓ Branch 50 → 51 taken 334 times.
✓ Branch 50 → 57 taken 435 times.
|
769 | if (manifestations.contains(candidate.getSignature())) { |
117 |
4/8✓ Branch 51 → 52 taken 334 times.
✗ Branch 51 → 173 not taken.
✓ Branch 52 → 53 taken 334 times.
✗ Branch 52 → 172 not taken.
✓ Branch 53 → 54 taken 334 times.
✗ Branch 53 → 170 not taken.
✓ Branch 54 → 55 taken 334 times.
✗ Branch 54 → 170 not taken.
|
334 | matches.push_back(&matchScope->structs.at(structId).at(candidate.getSignature())); |
118 | 334 | 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 57 → 58 taken 435 times.
✗ Branch 57 → 191 not taken.
|
435 | Struct *substantiatedStruct = insertSubstantiation(matchScope, candidate, presetStruct.declNode); |
123 |
2/4✓ Branch 58 → 59 taken 435 times.
✗ Branch 58 → 191 not taken.
✓ Branch 59 → 60 taken 435 times.
✗ Branch 59 → 191 not taken.
|
435 | substantiatedStruct->genericPreset = &matchScope->structs.at(structId).at(mangledName); |
124 |
2/4✓ Branch 60 → 61 taken 435 times.
✗ Branch 60 → 191 not taken.
✓ Branch 61 → 62 taken 435 times.
✗ Branch 61 → 191 not taken.
|
435 | substantiatedStruct->declNode->getStructManifestations()->push_back(substantiatedStruct); |
125 | |||
126 | // Copy struct entry | ||
127 |
1/2✓ Branch 62 → 63 taken 435 times.
✗ Branch 62 → 191 not taken.
|
435 | const std::string newSignature = substantiatedStruct->getSignature(); |
128 |
1/2✓ Branch 63 → 64 taken 435 times.
✗ Branch 63 → 189 not taken.
|
435 | matchScope->lookupStrict(substantiatedStruct->name)->used = true; |
129 |
1/2✓ Branch 66 → 67 taken 435 times.
✗ Branch 66 → 189 not taken.
|
435 | substantiatedStruct->entry = matchScope->symbolTable.copySymbol(substantiatedStruct->name, newSignature); |
130 |
1/2✗ Branch 67 → 68 not taken.
✓ Branch 67 → 69 taken 435 times.
|
435 | assert(substantiatedStruct->entry != nullptr); |
131 | |||
132 | // Copy struct scope | ||
133 |
1/2✓ Branch 69 → 70 taken 435 times.
✗ Branch 69 → 189 not taken.
|
435 | const std::string oldScopeName = STRUCT_SCOPE_PREFIX + presetStruct.name; |
134 |
1/2✓ Branch 70 → 71 taken 435 times.
✗ Branch 70 → 187 not taken.
|
435 | const std::string newScopeName = STRUCT_SCOPE_PREFIX + newSignature; |
135 |
1/2✓ Branch 71 → 72 taken 435 times.
✗ Branch 71 → 185 not taken.
|
435 | substantiatedStruct->scope = matchScope->copyChildScope(oldScopeName, newScopeName); |
136 |
1/2✗ Branch 72 → 73 not taken.
✓ Branch 72 → 74 taken 435 times.
|
435 | assert(substantiatedStruct->scope != nullptr); |
137 | 435 | substantiatedStruct->scope->isGenericScope = false; | |
138 | |||
139 | // Attach the template types to the new struct entry | ||
140 |
1/2✓ Branch 74 → 75 taken 435 times.
✗ Branch 74 → 177 not taken.
|
435 | QualType entryType = substantiatedStruct->entry->getQualType() |
141 |
2/4✓ Branch 75 → 76 taken 435 times.
✗ Branch 75 → 176 not taken.
✓ Branch 76 → 77 taken 435 times.
✗ Branch 76 → 174 not taken.
|
870 | .getWithTemplateTypes(substantiatedStruct->getTemplateTypes()) |
142 |
1/2✓ Branch 77 → 78 taken 435 times.
✗ Branch 77 → 174 not taken.
|
435 | .getWithBodyScope(substantiatedStruct->scope); |
143 |
1/2✓ Branch 79 → 80 taken 435 times.
✗ Branch 79 → 185 not taken.
|
435 | substantiatedStruct->entry->updateType(entryType, true); |
144 | |||
145 | // Replace symbol types of field entries with concrete types | ||
146 |
1/2✗ Branch 80 → 81 not taken.
✓ Branch 80 → 82 taken 435 times.
|
435 | assert(substantiatedStruct->scope != nullptr); |
147 | 435 | const size_t fieldCount = substantiatedStruct->fieldTypes.size(); | |
148 |
1/2✓ Branch 83 → 84 taken 435 times.
✗ Branch 83 → 185 not taken.
|
435 | const size_t explicitFieldsStartIdx = substantiatedStruct->scope->getFieldCount() - fieldCount; |
149 |
2/2✓ Branch 108 → 85 taken 1015 times.
✓ Branch 108 → 109 taken 435 times.
|
1450 | for (size_t i = 0; i < fieldCount; i++) { |
150 | // Replace field type with concrete template type | ||
151 |
1/2✗ Branch 85 → 86 not taken.
✓ Branch 85 → 87 taken 1015 times.
|
1015 | SymbolTableEntry *fieldEntry = substantiatedStruct->scope->lookupField(explicitFieldsStartIdx + i); |
152 |
3/6✓ Branch 90 → 91 taken 1015 times.
✗ Branch 90 → 94 not taken.
✓ Branch 91 → 92 taken 1015 times.
✗ Branch 91 → 180 not taken.
✓ Branch 92 → 93 taken 1015 times.
✗ Branch 92 → 94 not taken.
|
1015 | assert(fieldEntry != nullptr && fieldEntry->isField()); |
153 |
1/2✓ Branch 95 → 96 taken 1015 times.
✗ Branch 95 → 180 not taken.
|
1015 | QualType &fieldType = substantiatedStruct->fieldTypes.at(i); |
154 |
1/2✓ Branch 96 → 97 taken 1015 times.
✗ Branch 96 → 180 not taken.
|
1015 | QualType baseType = fieldType.getBase(); |
155 | |||
156 | // Set the body scope of fields that are of type <candidate-struct>* | ||
157 |
4/6✓ Branch 97 → 98 taken 1015 times.
✗ Branch 97 → 180 not taken.
✓ Branch 98 → 99 taken 1015 times.
✗ Branch 98 → 180 not taken.
✓ Branch 99 → 100 taken 33 times.
✓ Branch 99 → 103 taken 982 times.
|
1015 | if (baseType.matches(substantiatedStruct->entry->getQualType(), false, true, true)) |
158 |
2/4✓ Branch 100 → 101 taken 33 times.
✗ Branch 100 → 178 not taken.
✓ Branch 101 → 102 taken 33 times.
✗ Branch 101 → 178 not taken.
|
33 | fieldType = fieldType.replaceBaseType(baseType.getWithBodyScope(substantiatedStruct->scope)); |
159 | |||
160 |
1/2✓ Branch 103 → 104 taken 1015 times.
✗ Branch 103 → 180 not taken.
|
1015 | fieldEntry->updateType(fieldType, /*overwriteExistingType=*/true); |
161 | |||
162 | // Instantiate structs | ||
163 |
3/4✓ Branch 104 → 105 taken 1015 times.
✗ Branch 104 → 180 not taken.
✓ Branch 105 → 106 taken 395 times.
✓ Branch 105 → 107 taken 620 times.
|
1015 | if (baseType.is(TY_STRUCT)) |
164 |
1/2✓ Branch 106 → 107 taken 395 times.
✗ Branch 106 → 180 not taken.
|
395 | (void)baseType.getStruct(node); |
165 | } | ||
166 | |||
167 | // Instantiate implemented interfaces if required | ||
168 |
2/2✓ Branch 126 → 111 taken 152 times.
✓ Branch 126 → 127 taken 435 times.
|
587 | for (QualType &interfaceType : substantiatedStruct->interfaceTypes) { |
169 | // Skip non-generic interfaces | ||
170 |
2/4✓ Branch 112 → 113 taken 152 times.
✗ Branch 112 → 183 not taken.
✗ Branch 113 → 114 not taken.
✓ Branch 113 → 115 taken 152 times.
|
152 | if (!interfaceType.hasAnyGenericParts()) |
171 | ✗ | continue; | |
172 | |||
173 | // Build template types | ||
174 |
2/4✓ Branch 115 → 116 taken 152 times.
✗ Branch 115 → 183 not taken.
✓ Branch 116 → 117 taken 152 times.
✗ Branch 116 → 183 not taken.
|
152 | QualTypeList templateTypes = interfaceType.getTemplateTypes(); |
175 |
1/2✓ Branch 117 → 118 taken 152 times.
✗ Branch 117 → 181 not taken.
|
152 | TypeMatcher::substantiateTypesWithTypeMapping(templateTypes, typeMapping, node); |
176 | |||
177 | // Instantiate interface | ||
178 |
1/2✓ Branch 118 → 119 taken 152 times.
✗ Branch 118 → 181 not taken.
|
152 | Interface *spiceInterface = interfaceType.getInterface(node, templateTypes); |
179 |
1/2✗ Branch 119 → 120 not taken.
✓ Branch 119 → 121 taken 152 times.
|
152 | assert(spiceInterface != nullptr); |
180 |
1/2✓ Branch 121 → 122 taken 152 times.
✗ Branch 121 → 181 not taken.
|
152 | interfaceType = spiceInterface->entry->getQualType(); |
181 | 152 | } | |
182 | |||
183 | // Add to matched structs | ||
184 |
1/2✓ Branch 127 → 128 taken 435 times.
✗ Branch 127 → 185 not taken.
|
435 | matches.push_back(substantiatedStruct); |
185 |
3/3✓ Branch 133 → 134 taken 435 times.
✓ Branch 133 → 136 taken 421 times.
✓ Branch 133 → 137 taken 1109 times.
|
1965 | } |
186 | 1965 | } | |
187 | |||
188 | // If no matches were found, return a nullptr | ||
189 |
2/2✓ Branch 146 → 147 taken 53 times.
✓ Branch 146 → 148 taken 1189 times.
|
1242 | if (matches.empty()) |
190 | 53 | return nullptr; | |
191 | |||
192 | // Check if more than one struct matches the requirements | ||
193 |
1/2✗ Branch 149 → 150 not taken.
✓ Branch 149 → 158 taken 1189 times.
|
1189 | 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 159 → 160 taken 1189 times.
✗ Branch 159 → 208 not taken.
|
1189 | lookupCache[cacheKey] = matches.front(); |
198 | |||
199 | 1189 | return matches.front(); | |
200 | 1242 | } | |
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 | 1965 | 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 | 1190 | bool StructManager::matchTemplateTypes(Struct &candidate, const QualTypeList &reqTemplateTypes, TypeMapping &typeMapping, | |
221 | const ASTNode *node) { | ||
222 | // Check if the number of types match | ||
223 | 1190 | const size_t typeCount = reqTemplateTypes.size(); | |
224 |
2/2✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 1189 times.
|
1190 | 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 | 3504 | TypeMatcher::ResolverFct genericTypeResolver = [&](const std::string &genericTypeName) { | |
229 | 1126 | return getGenericTypeOfCandidateByName(candidate, genericTypeName); | |
230 | 1189 | }; | |
231 | |||
232 | // Loop over all template types | ||
233 |
2/2✓ Branch 17 → 8 taken 1126 times.
✓ Branch 17 → 18 taken 1189 times.
|
2315 | for (size_t i = 0; i < typeCount; i++) { |
234 |
1/2✓ Branch 8 → 9 taken 1126 times.
✗ Branch 8 → 22 not taken.
|
1126 | const QualType &reqType = reqTemplateTypes.at(i); |
235 |
1/2✓ Branch 9 → 10 taken 1126 times.
✗ Branch 9 → 22 not taken.
|
1126 | 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 10 → 11 taken 1126 times.
✗ Branch 10 → 22 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1126 times.
|
1126 | 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 13 → 14 taken 1126 times.
✗ Branch 13 → 22 not taken.
✓ Branch 14 → 15 taken 1126 times.
✗ Branch 14 → 16 not taken.
|
1126 | if (candidateType.hasAnyGenericParts()) |
243 |
1/2✓ Branch 15 → 16 taken 1126 times.
✗ Branch 15 → 22 not taken.
|
1126 | TypeMatcher::substantiateTypeWithTypeMapping(candidateType, typeMapping, node); |
244 | } | ||
245 | |||
246 | 1189 | return true; | |
247 | 1189 | } | |
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 | 1189 | void StructManager::substantiateFieldTypes(Struct &candidate, const TypeMapping &typeMapping, const ASTNode *node) { | |
257 | // Loop over all implicit fields and substantiate the generic ones | ||
258 | 1189 | const size_t fieldCount = candidate.scope->getFieldCount() - candidate.fieldTypes.size(); | |
259 |
2/2✓ Branch 16 → 5 taken 309 times.
✓ Branch 16 → 17 taken 1189 times.
|
1498 | for (size_t i = 0; i < fieldCount; i++) { |
260 |
1/2✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 309 times.
|
309 | SymbolTableEntry *fieldEntry = candidate.scope->lookupField(i); |
261 |
1/2✓ Branch 10 → 11 taken 309 times.
✗ Branch 10 → 27 not taken.
|
309 | QualType fieldType = fieldEntry->getQualType(); |
262 |
3/4✓ Branch 11 → 12 taken 309 times.
✗ Branch 11 → 27 not taken.
✓ Branch 12 → 13 taken 254 times.
✓ Branch 12 → 15 taken 55 times.
|
309 | if (fieldType.hasAnyGenericParts()) { |
263 |
1/2✓ Branch 13 → 14 taken 254 times.
✗ Branch 13 → 27 not taken.
|
254 | TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, node); |
264 |
1/2✓ Branch 14 → 15 taken 254 times.
✗ Branch 14 → 27 not taken.
|
254 | fieldEntry->updateType(fieldType, true); |
265 | } | ||
266 | } | ||
267 | |||
268 | // Loop over all explicit field types and substantiate the generic ones | ||
269 |
2/2✓ Branch 25 → 19 taken 2693 times.
✓ Branch 25 → 26 taken 1189 times.
|
3882 | for (QualType &fieldType : candidate.fieldTypes) |
270 |
3/4✓ Branch 20 → 21 taken 2693 times.
✗ Branch 20 → 28 not taken.
✓ Branch 21 → 22 taken 1250 times.
✓ Branch 21 → 23 taken 1443 times.
|
2693 | if (fieldType.hasAnyGenericParts()) |
271 |
1/2✓ Branch 22 → 23 taken 1250 times.
✗ Branch 22 → 28 not taken.
|
1250 | TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, node); |
272 | 1189 | } | |
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 | 1126 | const GenericType *StructManager::getGenericTypeOfCandidateByName(const Struct &candidate, const std::string &templateTypeName) { | |
282 |
1/2✓ Branch 14 → 4 taken 1485 times.
✗ Branch 14 → 15 not taken.
|
1485 | for (const GenericType &templateType : candidate.templateTypes) { |
283 |
3/4✓ Branch 5 → 6 taken 1485 times.
✗ Branch 5 → 17 not taken.
✓ Branch 6 → 7 taken 221 times.
✓ Branch 6 → 8 taken 1264 times.
|
1485 | if (!templateType.is(TY_GENERIC)) |
284 | 221 | continue; | |
285 |
3/4✓ Branch 8 → 9 taken 1264 times.
✗ Branch 8 → 17 not taken.
✓ Branch 10 → 11 taken 1126 times.
✓ Branch 10 → 12 taken 138 times.
|
1264 | if (templateType.getSubType() == templateTypeName) |
286 | 1126 | 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 | 23860 | uint64_t StructManager::getCacheKey(Scope *scope, const std::string &name, const QualTypeList &templateTypes) { | |
300 | 13388 | 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 | 13388 | return acc * 31 + std::hash<QualType>{}(val); | |
303 | }; | ||
304 | // Calculate the cache key | ||
305 | 23860 | const uint64_t scopeHash = std::hash<Scope *>{}(scope); | |
306 | 23860 | const uint64_t hashName = std::hash<std::string>{}(name); | |
307 | 23860 | const uint64_t hashTemplateTypes = std::accumulate(templateTypes.begin(), templateTypes.end(), 0u, pred); | |
308 | 23860 | return scopeHash ^ (hashName << 1) ^ (hashTemplateTypes << 2); | |
309 | } | ||
310 | |||
311 | /** | ||
312 | * Clear the lookup cache | ||
313 | */ | ||
314 | 416 | void StructManager::cleanup() { | |
315 | 416 | lookupCache.clear(); | |
316 | 416 | lookupCacheHits = 0; | |
317 | 416 | lookupCacheMisses = 0; | |
318 | 416 | } | |
319 | |||
320 | /** | ||
321 | * Dump usage statistics for the lookup cache | ||
322 | */ | ||
323 | 198 | std::string StructManager::dumpLookupCacheStatistics() { | |
324 |
1/2✓ Branch 2 → 3 taken 198 times.
✗ Branch 2 → 22 not taken.
|
198 | std::stringstream stats; |
325 |
2/4✓ Branch 3 → 4 taken 198 times.
✗ Branch 3 → 20 not taken.
✓ Branch 4 → 5 taken 198 times.
✗ Branch 4 → 20 not taken.
|
198 | stats << "StructManager lookup cache statistics:" << std::endl; |
326 |
3/6✓ Branch 5 → 6 taken 198 times.
✗ Branch 5 → 20 not taken.
✓ Branch 7 → 8 taken 198 times.
✗ Branch 7 → 20 not taken.
✓ Branch 8 → 9 taken 198 times.
✗ Branch 8 → 20 not taken.
|
198 | stats << " lookup cache entries: " << lookupCache.size() << std::endl; |
327 |
3/6✓ Branch 9 → 10 taken 198 times.
✗ Branch 9 → 20 not taken.
✓ Branch 10 → 11 taken 198 times.
✗ Branch 10 → 20 not taken.
✓ Branch 11 → 12 taken 198 times.
✗ Branch 11 → 20 not taken.
|
198 | stats << " lookup cache hits: " << lookupCacheHits << std::endl; |
328 |
3/6✓ Branch 12 → 13 taken 198 times.
✗ Branch 12 → 20 not taken.
✓ Branch 13 → 14 taken 198 times.
✗ Branch 13 → 20 not taken.
✓ Branch 14 → 15 taken 198 times.
✗ Branch 14 → 20 not taken.
|
198 | stats << " lookup cache misses: " << lookupCacheMisses << std::endl; |
329 |
1/2✓ Branch 15 → 16 taken 198 times.
✗ Branch 15 → 20 not taken.
|
396 | return stats.str(); |
330 | 198 | } | |
331 | |||
332 | } // namespace spice::compiler | ||
333 |