GCC Code Coverage Report


Directory: ../
File: src/typechecker/TypeCheckerImplicit.cpp
Date: 2025-12-07 00:53:49
Coverage Exec Excl Total
Lines: 98.7% 233 0 236
Functions: 100.0% 15 0 15
Branches: 60.4% 324 0 536

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include "TypeChecker.h"
4
5 #include <SourceFile.h>
6 #include <ast/ASTBuilder.h>
7 #include <ast/ASTNodes.h>
8 #include <global/GlobalResourceManager.h>
9 #include <symboltablebuilder/SymbolTableBuilder.h>
10 #include <typechecker/TypeMatcher.h>
11
12 namespace spice::compiler {
13
14 static const char *const FCT_NAME_DEALLOC = "sDealloc";
15
16 /**
17 * Create a default struct method
18 * Checks if the given struct scope already has a user-defined constructor and creates a default one if not.
19 *
20 * @param spiceStruct Struct instance
21 * @param entryName Name of the symbol table entry
22 * @param name Name of the method to create
23 * @param params Parameter types of the method
24 */
25 372 void TypeChecker::createDefaultStructMethod(const Struct &spiceStruct, const std::string &entryName, const std::string &name,
26 const ParamList &params) const {
27 372 Scope *structScope = spiceStruct.scope;
28 372 ASTNode *node = spiceStruct.declNode;
29 372 const SymbolTableEntry *structEntry = spiceStruct.entry;
30
1/2
✓ Branch 2 → 3 taken 372 times.
✗ Branch 2 → 68 not taken.
372 const QualType &structType = structEntry->getQualType();
31
3/6
✓ Branch 3 → 4 taken 372 times.
✗ Branch 3 → 44 not taken.
✓ Branch 4 → 5 taken 372 times.
✗ Branch 4 → 44 not taken.
✓ Branch 5 → 6 taken 372 times.
✗ Branch 5 → 42 not taken.
372 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + name;
32
33 // Procedure type
34
1/2
✓ Branch 7 → 8 taken 372 times.
✗ Branch 7 → 66 not taken.
372 QualType procedureType(TY_PROCEDURE);
35
1/2
✓ Branch 8 → 9 taken 372 times.
✗ Branch 8 → 66 not taken.
372 procedureType.makePublic(); // Always public
36
37 // Insert symbol for function into the symbol table
38
1/2
✓ Branch 9 → 10 taken 372 times.
✗ Branch 9 → 66 not taken.
372 SymbolTableEntry *procEntry = structScope->insert(entryName, structEntry->declNode);
39
1/2
✓ Branch 12 → 13 taken 372 times.
✗ Branch 12 → 66 not taken.
372 procEntry->updateType(procedureType, true);
40
41 // Add to external name registry
42
1/2
✓ Branch 13 → 14 taken 372 times.
✗ Branch 13 → 66 not taken.
372 sourceFile->addNameRegistryEntry(fqFctName, TY_PROCEDURE, procEntry, structScope, true);
43
44 // Create the default method
45
1/2
✓ Branch 14 → 15 taken 372 times.
✗ Branch 14 → 66 not taken.
372 const std::vector<GenericType> templateTypes = spiceStruct.templateTypes;
46
1/2
✓ Branch 15 → 16 taken 372 times.
✗ Branch 15 → 64 not taken.
372 const QualType returnType(TY_DYN);
47
3/6
✓ Branch 16 → 17 taken 372 times.
✗ Branch 16 → 51 not taken.
✓ Branch 17 → 18 taken 372 times.
✗ Branch 17 → 48 not taken.
✓ Branch 18 → 19 taken 372 times.
✗ Branch 18 → 45 not taken.
372 Function defaultMethod(name, procEntry, structType, returnType, params, templateTypes, structEntry->declNode);
48 372 defaultMethod.implicitDefault = true;
49
50 // Create function scope
51
2/4
✓ Branch 23 → 24 taken 372 times.
✗ Branch 23 → 54 not taken.
✓ Branch 24 → 25 taken 372 times.
✗ Branch 24 → 52 not taken.
372 Scope *procScope = structScope->createChildScope(defaultMethod.getScopeName(), ScopeType::FUNC_PROC_BODY, &node->codeLoc);
52 372 defaultMethod.bodyScope = procScope;
53
54 // Create 'this' symbol in the function scope
55
1/2
✓ Branch 28 → 29 taken 372 times.
✗ Branch 28 → 57 not taken.
1116 SymbolTableEntry *thisEntry = procScope->insert(THIS_VARIABLE_NAME, node);
56
2/4
✓ Branch 34 → 35 taken 372 times.
✗ Branch 34 → 61 not taken.
✓ Branch 35 → 36 taken 372 times.
✗ Branch 35 → 61 not taken.
372 thisEntry->updateType(structType.toPtr(node), true);
57 372 thisEntry->used = true; // Always set to used to not print warnings for non-existing code
58
59 // Hand it off to the function manager to register the function
60
2/4
✓ Branch 36 → 37 taken 372 times.
✗ Branch 36 → 62 not taken.
✓ Branch 37 → 38 taken 372 times.
✗ Branch 37 → 62 not taken.
372 FunctionManager::insert(structScope, defaultMethod, structEntry->declNode->getFctManifestations(name));
61 372 }
62
63 /**
64 * Checks if the given struct scope already has a user-defined constructor and creates a default one if not.
65 *
66 * For generating a default ctor, the following conditions need to be met:
67 * - No user-defined constructors
68 *
69 * @param spiceStruct Struct instance
70 * @param structScope Scope of the struct
71 */
72 705 void TypeChecker::createDefaultCtorIfRequired(const Struct &spiceStruct, Scope *structScope) const {
73
1/2
✓ Branch 2 → 3 taken 705 times.
✗ Branch 2 → 4 not taken.
705 const auto node = spice_pointer_cast<StructDefNode *>(spiceStruct.declNode);
74
2/4
✓ Branch 9 → 10 taken 705 times.
✗ Branch 9 → 12 not taken.
✓ Branch 10 → 11 taken 705 times.
✗ Branch 10 → 12 not taken.
705 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
75
76 // Abort if the struct already has a user-defined constructor
77 705 const SymbolTableEntry *structEntry = spiceStruct.entry;
78
1/2
✓ Branch 13 → 14 taken 705 times.
✗ Branch 13 → 128 not taken.
705 const QualType &structType = structEntry->getQualType();
79
3/6
✓ Branch 14 → 15 taken 705 times.
✗ Branch 14 → 101 not taken.
✓ Branch 15 → 16 taken 705 times.
✗ Branch 15 → 101 not taken.
✓ Branch 16 → 17 taken 705 times.
✗ Branch 16 → 99 not taken.
705 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + CTOR_FUNCTION_NAME;
80
3/4
✓ Branch 18 → 19 taken 705 times.
✗ Branch 18 → 126 not taken.
✓ Branch 19 → 20 taken 547 times.
✓ Branch 19 → 21 taken 158 times.
705 if (sourceFile->getNameRegistryEntry(fqFctName))
81 547 return;
82
83 // Check if we have fields, that require us to do anything in the ctor
84
1/2
✓ Branch 21 → 22 taken 158 times.
✗ Branch 21 → 126 not taken.
158 const size_t fieldCount = structScope->getFieldCount();
85 158 bool hasFieldsWithDefaultValue = false;
86 158 bool hasFieldsToConstruct = false;
87
2/2
✓ Branch 77 → 23 taken 349 times.
✓ Branch 77 → 78 taken 152 times.
501 for (size_t i = 0; i < fieldCount; i++) {
88
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 349 times.
349 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
89
1/2
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 349 times.
349 assert(fieldSymbol != nullptr);
90
1/2
✓ Branch 30 → 31 taken 349 times.
✗ Branch 30 → 114 not taken.
349 const QualType &thisType = fieldSymbol->getQualType();
91
92 // Abort if we have a field, that is a reference
93
3/4
✓ Branch 31 → 32 taken 349 times.
✗ Branch 31 → 114 not taken.
✓ Branch 32 → 33 taken 5 times.
✓ Branch 32 → 34 taken 344 times.
349 if (thisType.isRef())
94 6 return;
95
96
3/4
✓ Branch 34 → 35 taken 344 times.
✗ Branch 34 → 36 not taken.
✓ Branch 37 → 38 taken 315 times.
✓ Branch 37 → 39 taken 29 times.
344 if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldSymbol->declNode)) {
97 315 hasFieldsWithDefaultValue |= fieldNode->defaultValue != nullptr;
98 } else {
99
2/4
✓ Branch 39 → 40 taken 29 times.
✗ Branch 39 → 41 not taken.
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 44 taken 29 times.
29 assert(dynamic_cast<DataTypeNode *>(fieldSymbol->declNode) != nullptr);
100 }
101
102
1/2
✓ Branch 44 → 45 taken 344 times.
✗ Branch 44 → 114 not taken.
344 const QualType fieldType = fieldSymbol->getQualType();
103
3/4
✓ Branch 45 → 46 taken 344 times.
✗ Branch 45 → 114 not taken.
✓ Branch 46 → 47 taken 26 times.
✓ Branch 46 → 75 taken 318 times.
344 if (fieldType.is(TY_STRUCT)) {
104
1/2
✓ Branch 47 → 48 taken 26 times.
✗ Branch 47 → 114 not taken.
26 Scope *bodyScope = fieldType.getBodyScope();
105
1/2
✓ Branch 48 → 49 taken 26 times.
✗ Branch 48 → 114 not taken.
26 const Struct *fieldStruct = fieldType.getStruct(node);
106 // Check if we are required to call a ctor
107
1/2
✓ Branch 49 → 50 taken 26 times.
✗ Branch 49 → 51 not taken.
26 const auto structDeclNode = spice_pointer_cast<StructDefNode *>(fieldStruct->declNode);
108
5/6
✓ Branch 56 → 57 taken 26 times.
✗ Branch 56 → 114 not taken.
✓ Branch 57 → 58 taken 25 times.
✓ Branch 57 → 59 taken 1 time.
✓ Branch 58 → 59 taken 7 times.
✓ Branch 58 → 60 taken 18 times.
26 const bool isCtorCallRequired = bodyScope->hasRefFields() || structDeclNode->emitVTable;
109 // Lookup ctor function
110
2/4
✓ Branch 65 → 66 taken 26 times.
✗ Branch 65 → 104 not taken.
✓ Branch 66 → 67 taken 26 times.
✗ Branch 66 → 102 not taken.
78 const Function *ctorFct = FunctionManager::match(bodyScope, CTOR_FUNCTION_NAME, thisType, {}, {}, true, node);
111 // If we are required to construct, but no constructor is found, we can't generate a default ctor for the outer struct
112
4/4
✓ Branch 71 → 72 taken 12 times.
✓ Branch 71 → 74 taken 14 times.
✓ Branch 72 → 73 taken 1 time.
✓ Branch 72 → 74 taken 11 times.
26 if (!ctorFct && isCtorCallRequired)
113 1 return;
114 25 hasFieldsToConstruct |= ctorFct != nullptr;
115 }
116 }
117
118 // If we don't have any fields, that require us to do anything in the ctor, we can skip it
119
6/6
✓ Branch 78 → 79 taken 110 times.
✓ Branch 78 → 82 taken 42 times.
✓ Branch 79 → 80 taken 96 times.
✓ Branch 79 → 82 taken 14 times.
✓ Branch 80 → 81 taken 91 times.
✓ Branch 80 → 82 taken 5 times.
152 if (!hasFieldsWithDefaultValue && !hasFieldsToConstruct && !node->emitVTable)
120 91 return;
121
122 // Create the default ctor function
123
1/2
✓ Branch 82 → 83 taken 61 times.
✗ Branch 82 → 126 not taken.
61 const std::string entryName = Function::getSymbolTableEntryNameDefaultCtor(node->codeLoc);
124
2/4
✓ Branch 86 → 87 taken 61 times.
✗ Branch 86 → 117 not taken.
✓ Branch 87 → 88 taken 61 times.
✗ Branch 87 → 115 not taken.
183 createDefaultStructMethod(spiceStruct, entryName, CTOR_FUNCTION_NAME, {});
125
2/2
✓ Branch 94 → 95 taken 61 times.
✓ Branch 94 → 97 taken 644 times.
705 }
126
127 /**
128 * Checks if the given struct scope already has a user-defined constructor and creates a default one if not.
129 *
130 * For generating a default copy ctor, the following conditions need to be met:
131 * - No user-defined copy ctor
132 * - No user-defined move ctor
133 *
134 * @param spiceStruct Struct instance
135 * @param structScope Scope of the struct
136 */
137 705 void TypeChecker::createDefaultCopyCtorIfRequired(const Struct &spiceStruct, Scope *structScope) const {
138
1/2
✓ Branch 2 → 3 taken 705 times.
✗ Branch 2 → 4 not taken.
705 const auto node = spice_pointer_cast<const StructDefNode *>(spiceStruct.declNode);
139
2/4
✓ Branch 9 → 10 taken 705 times.
✗ Branch 9 → 12 not taken.
✓ Branch 10 → 11 taken 705 times.
✗ Branch 10 → 12 not taken.
705 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
140
141 // Abort if the struct already has a user-defined copy constructor
142
1/2
✓ Branch 13 → 14 taken 705 times.
✗ Branch 13 → 153 not taken.
705 const QualType structType = spiceStruct.entry->getQualType();
143
2/4
✓ Branch 14 → 15 taken 705 times.
✗ Branch 14 → 111 not taken.
✓ Branch 18 → 19 taken 705 times.
✗ Branch 18 → 107 not taken.
2115 const ArgList lookupArgs = {{structType.toConstRef(node), true}};
144
2/4
✓ Branch 22 → 23 taken 705 times.
✗ Branch 22 → 115 not taken.
✓ Branch 23 → 24 taken 705 times.
✗ Branch 23 → 113 not taken.
705 const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, structType, lookupArgs, true);
145
2/2
✓ Branch 26 → 27 taken 134 times.
✓ Branch 26 → 28 taken 571 times.
705 if (copyCtor != nullptr)
146 134 return;
147
148 // Abort if the struct has a user-defined move constructor
149 // ToDo: Check for move ctor
150
151 // Check if we have fields, that require us to do anything in the ctor
152
1/2
✓ Branch 28 → 29 taken 571 times.
✗ Branch 28 → 151 not taken.
571 const size_t fieldCount = structScope->getFieldCount();
153 571 bool copyCtorRequired = false;
154
2/2
✓ Branch 82 → 30 taken 1223 times.
✓ Branch 82 → 83 taken 553 times.
1776 for (size_t i = 0; i < fieldCount; i++) {
155
1/2
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 1223 times.
1223 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
156
1/2
✓ Branch 35 → 36 taken 1223 times.
✗ Branch 35 → 151 not taken.
1223 const QualType &fieldType = fieldSymbol->getQualType();
157
158 // If the field is of type struct, check if this struct has a copy ctor that has to be called
159
3/4
✓ Branch 36 → 37 taken 1223 times.
✗ Branch 36 → 151 not taken.
✓ Branch 37 → 38 taken 167 times.
✓ Branch 37 → 75 taken 1056 times.
1223 if (fieldType.is(TY_STRUCT)) {
160
1/2
✓ Branch 38 → 39 taken 167 times.
✗ Branch 38 → 136 not taken.
167 Scope *bodyScope = fieldType.getBodyScope();
161
1/2
✓ Branch 39 → 40 taken 167 times.
✗ Branch 39 → 136 not taken.
167 const Struct *fieldStruct = fieldType.getStruct(node);
162 // Check if we are required to call a ctor
163
1/2
✓ Branch 40 → 41 taken 167 times.
✗ Branch 40 → 42 not taken.
167 const auto structDeclNode = spice_pointer_cast<StructDefNode *>(fieldStruct->declNode);
164
5/6
✓ Branch 47 → 48 taken 167 times.
✗ Branch 47 → 136 not taken.
✓ Branch 48 → 49 taken 157 times.
✓ Branch 48 → 50 taken 10 times.
✓ Branch 49 → 50 taken 37 times.
✓ Branch 49 → 51 taken 120 times.
167 const bool isCtorCallRequired = bodyScope->hasRefFields() || structDeclNode->emitVTable;
165 // Lookup copy ctor function
166
2/4
✓ Branch 52 → 53 taken 167 times.
✗ Branch 52 → 123 not taken.
✓ Branch 56 → 57 taken 167 times.
✗ Branch 56 → 119 not taken.
334 const ArgList args = {{fieldType.toConstRef(node), false /* we always have the field as storage */}};
167
2/4
✓ Branch 61 → 62 taken 167 times.
✗ Branch 61 → 127 not taken.
✓ Branch 62 → 63 taken 167 times.
✗ Branch 62 → 125 not taken.
501 const Function *ctorFct = FunctionManager::match(bodyScope, CTOR_FUNCTION_NAME, fieldType, args, {}, true, node);
168 // If we are required to construct, but no constructor is found, we can't generate a default ctor for the outer struct
169
4/4
✓ Branch 66 → 67 taken 98 times.
✓ Branch 66 → 69 taken 69 times.
✓ Branch 67 → 68 taken 18 times.
✓ Branch 67 → 69 taken 80 times.
167 if (!ctorFct && isCtorCallRequired)
170 18 return;
171 149 copyCtorRequired |= ctorFct != nullptr;
172
2/2
✓ Branch 71 → 72 taken 149 times.
✓ Branch 71 → 74 taken 18 times.
167 }
173
174 // If we have an owning heap pointer, we need to do a memcpy of the heap storage and therefore need a default copy ctor
175
3/4
✓ Branch 75 → 76 taken 1205 times.
✗ Branch 75 → 151 not taken.
✓ Branch 76 → 77 taken 32 times.
✓ Branch 76 → 81 taken 1173 times.
1205 if (fieldType.isHeap()) {
176
2/4
✓ Branch 77 → 78 taken 32 times.
✗ Branch 77 → 151 not taken.
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 32 times.
32 assert(fieldType.isPtr());
177 32 copyCtorRequired = true;
178 }
179 }
180
181 // If we don't have any fields, that require us to do anything in the copy ctor, we can skip it
182
4/4
✓ Branch 83 → 84 taken 481 times.
✓ Branch 83 → 86 taken 72 times.
✓ Branch 84 → 85 taken 349 times.
✓ Branch 84 → 86 taken 132 times.
553 if (!copyCtorRequired && !node->emitVTable)
183 349 return;
184
185 // Create the default copy ctor function
186
1/2
✓ Branch 86 → 87 taken 204 times.
✗ Branch 86 → 151 not taken.
204 const std::string entryName = Function::getSymbolTableEntryNameDefaultCopyCtor(node->codeLoc);
187
2/4
✓ Branch 87 → 88 taken 204 times.
✗ Branch 87 → 140 not taken.
✓ Branch 90 → 91 taken 204 times.
✗ Branch 90 → 137 not taken.
612 const ParamList paramTypes = {{structType.toConstRef(node), false}};
188
2/4
✓ Branch 94 → 95 taken 204 times.
✗ Branch 94 → 143 not taken.
✓ Branch 95 → 96 taken 204 times.
✗ Branch 95 → 141 not taken.
204 createDefaultStructMethod(spiceStruct, entryName, CTOR_FUNCTION_NAME, paramTypes);
189
2/2
✓ Branch 102 → 103 taken 204 times.
✓ Branch 102 → 105 taken 501 times.
705 }
190
191 /**
192 * Checks if the given struct scope already has a user-defined destructor and creates a default one if not.
193 *
194 * For generating a default dtor, the following conditions need to be met:
195 * - No user-defined dtor
196 *
197 * @param spiceStruct Struct instance
198 * @param structScope Scope of the struct
199 */
200 705 void TypeChecker::createDefaultDtorIfRequired(const Struct &spiceStruct, Scope *structScope) const {
201 705 const ASTNode *node = spiceStruct.declNode;
202
2/4
✓ Branch 2 → 3 taken 705 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 705 times.
✗ Branch 3 → 5 not taken.
705 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
203
204 // Abort if the struct already has a user-defined destructor
205 705 const SymbolTableEntry *structEntry = spiceStruct.entry;
206
1/2
✓ Branch 6 → 7 taken 705 times.
✗ Branch 6 → 143 not taken.
705 const QualType &structType = structEntry->getQualType();
207
3/6
✓ Branch 7 → 8 taken 705 times.
✗ Branch 7 → 98 not taken.
✓ Branch 8 → 9 taken 705 times.
✗ Branch 8 → 98 not taken.
✓ Branch 9 → 10 taken 705 times.
✗ Branch 9 → 96 not taken.
705 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + DTOR_FUNCTION_NAME;
208
3/4
✓ Branch 11 → 12 taken 705 times.
✗ Branch 11 → 141 not taken.
✓ Branch 12 → 13 taken 116 times.
✓ Branch 12 → 14 taken 589 times.
705 if (sourceFile->getNameRegistryEntry(fqFctName))
209 116 return;
210
211 // Check we have field types, that require use to do anything in the destructor
212
1/2
✓ Branch 14 → 15 taken 589 times.
✗ Branch 14 → 141 not taken.
589 const size_t fieldCount = structScope->getFieldCount();
213 589 bool hasFieldsToDeAllocate = false;
214 589 bool hasFieldsToDestruct = false;
215
2/2
✓ Branch 41 → 16 taken 1349 times.
✓ Branch 41 → 42 taken 589 times.
1938 for (size_t i = 0; i < fieldCount; i++) {
216
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1349 times.
1349 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
217
2/4
✓ Branch 21 → 22 taken 1349 times.
✗ Branch 21 → 141 not taken.
✓ Branch 22 → 23 taken 1349 times.
✗ Branch 22 → 141 not taken.
1349 hasFieldsToDeAllocate |= fieldSymbol->getQualType().needsDeAllocation();
218
4/6
✓ Branch 23 → 24 taken 1349 times.
✗ Branch 23 → 141 not taken.
✓ Branch 24 → 25 taken 1349 times.
✗ Branch 24 → 141 not taken.
✓ Branch 25 → 26 taken 166 times.
✓ Branch 25 → 40 taken 1183 times.
1349 if (fieldSymbol->getQualType().is(TY_STRUCT)) {
219
2/4
✓ Branch 26 → 27 taken 166 times.
✗ Branch 26 → 141 not taken.
✓ Branch 27 → 28 taken 166 times.
✗ Branch 27 → 141 not taken.
166 Scope *fieldScope = fieldSymbol->getQualType().getBodyScope();
220 // Lookup dtor function
221
1/2
✓ Branch 28 → 29 taken 166 times.
✗ Branch 28 → 141 not taken.
166 const QualType &thisType = fieldSymbol->getQualType();
222
2/4
✓ Branch 33 → 34 taken 166 times.
✗ Branch 33 → 101 not taken.
✓ Branch 34 → 35 taken 166 times.
✗ Branch 34 → 99 not taken.
498 const Function *dtorFct = FunctionManager::match(fieldScope, DTOR_FUNCTION_NAME, thisType, {}, {}, true, node);
223 166 hasFieldsToDestruct |= dtorFct != nullptr;
224
1/2
✓ Branch 39 → 40 taken 166 times.
✗ Branch 39 → 141 not taken.
166 requestRevisitIfRequired(dtorFct);
225 }
226 }
227
228 // If we don't have any fields, that require us to do anything in the dtor, we can skip it
229
4/4
✓ Branch 42 → 43 taken 526 times.
✓ Branch 42 → 45 taken 63 times.
✓ Branch 43 → 44 taken 482 times.
✓ Branch 43 → 45 taken 44 times.
589 if (!hasFieldsToDeAllocate && !hasFieldsToDestruct)
230 482 return;
231
232 // Create the default dtor function
233
1/2
✓ Branch 45 → 46 taken 107 times.
✗ Branch 45 → 141 not taken.
107 const std::string entryName = Function::getSymbolTableEntryNameDefaultDtor(node->codeLoc);
234
2/4
✓ Branch 49 → 50 taken 107 times.
✗ Branch 49 → 113 not taken.
✓ Branch 50 → 51 taken 107 times.
✗ Branch 50 → 111 not taken.
321 createDefaultStructMethod(spiceStruct, entryName, DTOR_FUNCTION_NAME, {});
235
236 // Request memory runtime if we have fields, that are allocated on the heap
237 // The string runtime does not use it, but allocates manually to avoid circular dependencies
238
6/8
✓ Branch 54 → 55 taken 63 times.
✓ Branch 54 → 60 taken 44 times.
✓ Branch 55 → 56 taken 63 times.
✗ Branch 55 → 139 not taken.
✓ Branch 58 → 59 taken 63 times.
✗ Branch 58 → 60 not taken.
✓ Branch 61 → 62 taken 63 times.
✓ Branch 61 → 88 taken 44 times.
170 if (hasFieldsToDeAllocate && !sourceFile->isStringRT()) {
239
1/2
✓ Branch 62 → 63 taken 63 times.
✗ Branch 62 → 138 not taken.
63 const SourceFile *memoryRT = sourceFile->requestRuntimeModule(MEMORY_RT);
240
1/2
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 65 taken 63 times.
63 assert(memoryRT != nullptr);
241 63 Scope *matchScope = memoryRT->globalScope.get();
242 // Set dealloc function to used
243
1/2
✓ Branch 66 → 67 taken 63 times.
✗ Branch 66 → 138 not taken.
63 const QualType thisType(TY_DYN);
244
3/6
✓ Branch 67 → 68 taken 63 times.
✗ Branch 67 → 120 not taken.
✓ Branch 68 → 69 taken 63 times.
✗ Branch 68 → 120 not taken.
✓ Branch 69 → 70 taken 63 times.
✗ Branch 69 → 120 not taken.
63 QualType bytePtrRefType = QualType(TY_BYTE).toPtr(node).toRef(node);
245
1/2
✓ Branch 70 → 71 taken 63 times.
✗ Branch 70 → 138 not taken.
63 bytePtrRefType.makeHeap();
246
1/2
✓ Branch 74 → 75 taken 63 times.
✗ Branch 74 → 122 not taken.
126 const ArgList args = {{bytePtrRefType, false /* we always have the field as storage */}};
247
2/4
✓ Branch 79 → 80 taken 63 times.
✗ Branch 79 → 129 not taken.
✓ Branch 80 → 81 taken 63 times.
✗ Branch 80 → 127 not taken.
189 Function *deallocFct = FunctionManager::match(matchScope, FCT_NAME_DEALLOC, thisType, args, {}, true, node);
248
1/2
✗ Branch 84 → 85 not taken.
✓ Branch 84 → 86 taken 63 times.
63 assert(deallocFct != nullptr);
249 63 deallocFct->used = true;
250 63 }
251
2/2
✓ Branch 91 → 92 taken 107 times.
✓ Branch 91 → 94 taken 598 times.
705 }
252
253 /**
254 * Prepare the generation of the ctor body preamble. This preamble is used to initialize the VTable, construct or initialize
255 * fields.
256 */
257 1444 void TypeChecker::createCtorBodyPreamble(const Scope *bodyScope) const {
258 // Retrieve struct scope
259 1444 Scope *structScope = bodyScope->parent;
260
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1444 times.
1444 assert(structScope != nullptr);
261
262 1444 const size_t fieldCount = structScope->getFieldCount();
263
2/2
✓ Branch 49 → 6 taken 3642 times.
✓ Branch 49 → 50 taken 1444 times.
5086 for (size_t i = 0; i < fieldCount; i++) {
264
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 3642 times.
3642 SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
265
3/6
✓ Branch 11 → 12 taken 3642 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 3642 times.
✗ Branch 12 → 64 not taken.
✓ Branch 13 → 14 taken 3642 times.
✗ Branch 13 → 15 not taken.
3642 assert(fieldSymbol != nullptr && fieldSymbol->isField());
266
2/2
✓ Branch 16 → 17 taken 243 times.
✓ Branch 16 → 18 taken 3399 times.
3642 if (fieldSymbol->isImplicitField)
267 243 continue;
268
1/2
✓ Branch 18 → 19 taken 3399 times.
✗ Branch 18 → 64 not taken.
3399 QualType fieldType = fieldSymbol->getQualType();
269
3/4
✓ Branch 19 → 20 taken 3399 times.
✗ Branch 19 → 64 not taken.
✓ Branch 20 → 21 taken 526 times.
✓ Branch 20 → 22 taken 2873 times.
3399 if (fieldType.hasAnyGenericParts())
270
1/2
✓ Branch 21 → 22 taken 526 times.
✗ Branch 21 → 64 not taken.
526 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
271
272
3/4
✓ Branch 22 → 23 taken 3399 times.
✗ Branch 22 → 64 not taken.
✓ Branch 23 → 24 taken 447 times.
✓ Branch 23 → 47 taken 2952 times.
3399 if (fieldType.is(TY_STRUCT)) {
273
1/2
✓ Branch 24 → 25 taken 447 times.
✗ Branch 24 → 26 not taken.
447 const auto fieldNode = spice_pointer_cast<const FieldNode *>(fieldSymbol->declNode);
274 // Match ctor function, create the concrete manifestation and set it to used
275
1/2
✓ Branch 31 → 32 taken 447 times.
✗ Branch 31 → 64 not taken.
447 Scope *matchScope = fieldType.getBodyScope();
276
2/4
✓ Branch 36 → 37 taken 447 times.
✗ Branch 36 → 53 not taken.
✓ Branch 37 → 38 taken 447 times.
✗ Branch 37 → 51 not taken.
1341 const Function *spiceFunc = FunctionManager::match(matchScope, CTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
277
2/2
✓ Branch 42 → 43 taken 396 times.
✓ Branch 42 → 47 taken 51 times.
447 if (spiceFunc != nullptr)
278
3/6
✓ Branch 43 → 44 taken 396 times.
✗ Branch 43 → 63 not taken.
✓ Branch 44 → 45 taken 396 times.
✗ Branch 44 → 63 not taken.
✓ Branch 45 → 46 taken 396 times.
✗ Branch 45 → 63 not taken.
396 fieldSymbol->updateType(fieldType.getWithBodyScope(spiceFunc->thisType.getBodyScope()), true);
279 }
280 }
281 1444 }
282
283 /**
284 * Prepare the generation of the copy ctor body preamble. This preamble is used to initialize the VTable, construct or initialize
285 * fields.
286 */
287 143 void TypeChecker::createCopyCtorBodyPreamble(const Scope *bodyScope) const {
288 // Retrieve struct scope
289 143 Scope *structScope = bodyScope->parent;
290
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 143 times.
143 assert(structScope != nullptr);
291
292 143 const size_t fieldCount = structScope->getFieldCount();
293
2/2
✓ Branch 55 → 6 taken 298 times.
✓ Branch 55 → 56 taken 143 times.
441 for (size_t i = 0; i < fieldCount; i++) {
294
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 298 times.
298 SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
295
3/6
✓ Branch 11 → 12 taken 298 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 298 times.
✗ Branch 12 → 76 not taken.
✓ Branch 13 → 14 taken 298 times.
✗ Branch 13 → 15 not taken.
298 assert(fieldSymbol != nullptr && fieldSymbol->isField());
296
2/2
✓ Branch 16 → 17 taken 33 times.
✓ Branch 16 → 18 taken 265 times.
298 if (fieldSymbol->isImplicitField)
297 33 continue;
298
299
1/2
✓ Branch 18 → 19 taken 265 times.
✗ Branch 18 → 76 not taken.
265 QualType fieldType = fieldSymbol->getQualType();
300
2/4
✓ Branch 19 → 20 taken 265 times.
✗ Branch 19 → 76 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 265 times.
265 if (fieldType.hasAnyGenericParts())
301 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
302
303
3/4
✓ Branch 22 → 23 taken 265 times.
✗ Branch 22 → 76 not taken.
✓ Branch 23 → 24 taken 117 times.
✓ Branch 23 → 53 taken 148 times.
265 if (fieldType.is(TY_STRUCT)) {
304
1/2
✓ Branch 24 → 25 taken 117 times.
✗ Branch 24 → 26 not taken.
117 const auto fieldNode = spice_pointer_cast<const FieldNode *>(fieldSymbol->declNode);
305 // Match ctor function, create the concrete manifestation and set it to used
306
1/2
✓ Branch 31 → 32 taken 117 times.
✗ Branch 31 → 75 not taken.
117 Scope *matchScope = fieldType.getBodyScope();
307
2/4
✓ Branch 32 → 33 taken 117 times.
✗ Branch 32 → 61 not taken.
✓ Branch 36 → 37 taken 117 times.
✗ Branch 36 → 57 not taken.
234 const ArgList args = {{fieldType.toConstRef(fieldNode), false /* we always have the field as storage */}};
308
2/4
✓ Branch 41 → 42 taken 117 times.
✗ Branch 41 → 65 not taken.
✓ Branch 42 → 43 taken 117 times.
✗ Branch 42 → 63 not taken.
351 const Function *copyCtorFct = FunctionManager::match(matchScope, CTOR_FUNCTION_NAME, fieldType, args, {}, false, fieldNode);
309
2/2
✓ Branch 46 → 47 taken 106 times.
✓ Branch 46 → 51 taken 11 times.
117 if (copyCtorFct != nullptr)
310
3/6
✓ Branch 47 → 48 taken 106 times.
✗ Branch 47 → 72 not taken.
✓ Branch 48 → 49 taken 106 times.
✗ Branch 48 → 72 not taken.
✓ Branch 49 → 50 taken 106 times.
✗ Branch 49 → 72 not taken.
106 fieldSymbol->updateType(fieldType.getWithBodyScope(copyCtorFct->thisType.getBodyScope()), true);
311 117 }
312 }
313 143 }
314
315 /**
316 * Prepare the generation of the dtor body preamble. This preamble is used to destruct all fields and to free all heap fields.
317 */
318 231 void TypeChecker::createDtorBodyPreamble(const Scope *bodyScope) const {
319 // Retrieve struct scope
320 231 Scope *structScope = bodyScope->parent;
321
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 231 times.
231 assert(structScope != nullptr);
322
323 231 const size_t fieldCount = structScope->getFieldCount();
324
2/2
✓ Branch 45 → 6 taken 813 times.
✓ Branch 45 → 46 taken 231 times.
1044 for (size_t i = 0; i < fieldCount; i++) {
325
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 813 times.
813 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
326
3/6
✓ Branch 11 → 12 taken 813 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 813 times.
✗ Branch 12 → 59 not taken.
✓ Branch 13 → 14 taken 813 times.
✗ Branch 13 → 15 not taken.
813 assert(fieldSymbol != nullptr && fieldSymbol->isField());
327
2/2
✓ Branch 16 → 17 taken 150 times.
✓ Branch 16 → 18 taken 663 times.
813 if (fieldSymbol->isImplicitField)
328 150 continue;
329
1/2
✓ Branch 18 → 19 taken 663 times.
✗ Branch 18 → 59 not taken.
663 QualType fieldType = fieldSymbol->getQualType();
330
2/4
✓ Branch 19 → 20 taken 663 times.
✗ Branch 19 → 59 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 663 times.
663 if (fieldType.hasAnyGenericParts())
331 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
332
333
3/4
✓ Branch 22 → 23 taken 663 times.
✗ Branch 22 → 59 not taken.
✓ Branch 23 → 24 taken 159 times.
✓ Branch 23 → 43 taken 504 times.
663 if (fieldType.is(TY_STRUCT)) {
334
1/2
✓ Branch 24 → 25 taken 159 times.
✗ Branch 24 → 26 not taken.
159 const auto fieldNode = spice_pointer_cast<const FieldNode *>(fieldSymbol->declNode);
335 // Match ctor function, create the concrete manifestation and set it to used
336
1/2
✓ Branch 31 → 32 taken 159 times.
✗ Branch 31 → 59 not taken.
159 Scope *matchScope = fieldType.getBodyScope();
337
2/4
✓ Branch 36 → 37 taken 159 times.
✗ Branch 36 → 49 not taken.
✓ Branch 37 → 38 taken 159 times.
✗ Branch 37 → 47 not taken.
477 FunctionManager::match(matchScope, DTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
338 }
339 }
340 231 }
341
342 /**
343 * Prepare the generation of a call to a method of a given struct
344 *
345 * @param entry Symbol entry to use as 'this' pointer for the method call
346 * @param methodName Name of the method to call
347 * @param args Provided arguments by the caller
348 * @param node AST node
349 */
350 1436 Function *TypeChecker::implicitlyCallStructMethod(const SymbolTableEntry *entry, const std::string &methodName,
351 const ArgList &args, const ASTNode *node) {
352
3/6
✓ Branch 2 → 3 taken 1436 times.
✗ Branch 2 → 9 not taken.
✓ Branch 3 → 4 taken 1436 times.
✗ Branch 3 → 9 not taken.
✓ Branch 4 → 5 taken 1436 times.
✗ Branch 4 → 9 not taken.
1436 const QualType thisType = entry->getQualType().removeReferenceWrapper().toNonConst();
353
1/2
✓ Branch 5 → 6 taken 1436 times.
✗ Branch 5 → 10 not taken.
2872 return implicitlyCallStructMethod(thisType, methodName, args, node);
354 }
355
356 /**
357 * Prepare the generation of a call to a method of a given struct
358 *
359 * @param thisType Struct type to call the method on
360 * @param methodName Name of the method to call
361 * @param args Provided arguments by the caller
362 * @param node AST node
363 */
364 1692 Function *TypeChecker::implicitlyCallStructMethod(QualType thisType, const std::string &methodName, const ArgList &args,
365 const ASTNode *node) const {
366
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1692 times.
1692 assert(thisType.is(TY_STRUCT));
367 1692 Scope *matchScope = thisType.getBodyScope();
368
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 1692 times.
1692 assert(matchScope->type == ScopeType::STRUCT);
369
370 // Search for dtor
371
2/2
✓ Branch 9 → 10 taken 914 times.
✓ Branch 9 → 12 taken 778 times.
1692 if (matchScope->isImportedBy(rootScope))
372
1/2
✓ Branch 10 → 11 taken 914 times.
✗ Branch 10 → 18 not taken.
914 thisType = mapLocalTypeToImportedScopeType(matchScope, thisType);
373
1/2
✓ Branch 13 → 14 taken 1692 times.
✗ Branch 13 → 19 not taken.
1692 return FunctionManager::match(matchScope, methodName, thisType, args, {}, true, node);
374 }
375
376 /**
377 * Prepare the generation of a call to the copy ctor of a given struct
378 *
379 * @param entry Symbol entry to use as 'this' pointer for the copy ctor call
380 * @param node Current AST node
381 */
382 5 Function *TypeChecker::implicitlyCallStructCopyCtor(const SymbolTableEntry *entry, const ASTNode *node) const {
383
2/4
✓ Branch 2 → 3 taken 5 times.
✗ Branch 2 → 7 not taken.
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 7 not taken.
5 assert(entry != nullptr && entry->getQualType().is(TY_STRUCT));
384 5 return implicitlyCallStructCopyCtor(entry->getQualType(), node);
385 }
386
387 /**
388 * Prepare the generation of a call to the copy ctor of a given struct
389 *
390 * @param thisType Struct type to call the copy ctor on
391 * @param node Current AST node
392 */
393 256 Function *TypeChecker::implicitlyCallStructCopyCtor(const QualType &thisType, const ASTNode *node) const {
394
2/4
✓ Branch 2 → 3 taken 256 times.
✗ Branch 2 → 19 not taken.
✓ Branch 3 → 4 taken 256 times.
✗ Branch 3 → 19 not taken.
256 const QualType argType = thisType.removeReferenceWrapper().toConstRef(node);
395
1/2
✓ Branch 7 → 8 taken 256 times.
✗ Branch 7 → 20 not taken.
768 const ArgList args = {{argType, false /* we always have an entry here */}};
396
2/4
✓ Branch 11 → 12 taken 256 times.
✗ Branch 11 → 27 not taken.
✓ Branch 12 → 13 taken 256 times.
✗ Branch 12 → 25 not taken.
512 return implicitlyCallStructMethod(thisType, CTOR_FUNCTION_NAME, args, node);
397 256 }
398
399 /**
400 * Prepare the generation of a call to the dtor of a given struct
401 *
402 * @param entry Symbol entry to use as 'this' pointer for the dtor call
403 * @param node StmtLstNode for the current scope
404 */
405 1436 void TypeChecker::implicitlyCallStructDtor(SymbolTableEntry *entry, StmtLstNode *node) {
406 // Add the dtor to the stmt list node to call it later in codegen
407
4/6
✓ Branch 5 → 6 taken 1436 times.
✗ Branch 5 → 16 not taken.
✓ Branch 6 → 7 taken 1436 times.
✗ Branch 6 → 14 not taken.
✓ Branch 10 → 11 taken 1059 times.
✓ Branch 10 → 13 taken 377 times.
4308 if (Function *dtor = implicitlyCallStructMethod(entry, DTOR_FUNCTION_NAME, {}, node))
408
2/4
✓ Branch 11 → 12 taken 1059 times.
✗ Branch 11 → 23 not taken.
✓ Branch 12 → 13 taken 1059 times.
✗ Branch 12 → 23 not taken.
1059 node->resourcesToCleanup.at(manIdx).dtorFunctionsToCall.emplace_back(entry, dtor);
409 1436 }
410
411 /**
412 * Prepare the generation of a call to the deallocate function for a heap-allocated variable
413 *
414 * @param node Current AST node for error messages
415 */
416 4 void TypeChecker::implicitlyCallDeallocate(const ASTNode *node) const {
417
1/2
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 46 not taken.
4 const SourceFile *memoryRT = sourceFile->requestRuntimeModule(MEMORY_RT);
418
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
4 assert(memoryRT != nullptr);
419 4 Scope *matchScope = memoryRT->globalScope.get();
420 // Set dealloc function to used
421
1/2
✓ Branch 6 → 7 taken 4 times.
✗ Branch 6 → 46 not taken.
4 const QualType thisType(TY_DYN);
422
3/6
✓ Branch 7 → 8 taken 4 times.
✗ Branch 7 → 28 not taken.
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 28 not taken.
✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 28 not taken.
4 QualType bytePtrRefType = QualType(TY_BYTE).toPtr(node).toRef(node);
423
1/2
✓ Branch 10 → 11 taken 4 times.
✗ Branch 10 → 46 not taken.
4 bytePtrRefType.makeHeap();
424
1/2
✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 30 not taken.
8 const ArgList args = {{bytePtrRefType, false /* we always have the field as storage */}};
425
2/4
✓ Branch 19 → 20 taken 4 times.
✗ Branch 19 → 37 not taken.
✓ Branch 20 → 21 taken 4 times.
✗ Branch 20 → 35 not taken.
12 Function *deallocFct = FunctionManager::match(matchScope, FCT_NAME_DEALLOC, thisType, args, {}, true, node);
426
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 4 times.
4 assert(deallocFct != nullptr);
427 4 deallocFct->used = true;
428 4 }
429
430 /**
431 * Consider calls to destructors for the given scope
432 *
433 * @param node StmtLstNode for the current scope
434 */
435 21261 void TypeChecker::doScopeCleanup(StmtLstNode *node) {
436 // Get all variables, that are approved for de-allocation
437
1/2
✓ Branch 2 → 3 taken 21261 times.
✗ Branch 2 → 61 not taken.
21261 std::vector<SymbolTableEntry *> vars = currentScope->getVarsGoingOutOfScope();
438 // Sort by reverse declaration order
439
2/2
✓ Branch 2 → 3 taken 142 times.
✓ Branch 2 → 4 taken 6381 times.
13046 auto comp = [](const SymbolTableEntry *a, const SymbolTableEntry *b) { return a->declNode->codeLoc > b->declNode->codeLoc; };
440
1/2
✓ Branch 3 → 4 taken 21261 times.
✗ Branch 3 → 59 not taken.
21261 std::ranges::sort(vars, comp);
441 // Call the dtor of each variable. We call the dtor in reverse declaration order
442
2/2
✓ Branch 54 → 6 taken 8721 times.
✓ Branch 54 → 55 taken 21261 times.
29982 for (SymbolTableEntry *var : vars) {
443 // Check if we have a heap-allocated pointer
444
10/14
✓ Branch 7 → 8 taken 8721 times.
✗ Branch 7 → 57 not taken.
✓ Branch 8 → 9 taken 8721 times.
✗ Branch 8 → 57 not taken.
✓ Branch 9 → 10 taken 1170 times.
✓ Branch 9 → 14 taken 7551 times.
✓ Branch 10 → 11 taken 1170 times.
✗ Branch 10 → 57 not taken.
✓ Branch 11 → 12 taken 1170 times.
✗ Branch 11 → 57 not taken.
✓ Branch 12 → 13 taken 1137 times.
✓ Branch 12 → 14 taken 33 times.
✓ Branch 15 → 16 taken 1137 times.
✓ Branch 15 → 35 taken 7584 times.
8721 if (var->getQualType().isHeap() && var->getQualType().isOneOf({TY_PTR, TY_STRING, TY_FUNCTION, TY_PROCEDURE})) {
445 // The memory runtime is ignored, because it manually allocates to avoid circular dependencies.
446 // Same goes for the string runtime.
447
8/10
✓ Branch 16 → 17 taken 1137 times.
✗ Branch 16 → 58 not taken.
✓ Branch 19 → 20 taken 973 times.
✓ Branch 19 → 24 taken 164 times.
✓ Branch 20 → 21 taken 973 times.
✗ Branch 20 → 58 not taken.
✓ Branch 23 → 24 taken 930 times.
✓ Branch 23 → 25 taken 43 times.
✓ Branch 26 → 27 taken 1094 times.
✓ Branch 26 → 28 taken 43 times.
3247 if (sourceFile->isMemoryRT() || sourceFile->isStringRT())
448 1094 continue;
449 // If the local variable currently does not have the ownership, we must not deallocate its memory
450
3/4
✓ Branch 29 → 30 taken 43 times.
✗ Branch 29 → 58 not taken.
✓ Branch 30 → 31 taken 39 times.
✓ Branch 30 → 32 taken 4 times.
43 if (!var->getLifecycle().isInOwningState())
451 39 continue;
452
453
1/2
✓ Branch 32 → 33 taken 4 times.
✗ Branch 32 → 58 not taken.
4 implicitlyCallDeallocate(node); // Required to request the memory runtime
454
2/4
✓ Branch 33 → 34 taken 4 times.
✗ Branch 33 → 58 not taken.
✓ Branch 34 → 35 taken 4 times.
✗ Branch 34 → 58 not taken.
4 node->resourcesToCleanup.at(manIdx).heapVarsToFree.push_back(var);
455 }
456 // Only generate dtor call for structs and if not omitted
457
8/10
✓ Branch 35 → 36 taken 7588 times.
✗ Branch 35 → 58 not taken.
✓ Branch 36 → 37 taken 7588 times.
✗ Branch 36 → 58 not taken.
✓ Branch 37 → 38 taken 1546 times.
✓ Branch 37 → 39 taken 6042 times.
✓ Branch 38 → 39 taken 110 times.
✓ Branch 38 → 40 taken 1436 times.
✓ Branch 41 → 42 taken 6152 times.
✓ Branch 41 → 43 taken 1436 times.
7588 if (!var->getQualType().is(TY_STRUCT) || var->omitDtorCall)
458 6152 continue;
459 // Variable must be either initialized or a struct field
460
3/8
✓ Branch 44 → 45 taken 1436 times.
✗ Branch 44 → 58 not taken.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 48 taken 1436 times.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 1436 times.
1436 if (!var->getLifecycle().isInitialized() && var->scope->type != ScopeType::STRUCT)
461 continue;
462 // Call dtor
463
1/2
✓ Branch 51 → 52 taken 1436 times.
✗ Branch 51 → 58 not taken.
1436 implicitlyCallStructDtor(var, node);
464 }
465 21261 }
466
467 } // namespace spice::compiler
468