GCC Code Coverage Report


Directory: ../
File: src/typechecker/TypeCheckerImplicit.cpp
Date: 2025-10-21 13:42:48
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 358 void TypeChecker::createDefaultStructMethod(const Struct &spiceStruct, const std::string &entryName, const std::string &name,
26 const ParamList &params) const {
27 358 Scope *structScope = spiceStruct.scope;
28 358 ASTNode *node = spiceStruct.declNode;
29 358 const SymbolTableEntry *structEntry = spiceStruct.entry;
30
1/2
✓ Branch 2 → 3 taken 358 times.
✗ Branch 2 → 68 not taken.
358 const QualType &structType = structEntry->getQualType();
31
3/6
✓ Branch 3 → 4 taken 358 times.
✗ Branch 3 → 44 not taken.
✓ Branch 4 → 5 taken 358 times.
✗ Branch 4 → 44 not taken.
✓ Branch 5 → 6 taken 358 times.
✗ Branch 5 → 42 not taken.
358 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + name;
32
33 // Procedure type
34
1/2
✓ Branch 7 → 8 taken 358 times.
✗ Branch 7 → 66 not taken.
358 QualType procedureType(TY_PROCEDURE);
35
1/2
✓ Branch 8 → 9 taken 358 times.
✗ Branch 8 → 66 not taken.
358 procedureType.makePublic(); // Always public
36
37 // Insert symbol for function into the symbol table
38
1/2
✓ Branch 9 → 10 taken 358 times.
✗ Branch 9 → 66 not taken.
358 SymbolTableEntry *procEntry = structScope->insert(entryName, structEntry->declNode);
39
1/2
✓ Branch 12 → 13 taken 358 times.
✗ Branch 12 → 66 not taken.
358 procEntry->updateType(procedureType, true);
40
41 // Add to external name registry
42
1/2
✓ Branch 13 → 14 taken 358 times.
✗ Branch 13 → 66 not taken.
358 sourceFile->addNameRegistryEntry(fqFctName, TY_PROCEDURE, procEntry, structScope, true);
43
44 // Create the default method
45
1/2
✓ Branch 14 → 15 taken 358 times.
✗ Branch 14 → 66 not taken.
358 const std::vector<GenericType> templateTypes = spiceStruct.templateTypes;
46
1/2
✓ Branch 15 → 16 taken 358 times.
✗ Branch 15 → 64 not taken.
358 const QualType returnType(TY_DYN);
47
3/6
✓ Branch 16 → 17 taken 358 times.
✗ Branch 16 → 51 not taken.
✓ Branch 17 → 18 taken 358 times.
✗ Branch 17 → 48 not taken.
✓ Branch 18 → 19 taken 358 times.
✗ Branch 18 → 45 not taken.
358 Function defaultMethod(name, procEntry, structType, returnType, params, templateTypes, structEntry->declNode);
48 358 defaultMethod.implicitDefault = true;
49
50 // Create function scope
51
2/4
✓ Branch 23 → 24 taken 358 times.
✗ Branch 23 → 54 not taken.
✓ Branch 24 → 25 taken 358 times.
✗ Branch 24 → 52 not taken.
358 Scope *procScope = structScope->createChildScope(defaultMethod.getSignature(false), ScopeType::FUNC_PROC_BODY, &node->codeLoc);
52 358 defaultMethod.bodyScope = procScope;
53
54 // Create 'this' symbol in the function scope
55
1/2
✓ Branch 28 → 29 taken 358 times.
✗ Branch 28 → 57 not taken.
1074 SymbolTableEntry *thisEntry = procScope->insert(THIS_VARIABLE_NAME, node);
56
2/4
✓ Branch 34 → 35 taken 358 times.
✗ Branch 34 → 61 not taken.
✓ Branch 35 → 36 taken 358 times.
✗ Branch 35 → 61 not taken.
358 thisEntry->updateType(structType.toPtr(node), true);
57 358 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 358 times.
✗ Branch 36 → 62 not taken.
✓ Branch 37 → 38 taken 358 times.
✗ Branch 37 → 62 not taken.
358 FunctionManager::insert(structScope, defaultMethod, structEntry->declNode->getFctManifestations(name));
61 358 }
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 663 void TypeChecker::createDefaultCtorIfRequired(const Struct &spiceStruct, Scope *structScope) {
73
1/2
✓ Branch 2 → 3 taken 663 times.
✗ Branch 2 → 4 not taken.
663 const auto node = spice_pointer_cast<StructDefNode *>(spiceStruct.declNode);
74
2/4
✓ Branch 9 → 10 taken 663 times.
✗ Branch 9 → 12 not taken.
✓ Branch 10 → 11 taken 663 times.
✗ Branch 10 → 12 not taken.
663 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
75
76 // Abort if the struct already has a user-defined constructor
77 663 const SymbolTableEntry *structEntry = spiceStruct.entry;
78
1/2
✓ Branch 13 → 14 taken 663 times.
✗ Branch 13 → 128 not taken.
663 const QualType &structType = structEntry->getQualType();
79
3/6
✓ Branch 14 → 15 taken 663 times.
✗ Branch 14 → 101 not taken.
✓ Branch 15 → 16 taken 663 times.
✗ Branch 15 → 101 not taken.
✓ Branch 16 → 17 taken 663 times.
✗ Branch 16 → 99 not taken.
663 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + CTOR_FUNCTION_NAME;
80
3/4
✓ Branch 18 → 19 taken 663 times.
✗ Branch 18 → 126 not taken.
✓ Branch 19 → 20 taken 506 times.
✓ Branch 19 → 21 taken 157 times.
663 if (sourceFile->getNameRegistryEntry(fqFctName))
81 506 return;
82
83 // Check if we have fields, that require us to do anything in the ctor
84
1/2
✓ Branch 21 → 22 taken 157 times.
✗ Branch 21 → 126 not taken.
157 const size_t fieldCount = structScope->getFieldCount();
85 157 bool hasFieldsWithDefaultValue = false;
86 157 bool hasFieldsToConstruct = false;
87
2/2
✓ Branch 77 → 23 taken 346 times.
✓ Branch 77 → 78 taken 151 times.
497 for (size_t i = 0; i < fieldCount; i++) {
88
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 346 times.
346 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
89
1/2
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 346 times.
346 assert(fieldSymbol != nullptr);
90
1/2
✓ Branch 30 → 31 taken 346 times.
✗ Branch 30 → 114 not taken.
346 const QualType &thisType = fieldSymbol->getQualType();
91
92 // Abort if we have a field, that is a reference
93
3/4
✓ Branch 31 → 32 taken 346 times.
✗ Branch 31 → 114 not taken.
✓ Branch 32 → 33 taken 5 times.
✓ Branch 32 → 34 taken 341 times.
346 if (thisType.isRef())
94 6 return;
95
96
3/4
✓ Branch 34 → 35 taken 341 times.
✗ Branch 34 → 36 not taken.
✓ Branch 37 → 38 taken 312 times.
✓ Branch 37 → 39 taken 29 times.
341 if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldSymbol->declNode)) {
97 312 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 341 times.
✗ Branch 44 → 114 not taken.
341 const QualType fieldType = fieldSymbol->getQualType();
103
3/4
✓ Branch 45 → 46 taken 341 times.
✗ Branch 45 → 114 not taken.
✓ Branch 46 → 47 taken 26 times.
✓ Branch 46 → 75 taken 315 times.
341 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(this, 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 111 times.
✓ Branch 78 → 82 taken 40 times.
✓ Branch 79 → 80 taken 97 times.
✓ Branch 79 → 82 taken 14 times.
✓ Branch 80 → 81 taken 92 times.
✓ Branch 80 → 82 taken 5 times.
151 if (!hasFieldsWithDefaultValue && !hasFieldsToConstruct && !node->emitVTable)
120 92 return;
121
122 // Create the default ctor function
123
1/2
✓ Branch 82 → 83 taken 59 times.
✗ Branch 82 → 126 not taken.
59 const std::string entryName = Function::getSymbolTableEntryNameDefaultCtor(node->codeLoc);
124
2/4
✓ Branch 86 → 87 taken 59 times.
✗ Branch 86 → 117 not taken.
✓ Branch 87 → 88 taken 59 times.
✗ Branch 87 → 115 not taken.
177 createDefaultStructMethod(spiceStruct, entryName, CTOR_FUNCTION_NAME, {});
125
2/2
✓ Branch 94 → 95 taken 59 times.
✓ Branch 94 → 97 taken 604 times.
663 }
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 663 void TypeChecker::createDefaultCopyCtorIfRequired(const Struct &spiceStruct, Scope *structScope) {
138
1/2
✓ Branch 2 → 3 taken 663 times.
✗ Branch 2 → 4 not taken.
663 const auto node = spice_pointer_cast<const StructDefNode *>(spiceStruct.declNode);
139
2/4
✓ Branch 9 → 10 taken 663 times.
✗ Branch 9 → 12 not taken.
✓ Branch 10 → 11 taken 663 times.
✗ Branch 10 → 12 not taken.
663 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 663 times.
✗ Branch 13 → 153 not taken.
663 const QualType structType = spiceStruct.entry->getQualType();
143
2/4
✓ Branch 14 → 15 taken 663 times.
✗ Branch 14 → 111 not taken.
✓ Branch 18 → 19 taken 663 times.
✗ Branch 18 → 107 not taken.
1989 const ArgList lookupArgs = {{structType.toConstRef(node), true}};
144
2/4
✓ Branch 22 → 23 taken 663 times.
✗ Branch 22 → 115 not taken.
✓ Branch 23 → 24 taken 663 times.
✗ Branch 23 → 113 not taken.
663 const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, structType, lookupArgs, true);
145
2/2
✓ Branch 26 → 27 taken 124 times.
✓ Branch 26 → 28 taken 539 times.
663 if (copyCtor != nullptr)
146 124 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 539 times.
✗ Branch 28 → 151 not taken.
539 const size_t fieldCount = structScope->getFieldCount();
153 539 bool copyCtorRequired = false;
154
2/2
✓ Branch 82 → 30 taken 1160 times.
✓ Branch 82 → 83 taken 521 times.
1681 for (size_t i = 0; i < fieldCount; i++) {
155
1/2
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 1160 times.
1160 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
156
1/2
✓ Branch 35 → 36 taken 1160 times.
✗ Branch 35 → 151 not taken.
1160 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 1160 times.
✗ Branch 36 → 151 not taken.
✓ Branch 37 → 38 taken 161 times.
✓ Branch 37 → 75 taken 999 times.
1160 if (fieldType.is(TY_STRUCT)) {
160
1/2
✓ Branch 38 → 39 taken 161 times.
✗ Branch 38 → 136 not taken.
161 Scope *bodyScope = fieldType.getBodyScope();
161
1/2
✓ Branch 39 → 40 taken 161 times.
✗ Branch 39 → 136 not taken.
161 const Struct *fieldStruct = fieldType.getStruct(node);
162 // Check if we are required to call a ctor
163
1/2
✓ Branch 40 → 41 taken 161 times.
✗ Branch 40 → 42 not taken.
161 const auto structDeclNode = spice_pointer_cast<StructDefNode *>(fieldStruct->declNode);
164
5/6
✓ Branch 47 → 48 taken 161 times.
✗ Branch 47 → 136 not taken.
✓ Branch 48 → 49 taken 151 times.
✓ Branch 48 → 50 taken 10 times.
✓ Branch 49 → 50 taken 37 times.
✓ Branch 49 → 51 taken 114 times.
161 const bool isCtorCallRequired = bodyScope->hasRefFields() || structDeclNode->emitVTable;
165 // Lookup copy ctor function
166
2/4
✓ Branch 52 → 53 taken 161 times.
✗ Branch 52 → 123 not taken.
✓ Branch 56 → 57 taken 161 times.
✗ Branch 56 → 119 not taken.
322 const ArgList args = {{fieldType.toConstRef(node), false /* we always have the field as storage */}};
167
2/4
✓ Branch 61 → 62 taken 161 times.
✗ Branch 61 → 127 not taken.
✓ Branch 62 → 63 taken 161 times.
✗ Branch 62 → 125 not taken.
483 const Function *ctorFct = FunctionManager::match(this, 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 92 times.
✓ Branch 66 → 69 taken 69 times.
✓ Branch 67 → 68 taken 18 times.
✓ Branch 67 → 69 taken 74 times.
161 if (!ctorFct && isCtorCallRequired)
170 18 return;
171 143 copyCtorRequired |= ctorFct != nullptr;
172
2/2
✓ Branch 71 → 72 taken 143 times.
✓ Branch 71 → 74 taken 18 times.
161 }
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 1142 times.
✗ Branch 75 → 151 not taken.
✓ Branch 76 → 77 taken 32 times.
✓ Branch 76 → 81 taken 1110 times.
1142 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 449 times.
✓ Branch 83 → 86 taken 72 times.
✓ Branch 84 → 85 taken 325 times.
✓ Branch 84 → 86 taken 124 times.
521 if (!copyCtorRequired && !node->emitVTable)
183 325 return;
184
185 // Create the default copy ctor function
186
1/2
✓ Branch 86 → 87 taken 196 times.
✗ Branch 86 → 151 not taken.
196 const std::string entryName = Function::getSymbolTableEntryNameDefaultCopyCtor(node->codeLoc);
187
2/4
✓ Branch 87 → 88 taken 196 times.
✗ Branch 87 → 140 not taken.
✓ Branch 90 → 91 taken 196 times.
✗ Branch 90 → 137 not taken.
588 const ParamList paramTypes = {{structType.toConstRef(node), false}};
188
2/4
✓ Branch 94 → 95 taken 196 times.
✗ Branch 94 → 143 not taken.
✓ Branch 95 → 96 taken 196 times.
✗ Branch 95 → 141 not taken.
196 createDefaultStructMethod(spiceStruct, entryName, CTOR_FUNCTION_NAME, paramTypes);
189
2/2
✓ Branch 102 → 103 taken 196 times.
✓ Branch 102 → 105 taken 467 times.
663 }
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 663 void TypeChecker::createDefaultDtorIfRequired(const Struct &spiceStruct, Scope *structScope) {
201 663 const ASTNode *node = spiceStruct.declNode;
202
2/4
✓ Branch 2 → 3 taken 663 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 663 times.
✗ Branch 3 → 5 not taken.
663 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
203
204 // Abort if the struct already has a user-defined destructor
205 663 const SymbolTableEntry *structEntry = spiceStruct.entry;
206
1/2
✓ Branch 6 → 7 taken 663 times.
✗ Branch 6 → 143 not taken.
663 const QualType &structType = structEntry->getQualType();
207
3/6
✓ Branch 7 → 8 taken 663 times.
✗ Branch 7 → 98 not taken.
✓ Branch 8 → 9 taken 663 times.
✗ Branch 8 → 98 not taken.
✓ Branch 9 → 10 taken 663 times.
✗ Branch 9 → 96 not taken.
663 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + DTOR_FUNCTION_NAME;
208
3/4
✓ Branch 11 → 12 taken 663 times.
✗ Branch 11 → 141 not taken.
✓ Branch 12 → 13 taken 108 times.
✓ Branch 12 → 14 taken 555 times.
663 if (sourceFile->getNameRegistryEntry(fqFctName))
209 108 return;
210
211 // Check we have field types, that require use to do anything in the destructor
212
1/2
✓ Branch 14 → 15 taken 555 times.
✗ Branch 14 → 141 not taken.
555 const size_t fieldCount = structScope->getFieldCount();
213 555 bool hasFieldsToDeAllocate = false;
214 555 bool hasFieldsToDestruct = false;
215
2/2
✓ Branch 41 → 16 taken 1272 times.
✓ Branch 41 → 42 taken 555 times.
1827 for (size_t i = 0; i < fieldCount; i++) {
216
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1272 times.
1272 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
217
2/4
✓ Branch 21 → 22 taken 1272 times.
✗ Branch 21 → 141 not taken.
✓ Branch 22 → 23 taken 1272 times.
✗ Branch 22 → 141 not taken.
1272 hasFieldsToDeAllocate |= fieldSymbol->getQualType().needsDeAllocation();
218
4/6
✓ Branch 23 → 24 taken 1272 times.
✗ Branch 23 → 141 not taken.
✓ Branch 24 → 25 taken 1272 times.
✗ Branch 24 → 141 not taken.
✓ Branch 25 → 26 taken 160 times.
✓ Branch 25 → 40 taken 1112 times.
1272 if (fieldSymbol->getQualType().is(TY_STRUCT)) {
219
2/4
✓ Branch 26 → 27 taken 160 times.
✗ Branch 26 → 141 not taken.
✓ Branch 27 → 28 taken 160 times.
✗ Branch 27 → 141 not taken.
160 Scope *fieldScope = fieldSymbol->getQualType().getBodyScope();
220 // Lookup dtor function
221
1/2
✓ Branch 28 → 29 taken 160 times.
✗ Branch 28 → 141 not taken.
160 const QualType &thisType = fieldSymbol->getQualType();
222
2/4
✓ Branch 33 → 34 taken 160 times.
✗ Branch 33 → 101 not taken.
✓ Branch 34 → 35 taken 160 times.
✗ Branch 34 → 99 not taken.
480 const Function *dtorFct = FunctionManager::match(this, fieldScope, DTOR_FUNCTION_NAME, thisType, {}, {}, true, node);
223 160 hasFieldsToDestruct |= dtorFct != nullptr;
224
1/2
✓ Branch 39 → 40 taken 160 times.
✗ Branch 39 → 141 not taken.
160 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 496 times.
✓ Branch 42 → 45 taken 59 times.
✓ Branch 43 → 44 taken 452 times.
✓ Branch 43 → 45 taken 44 times.
555 if (!hasFieldsToDeAllocate && !hasFieldsToDestruct)
230 452 return;
231
232 // Create the default dtor function
233
1/2
✓ Branch 45 → 46 taken 103 times.
✗ Branch 45 → 141 not taken.
103 const std::string entryName = Function::getSymbolTableEntryNameDefaultDtor(node->codeLoc);
234
2/4
✓ Branch 49 → 50 taken 103 times.
✗ Branch 49 → 113 not taken.
✓ Branch 50 → 51 taken 103 times.
✗ Branch 50 → 111 not taken.
309 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 59 times.
✓ Branch 54 → 60 taken 44 times.
✓ Branch 55 → 56 taken 59 times.
✗ Branch 55 → 139 not taken.
✓ Branch 58 → 59 taken 59 times.
✗ Branch 58 → 60 not taken.
✓ Branch 61 → 62 taken 59 times.
✓ Branch 61 → 88 taken 44 times.
162 if (hasFieldsToDeAllocate && !sourceFile->isStringRT()) {
239
1/2
✓ Branch 62 → 63 taken 59 times.
✗ Branch 62 → 138 not taken.
59 const SourceFile *memoryRT = sourceFile->requestRuntimeModule(MEMORY_RT);
240
1/2
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 65 taken 59 times.
59 assert(memoryRT != nullptr);
241 59 Scope *matchScope = memoryRT->globalScope.get();
242 // Set dealloc function to used
243
1/2
✓ Branch 66 → 67 taken 59 times.
✗ Branch 66 → 138 not taken.
59 const QualType thisType(TY_DYN);
244
3/6
✓ Branch 67 → 68 taken 59 times.
✗ Branch 67 → 120 not taken.
✓ Branch 68 → 69 taken 59 times.
✗ Branch 68 → 120 not taken.
✓ Branch 69 → 70 taken 59 times.
✗ Branch 69 → 120 not taken.
59 QualType bytePtrRefType = QualType(TY_BYTE).toPtr(node).toRef(node);
245
1/2
✓ Branch 70 → 71 taken 59 times.
✗ Branch 70 → 138 not taken.
59 bytePtrRefType.makeHeap();
246
1/2
✓ Branch 74 → 75 taken 59 times.
✗ Branch 74 → 122 not taken.
118 const ArgList args = {{bytePtrRefType, false /* we always have the field as storage */}};
247
2/4
✓ Branch 79 → 80 taken 59 times.
✗ Branch 79 → 129 not taken.
✓ Branch 80 → 81 taken 59 times.
✗ Branch 80 → 127 not taken.
177 Function *deallocFct = FunctionManager::match(this, matchScope, FCT_NAME_DEALLOC, thisType, args, {}, true, node);
248
1/2
✗ Branch 84 → 85 not taken.
✓ Branch 84 → 86 taken 59 times.
59 assert(deallocFct != nullptr);
249 59 deallocFct->used = true;
250 59 }
251
2/2
✓ Branch 91 → 92 taken 103 times.
✓ Branch 91 → 94 taken 560 times.
663 }
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 1350 void TypeChecker::createCtorBodyPreamble(const Scope *bodyScope) {
258 // Retrieve struct scope
259 1350 Scope *structScope = bodyScope->parent;
260
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1350 times.
1350 assert(structScope != nullptr);
261
262 1350 const size_t fieldCount = structScope->getFieldCount();
263
2/2
✓ Branch 49 → 6 taken 3423 times.
✓ Branch 49 → 50 taken 1350 times.
4773 for (size_t i = 0; i < fieldCount; i++) {
264
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 3423 times.
3423 SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
265
3/6
✓ Branch 11 → 12 taken 3423 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 3423 times.
✗ Branch 12 → 64 not taken.
✓ Branch 13 → 14 taken 3423 times.
✗ Branch 13 → 15 not taken.
3423 assert(fieldSymbol != nullptr && fieldSymbol->isField());
266
2/2
✓ Branch 16 → 17 taken 233 times.
✓ Branch 16 → 18 taken 3190 times.
3423 if (fieldSymbol->isImplicitField)
267 233 continue;
268
1/2
✓ Branch 18 → 19 taken 3190 times.
✗ Branch 18 → 64 not taken.
3190 QualType fieldType = fieldSymbol->getQualType();
269
3/4
✓ Branch 19 → 20 taken 3190 times.
✗ Branch 19 → 64 not taken.
✓ Branch 20 → 21 taken 492 times.
✓ Branch 20 → 22 taken 2698 times.
3190 if (fieldType.hasAnyGenericParts())
270
1/2
✓ Branch 21 → 22 taken 492 times.
✗ Branch 21 → 64 not taken.
492 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
271
272
3/4
✓ Branch 22 → 23 taken 3190 times.
✗ Branch 22 → 64 not taken.
✓ Branch 23 → 24 taken 423 times.
✓ Branch 23 → 47 taken 2767 times.
3190 if (fieldType.is(TY_STRUCT)) {
273
1/2
✓ Branch 24 → 25 taken 423 times.
✗ Branch 24 → 26 not taken.
423 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 423 times.
✗ Branch 31 → 64 not taken.
423 Scope *matchScope = fieldType.getBodyScope();
276 const Function *spiceFunc =
277
2/4
✓ Branch 36 → 37 taken 423 times.
✗ Branch 36 → 53 not taken.
✓ Branch 37 → 38 taken 423 times.
✗ Branch 37 → 51 not taken.
1269 FunctionManager::match(this, matchScope, CTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
278
2/2
✓ Branch 42 → 43 taken 370 times.
✓ Branch 42 → 47 taken 53 times.
423 if (spiceFunc != nullptr)
279
3/6
✓ Branch 43 → 44 taken 370 times.
✗ Branch 43 → 63 not taken.
✓ Branch 44 → 45 taken 370 times.
✗ Branch 44 → 63 not taken.
✓ Branch 45 → 46 taken 370 times.
✗ Branch 45 → 63 not taken.
370 fieldSymbol->updateType(fieldType.getWithBodyScope(spiceFunc->thisType.getBodyScope()), true);
280 }
281 }
282 1350 }
283
284 /**
285 * Prepare the generation of the copy ctor body preamble. This preamble is used to initialize the VTable, construct or initialize
286 * fields.
287 */
288 139 void TypeChecker::createCopyCtorBodyPreamble(const Scope *bodyScope) {
289 // Retrieve struct scope
290 139 Scope *structScope = bodyScope->parent;
291
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 139 times.
139 assert(structScope != nullptr);
292
293 139 const size_t fieldCount = structScope->getFieldCount();
294
2/2
✓ Branch 55 → 6 taken 294 times.
✓ Branch 55 → 56 taken 139 times.
433 for (size_t i = 0; i < fieldCount; i++) {
295
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 294 times.
294 SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
296
3/6
✓ Branch 11 → 12 taken 294 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 294 times.
✗ Branch 12 → 76 not taken.
✓ Branch 13 → 14 taken 294 times.
✗ Branch 13 → 15 not taken.
294 assert(fieldSymbol != nullptr && fieldSymbol->isField());
297
2/2
✓ Branch 16 → 17 taken 33 times.
✓ Branch 16 → 18 taken 261 times.
294 if (fieldSymbol->isImplicitField)
298 33 continue;
299
300
1/2
✓ Branch 18 → 19 taken 261 times.
✗ Branch 18 → 76 not taken.
261 QualType fieldType = fieldSymbol->getQualType();
301
2/4
✓ Branch 19 → 20 taken 261 times.
✗ Branch 19 → 76 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 261 times.
261 if (fieldType.hasAnyGenericParts())
302 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
303
304
3/4
✓ Branch 22 → 23 taken 261 times.
✗ Branch 22 → 76 not taken.
✓ Branch 23 → 24 taken 117 times.
✓ Branch 23 → 53 taken 144 times.
261 if (fieldType.is(TY_STRUCT)) {
305
1/2
✓ Branch 24 → 25 taken 117 times.
✗ Branch 24 → 26 not taken.
117 const auto fieldNode = spice_pointer_cast<const FieldNode *>(fieldSymbol->declNode);
306 // Match ctor function, create the concrete manifestation and set it to used
307
1/2
✓ Branch 31 → 32 taken 117 times.
✗ Branch 31 → 75 not taken.
117 Scope *matchScope = fieldType.getBodyScope();
308
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 */}};
309 const Function *copyCtorFct =
310
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 FunctionManager::match(this, matchScope, CTOR_FUNCTION_NAME, fieldType, args, {}, false, fieldNode);
311
2/2
✓ Branch 46 → 47 taken 106 times.
✓ Branch 46 → 51 taken 11 times.
117 if (copyCtorFct != nullptr)
312
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);
313 117 }
314 }
315 139 }
316
317 /**
318 * Prepare the generation of the dtor body preamble. This preamble is used to destruct all fields and to free all heap fields.
319 */
320 223 void TypeChecker::createDtorBodyPreamble(const Scope *bodyScope) {
321 // Retrieve struct scope
322 223 Scope *structScope = bodyScope->parent;
323
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 223 times.
223 assert(structScope != nullptr);
324
325 223 const size_t fieldCount = structScope->getFieldCount();
326
2/2
✓ Branch 45 → 6 taken 781 times.
✓ Branch 45 → 46 taken 223 times.
1004 for (size_t i = 0; i < fieldCount; i++) {
327
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 781 times.
781 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
328
3/6
✓ Branch 11 → 12 taken 781 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 781 times.
✗ Branch 12 → 59 not taken.
✓ Branch 13 → 14 taken 781 times.
✗ Branch 13 → 15 not taken.
781 assert(fieldSymbol != nullptr && fieldSymbol->isField());
329
2/2
✓ Branch 16 → 17 taken 142 times.
✓ Branch 16 → 18 taken 639 times.
781 if (fieldSymbol->isImplicitField)
330 142 continue;
331
1/2
✓ Branch 18 → 19 taken 639 times.
✗ Branch 18 → 59 not taken.
639 QualType fieldType = fieldSymbol->getQualType();
332
2/4
✓ Branch 19 → 20 taken 639 times.
✗ Branch 19 → 59 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 639 times.
639 if (fieldType.hasAnyGenericParts())
333 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
334
335
3/4
✓ Branch 22 → 23 taken 639 times.
✗ Branch 22 → 59 not taken.
✓ Branch 23 → 24 taken 159 times.
✓ Branch 23 → 43 taken 480 times.
639 if (fieldType.is(TY_STRUCT)) {
336
1/2
✓ Branch 24 → 25 taken 159 times.
✗ Branch 24 → 26 not taken.
159 const auto fieldNode = spice_pointer_cast<const FieldNode *>(fieldSymbol->declNode);
337 // Match ctor function, create the concrete manifestation and set it to used
338
1/2
✓ Branch 31 → 32 taken 159 times.
✗ Branch 31 → 59 not taken.
159 Scope *matchScope = fieldType.getBodyScope();
339
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(this, matchScope, DTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
340 }
341 }
342 223 }
343
344 /**
345 * Prepare the generation of a call to a method of a given struct
346 *
347 * @param entry Symbol entry to use as 'this' pointer for the method call
348 * @param methodName Name of the method to call
349 * @param args Provided arguments by the caller
350 * @param node AST node
351 */
352 1344 Function *TypeChecker::implicitlyCallStructMethod(const SymbolTableEntry *entry, const std::string &methodName,
353 const ArgList &args, const ASTNode *node) {
354
3/6
✓ Branch 2 → 3 taken 1344 times.
✗ Branch 2 → 9 not taken.
✓ Branch 3 → 4 taken 1344 times.
✗ Branch 3 → 9 not taken.
✓ Branch 4 → 5 taken 1344 times.
✗ Branch 4 → 9 not taken.
1344 const QualType thisType = entry->getQualType().removeReferenceWrapper().toNonConst();
355
1/2
✓ Branch 5 → 6 taken 1344 times.
✗ Branch 5 → 10 not taken.
2688 return implicitlyCallStructMethod(thisType, methodName, args, node);
356 }
357
358 /**
359 * Prepare the generation of a call to a method of a given struct
360 *
361 * @param thisType Struct type to call the method on
362 * @param methodName Name of the method to call
363 * @param args Provided arguments by the caller
364 * @param node AST node
365 */
366 1581 Function *TypeChecker::implicitlyCallStructMethod(QualType thisType, const std::string &methodName, const ArgList &args,
367 const ASTNode *node) {
368
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1581 times.
1581 assert(thisType.is(TY_STRUCT));
369 1581 Scope *matchScope = thisType.getBodyScope();
370
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 1581 times.
1581 assert(matchScope->type == ScopeType::STRUCT);
371
372 // Search for dtor
373
2/2
✓ Branch 9 → 10 taken 839 times.
✓ Branch 9 → 12 taken 742 times.
1581 if (matchScope->isImportedBy(rootScope))
374
1/2
✓ Branch 10 → 11 taken 839 times.
✗ Branch 10 → 18 not taken.
839 thisType = mapLocalTypeToImportedScopeType(matchScope, thisType);
375
1/2
✓ Branch 13 → 14 taken 1581 times.
✗ Branch 13 → 19 not taken.
1581 return FunctionManager::match(this, matchScope, methodName, thisType, args, {}, true, node);
376 }
377
378 /**
379 * Prepare the generation of a call to the copy ctor of a given struct
380 *
381 * @param entry Symbol entry to use as 'this' pointer for the copy ctor call
382 * @param node Current AST node
383 */
384 5 Function *TypeChecker::implicitlyCallStructCopyCtor(const SymbolTableEntry *entry, const ASTNode *node) {
385
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));
386 5 return implicitlyCallStructCopyCtor(entry->getQualType(), node);
387 }
388
389 /**
390 * Prepare the generation of a call to the copy ctor of a given struct
391 *
392 * @param thisType Struct type to call the copy ctor on
393 * @param node Current AST node
394 */
395 237 Function *TypeChecker::implicitlyCallStructCopyCtor(const QualType &thisType, const ASTNode *node) {
396
2/4
✓ Branch 2 → 3 taken 237 times.
✗ Branch 2 → 19 not taken.
✓ Branch 3 → 4 taken 237 times.
✗ Branch 3 → 19 not taken.
237 const QualType argType = thisType.removeReferenceWrapper().toConstRef(node);
397
1/2
✓ Branch 7 → 8 taken 237 times.
✗ Branch 7 → 20 not taken.
711 const ArgList args = {{argType, false /* we always have an entry here */}};
398
2/4
✓ Branch 11 → 12 taken 237 times.
✗ Branch 11 → 27 not taken.
✓ Branch 12 → 13 taken 237 times.
✗ Branch 12 → 25 not taken.
474 return implicitlyCallStructMethod(thisType, CTOR_FUNCTION_NAME, args, node);
399 237 }
400
401 /**
402 * Prepare the generation of a call to the dtor of a given struct
403 *
404 * @param entry Symbol entry to use as 'this' pointer for the dtor call
405 * @param node StmtLstNode for the current scope
406 */
407 1344 void TypeChecker::implicitlyCallStructDtor(SymbolTableEntry *entry, StmtLstNode *node) {
408 // Add the dtor to the stmt list node to call it later in codegen
409
4/6
✓ Branch 5 → 6 taken 1344 times.
✗ Branch 5 → 16 not taken.
✓ Branch 6 → 7 taken 1344 times.
✗ Branch 6 → 14 not taken.
✓ Branch 10 → 11 taken 986 times.
✓ Branch 10 → 13 taken 358 times.
4032 if (Function *dtor = implicitlyCallStructMethod(entry, DTOR_FUNCTION_NAME, {}, node))
410
2/4
✓ Branch 11 → 12 taken 986 times.
✗ Branch 11 → 23 not taken.
✓ Branch 12 → 13 taken 986 times.
✗ Branch 12 → 23 not taken.
986 node->resourcesToCleanup.at(manIdx).dtorFunctionsToCall.emplace_back(entry, dtor);
411 1344 }
412
413 /**
414 * Prepare the generation of a call to the deallocate function for a heap-allocated variable
415 *
416 * @param node Current AST node for error messages
417 */
418 4 void TypeChecker::implicitlyCallDeallocate(const ASTNode *node) {
419
1/2
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 46 not taken.
4 const SourceFile *memoryRT = sourceFile->requestRuntimeModule(MEMORY_RT);
420
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
4 assert(memoryRT != nullptr);
421 4 Scope *matchScope = memoryRT->globalScope.get();
422 // Set dealloc function to used
423
1/2
✓ Branch 6 → 7 taken 4 times.
✗ Branch 6 → 46 not taken.
4 const QualType thisType(TY_DYN);
424
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);
425
1/2
✓ Branch 10 → 11 taken 4 times.
✗ Branch 10 → 46 not taken.
4 bytePtrRefType.makeHeap();
426
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 */}};
427
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(this, matchScope, FCT_NAME_DEALLOC, thisType, args, {}, true, node);
428
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 4 times.
4 assert(deallocFct != nullptr);
429 4 deallocFct->used = true;
430 4 }
431
432 /**
433 * Consider calls to destructors for the given scope
434 *
435 * @param node StmtLstNode for the current scope
436 */
437 19185 void TypeChecker::doScopeCleanup(StmtLstNode *node) {
438 // Get all variables, that are approved for de-allocation
439
1/2
✓ Branch 2 → 3 taken 19185 times.
✗ Branch 2 → 61 not taken.
19185 std::vector<SymbolTableEntry *> vars = currentScope->getVarsGoingOutOfScope();
440 // Sort by reverse declaration order
441
2/2
✓ Branch 2 → 3 taken 159 times.
✓ Branch 2 → 4 taken 6355 times.
13028 auto comp = [](const SymbolTableEntry *a, const SymbolTableEntry *b) { return a->declNode->codeLoc > b->declNode->codeLoc; };
442
1/2
✓ Branch 3 → 4 taken 19185 times.
✗ Branch 3 → 59 not taken.
19185 std::ranges::sort(vars, comp);
443 // Call dtor for each variable. We call the dtor in reverse declaration order
444
2/2
✓ Branch 54 → 6 taken 7827 times.
✓ Branch 54 → 55 taken 19185 times.
27012 for (SymbolTableEntry *var : vars) {
445 // Check if we have a heap-allocated pointer
446
10/14
✓ Branch 7 → 8 taken 7827 times.
✗ Branch 7 → 57 not taken.
✓ Branch 8 → 9 taken 7827 times.
✗ Branch 8 → 57 not taken.
✓ Branch 9 → 10 taken 1086 times.
✓ Branch 9 → 14 taken 6741 times.
✓ Branch 10 → 11 taken 1086 times.
✗ Branch 10 → 57 not taken.
✓ Branch 11 → 12 taken 1086 times.
✗ Branch 11 → 57 not taken.
✓ Branch 12 → 13 taken 1057 times.
✓ Branch 12 → 14 taken 29 times.
✓ Branch 15 → 16 taken 1057 times.
✓ Branch 15 → 35 taken 6770 times.
7827 if (var->getQualType().isHeap() && var->getQualType().isOneOf({TY_PTR, TY_STRING, TY_FUNCTION, TY_PROCEDURE})) {
447 // The memory runtime is ignored, because it manually allocates to avoid circular dependencies.
448 // Same goes for the string runtime.
449
8/10
✓ Branch 16 → 17 taken 1057 times.
✗ Branch 16 → 58 not taken.
✓ Branch 19 → 20 taken 913 times.
✓ Branch 19 → 24 taken 144 times.
✓ Branch 20 → 21 taken 913 times.
✗ Branch 20 → 58 not taken.
✓ Branch 23 → 24 taken 870 times.
✓ Branch 23 → 25 taken 43 times.
✓ Branch 26 → 27 taken 1014 times.
✓ Branch 26 → 28 taken 43 times.
3027 if (sourceFile->isMemoryRT() || sourceFile->isStringRT())
450 1014 continue;
451 // If the local variable currently does not have the ownership, we must not deallocate its memory
452
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())
453 39 continue;
454
455
1/2
✓ Branch 32 → 33 taken 4 times.
✗ Branch 32 → 58 not taken.
4 implicitlyCallDeallocate(node); // Required to request the memory runtime
456
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);
457 }
458 // Only generate dtor call for structs and if not omitted
459
8/10
✓ Branch 35 → 36 taken 6774 times.
✗ Branch 35 → 58 not taken.
✓ Branch 36 → 37 taken 6774 times.
✗ Branch 36 → 58 not taken.
✓ Branch 37 → 38 taken 1447 times.
✓ Branch 37 → 39 taken 5327 times.
✓ Branch 38 → 39 taken 103 times.
✓ Branch 38 → 40 taken 1344 times.
✓ Branch 41 → 42 taken 5430 times.
✓ Branch 41 → 43 taken 1344 times.
6774 if (!var->getQualType().is(TY_STRUCT) || var->omitDtorCall)
460 5430 continue;
461 // Variable must be either initialized or a struct field
462
3/8
✓ Branch 44 → 45 taken 1344 times.
✗ Branch 44 → 58 not taken.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 48 taken 1344 times.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 1344 times.
1344 if (!var->getLifecycle().isInitialized() && var->scope->type != ScopeType::STRUCT)
463 continue;
464 // Call dtor
465
1/2
✓ Branch 51 → 52 taken 1344 times.
✗ Branch 51 → 58 not taken.
1344 implicitlyCallStructDtor(var, node);
466 }
467 19185 }
468
469 } // namespace spice::compiler
470