GCC Code Coverage Report


Directory: ../
File: src/typechecker/TypeCheckerImplicit.cpp
Date: 2025-09-16 22:31:20
Exec Total Coverage
Lines: 233 236 98.7%
Functions: 15 15 100.0%
Branches: 324 536 60.4%

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 330 void TypeChecker::createDefaultStructMethod(const Struct &spiceStruct, const std::string &entryName, const std::string &name,
26 const ParamList &params) const {
27 330 Scope *structScope = spiceStruct.scope;
28 330 ASTNode *node = spiceStruct.declNode;
29 330 const SymbolTableEntry *structEntry = spiceStruct.entry;
30
1/2
✓ Branch 0 (2→3) taken 330 times.
✗ Branch 1 (2→68) not taken.
330 const QualType &structType = structEntry->getQualType();
31
3/6
✓ Branch 0 (3→4) taken 330 times.
✗ Branch 1 (3→44) not taken.
✓ Branch 2 (4→5) taken 330 times.
✗ Branch 3 (4→44) not taken.
✓ Branch 4 (5→6) taken 330 times.
✗ Branch 5 (5→42) not taken.
330 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + name;
32
33 // Procedure type
34
1/2
✓ Branch 0 (7→8) taken 330 times.
✗ Branch 1 (7→66) not taken.
330 QualType procedureType(TY_PROCEDURE);
35
1/2
✓ Branch 0 (8→9) taken 330 times.
✗ Branch 1 (8→66) not taken.
330 procedureType.makePublic(); // Always public
36
37 // Insert symbol for function into the symbol table
38
1/2
✓ Branch 0 (9→10) taken 330 times.
✗ Branch 1 (9→66) not taken.
330 SymbolTableEntry *procEntry = structScope->insert(entryName, structEntry->declNode);
39
1/2
✓ Branch 0 (12→13) taken 330 times.
✗ Branch 1 (12→66) not taken.
330 procEntry->updateType(procedureType, true);
40
41 // Add to external name registry
42
1/2
✓ Branch 0 (13→14) taken 330 times.
✗ Branch 1 (13→66) not taken.
330 sourceFile->addNameRegistryEntry(fqFctName, TY_PROCEDURE, procEntry, structScope, true);
43
44 // Create the default method
45
1/2
✓ Branch 0 (14→15) taken 330 times.
✗ Branch 1 (14→66) not taken.
330 const std::vector<GenericType> templateTypes = spiceStruct.templateTypes;
46
1/2
✓ Branch 0 (15→16) taken 330 times.
✗ Branch 1 (15→64) not taken.
330 const QualType returnType(TY_DYN);
47
3/6
✓ Branch 0 (16→17) taken 330 times.
✗ Branch 1 (16→51) not taken.
✓ Branch 2 (17→18) taken 330 times.
✗ Branch 3 (17→48) not taken.
✓ Branch 4 (18→19) taken 330 times.
✗ Branch 5 (18→45) not taken.
330 Function defaultMethod(name, procEntry, structType, returnType, params, templateTypes, structEntry->declNode);
48 330 defaultMethod.implicitDefault = true;
49
50 // Create function scope
51
2/4
✓ Branch 0 (23→24) taken 330 times.
✗ Branch 1 (23→54) not taken.
✓ Branch 2 (24→25) taken 330 times.
✗ Branch 3 (24→52) not taken.
330 Scope *procScope = structScope->createChildScope(defaultMethod.getSignature(false), ScopeType::FUNC_PROC_BODY, &node->codeLoc);
52 330 defaultMethod.bodyScope = procScope;
53
54 // Create 'this' symbol in the function scope
55
1/2
✓ Branch 0 (28→29) taken 330 times.
✗ Branch 1 (28→57) not taken.
990 SymbolTableEntry *thisEntry = procScope->insert(THIS_VARIABLE_NAME, node);
56
2/4
✓ Branch 0 (34→35) taken 330 times.
✗ Branch 1 (34→61) not taken.
✓ Branch 2 (35→36) taken 330 times.
✗ Branch 3 (35→61) not taken.
330 thisEntry->updateType(structType.toPtr(node), true);
57 330 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 0 (36→37) taken 330 times.
✗ Branch 1 (36→62) not taken.
✓ Branch 2 (37→38) taken 330 times.
✗ Branch 3 (37→62) not taken.
330 FunctionManager::insert(structScope, defaultMethod, structEntry->declNode->getFctManifestations(name));
61 330 }
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 633 void TypeChecker::createDefaultCtorIfRequired(const Struct &spiceStruct, Scope *structScope) {
73
1/2
✓ Branch 0 (2→3) taken 633 times.
✗ Branch 1 (2→4) not taken.
633 const auto node = spice_pointer_cast<StructDefNode *>(spiceStruct.declNode);
74
2/4
✓ Branch 0 (9→10) taken 633 times.
✗ Branch 1 (9→12) not taken.
✓ Branch 2 (10→11) taken 633 times.
✗ Branch 3 (10→12) not taken.
633 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
75
76 // Abort if the struct already has a user-defined constructor
77 633 const SymbolTableEntry *structEntry = spiceStruct.entry;
78
1/2
✓ Branch 0 (13→14) taken 633 times.
✗ Branch 1 (13→128) not taken.
633 const QualType &structType = structEntry->getQualType();
79
3/6
✓ Branch 0 (14→15) taken 633 times.
✗ Branch 1 (14→101) not taken.
✓ Branch 2 (15→16) taken 633 times.
✗ Branch 3 (15→101) not taken.
✓ Branch 4 (16→17) taken 633 times.
✗ Branch 5 (16→99) not taken.
633 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + CTOR_FUNCTION_NAME;
80
3/4
✓ Branch 0 (18→19) taken 633 times.
✗ Branch 1 (18→126) not taken.
✓ Branch 2 (19→20) taken 482 times.
✓ Branch 3 (19→21) taken 151 times.
633 if (sourceFile->getNameRegistryEntry(fqFctName))
81 482 return;
82
83 // Check if we have fields, that require us to do anything in the ctor
84
1/2
✓ Branch 0 (21→22) taken 151 times.
✗ Branch 1 (21→126) not taken.
151 const size_t fieldCount = structScope->getFieldCount();
85 151 bool hasFieldsWithDefaultValue = false;
86 151 bool hasFieldsToConstruct = false;
87
2/2
✓ Branch 0 (77→23) taken 328 times.
✓ Branch 1 (77→78) taken 145 times.
473 for (size_t i = 0; i < fieldCount; i++) {
88
1/2
✗ Branch 0 (23→24) not taken.
✓ Branch 1 (23→25) taken 328 times.
328 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
89
1/2
✗ Branch 0 (28→29) not taken.
✓ Branch 1 (28→30) taken 328 times.
328 assert(fieldSymbol != nullptr);
90
1/2
✓ Branch 0 (30→31) taken 328 times.
✗ Branch 1 (30→114) not taken.
328 const QualType &thisType = fieldSymbol->getQualType();
91
92 // Abort if we have a field, that is a reference
93
3/4
✓ Branch 0 (31→32) taken 328 times.
✗ Branch 1 (31→114) not taken.
✓ Branch 2 (32→33) taken 5 times.
✓ Branch 3 (32→34) taken 323 times.
328 if (thisType.isRef())
94 6 return;
95
96
3/4
✓ Branch 0 (34→35) taken 323 times.
✗ Branch 1 (34→36) not taken.
✓ Branch 2 (37→38) taken 299 times.
✓ Branch 3 (37→39) taken 24 times.
323 if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldSymbol->declNode)) {
97 299 hasFieldsWithDefaultValue |= fieldNode->defaultValue != nullptr;
98 } else {
99
2/4
✓ Branch 0 (39→40) taken 24 times.
✗ Branch 1 (39→41) not taken.
✗ Branch 2 (42→43) not taken.
✓ Branch 3 (42→44) taken 24 times.
24 assert(dynamic_cast<DataTypeNode *>(fieldSymbol->declNode) != nullptr);
100 }
101
102
1/2
✓ Branch 0 (44→45) taken 323 times.
✗ Branch 1 (44→114) not taken.
323 const QualType fieldType = fieldSymbol->getQualType();
103
3/4
✓ Branch 0 (45→46) taken 323 times.
✗ Branch 1 (45→114) not taken.
✓ Branch 2 (46→47) taken 25 times.
✓ Branch 3 (46→75) taken 298 times.
323 if (fieldType.is(TY_STRUCT)) {
104
1/2
✓ Branch 0 (47→48) taken 25 times.
✗ Branch 1 (47→114) not taken.
25 Scope *bodyScope = fieldType.getBodyScope();
105
1/2
✓ Branch 0 (48→49) taken 25 times.
✗ Branch 1 (48→114) not taken.
25 const Struct *fieldStruct = fieldType.getStruct(node);
106 // Check if we are required to call a ctor
107
1/2
✓ Branch 0 (49→50) taken 25 times.
✗ Branch 1 (49→51) not taken.
25 const auto structDeclNode = spice_pointer_cast<StructDefNode *>(fieldStruct->declNode);
108
5/6
✓ Branch 0 (56→57) taken 25 times.
✗ Branch 1 (56→114) not taken.
✓ Branch 2 (57→58) taken 24 times.
✓ Branch 3 (57→59) taken 1 times.
✓ Branch 4 (58→59) taken 6 times.
✓ Branch 5 (58→60) taken 18 times.
25 const bool isCtorCallRequired = bodyScope->hasRefFields() || structDeclNode->emitVTable;
109 // Lookup ctor function
110
2/4
✓ Branch 0 (65→66) taken 25 times.
✗ Branch 1 (65→104) not taken.
✓ Branch 2 (66→67) taken 25 times.
✗ Branch 3 (66→102) not taken.
75 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 0 (71→72) taken 12 times.
✓ Branch 1 (71→74) taken 13 times.
✓ Branch 2 (72→73) taken 1 times.
✓ Branch 3 (72→74) taken 11 times.
25 if (!ctorFct && isCtorCallRequired)
113 1 return;
114 24 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 0 (78→79) taken 110 times.
✓ Branch 1 (78→82) taken 35 times.
✓ Branch 2 (79→80) taken 97 times.
✓ Branch 3 (79→82) taken 13 times.
✓ Branch 4 (80→81) taken 92 times.
✓ Branch 5 (80→82) taken 5 times.
145 if (!hasFieldsWithDefaultValue && !hasFieldsToConstruct && !node->emitVTable)
120 92 return;
121
122 // Create the default ctor function
123
1/2
✓ Branch 0 (82→83) taken 53 times.
✗ Branch 1 (82→126) not taken.
53 const std::string entryName = Function::getSymbolTableEntryNameDefaultCtor(node->codeLoc);
124
2/4
✓ Branch 0 (86→87) taken 53 times.
✗ Branch 1 (86→117) not taken.
✓ Branch 2 (87→88) taken 53 times.
✗ Branch 3 (87→115) not taken.
159 createDefaultStructMethod(spiceStruct, entryName, CTOR_FUNCTION_NAME, {});
125
2/2
✓ Branch 0 (94→95) taken 53 times.
✓ Branch 1 (94→97) taken 580 times.
633 }
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 633 void TypeChecker::createDefaultCopyCtorIfRequired(const Struct &spiceStruct, Scope *structScope) {
138
1/2
✓ Branch 0 (2→3) taken 633 times.
✗ Branch 1 (2→4) not taken.
633 const auto node = spice_pointer_cast<const StructDefNode *>(spiceStruct.declNode);
139
2/4
✓ Branch 0 (9→10) taken 633 times.
✗ Branch 1 (9→12) not taken.
✓ Branch 2 (10→11) taken 633 times.
✗ Branch 3 (10→12) not taken.
633 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
140
141 // Abort if the struct already has a user-defined copy constructor
142
1/2
✓ Branch 0 (13→14) taken 633 times.
✗ Branch 1 (13→153) not taken.
633 const QualType structType = spiceStruct.entry->getQualType();
143
2/4
✓ Branch 0 (14→15) taken 633 times.
✗ Branch 1 (14→111) not taken.
✓ Branch 2 (18→19) taken 633 times.
✗ Branch 3 (18→107) not taken.
1899 const ArgList lookupArgs = {{structType.toConstRef(node), true}};
144
2/4
✓ Branch 0 (22→23) taken 633 times.
✗ Branch 1 (22→115) not taken.
✓ Branch 2 (23→24) taken 633 times.
✗ Branch 3 (23→113) not taken.
633 const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, structType, lookupArgs, true);
145
2/2
✓ Branch 0 (26→27) taken 119 times.
✓ Branch 1 (26→28) taken 514 times.
633 if (copyCtor != nullptr)
146 119 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 0 (28→29) taken 514 times.
✗ Branch 1 (28→151) not taken.
514 const size_t fieldCount = structScope->getFieldCount();
153 514 bool copyCtorRequired = false;
154
2/2
✓ Branch 0 (82→30) taken 1095 times.
✓ Branch 1 (82→83) taken 503 times.
1598 for (size_t i = 0; i < fieldCount; i++) {
155
1/2
✗ Branch 0 (30→31) not taken.
✓ Branch 1 (30→32) taken 1095 times.
1095 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
156
1/2
✓ Branch 0 (35→36) taken 1095 times.
✗ Branch 1 (35→151) not taken.
1095 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 0 (36→37) taken 1095 times.
✗ Branch 1 (36→151) not taken.
✓ Branch 2 (37→38) taken 150 times.
✓ Branch 3 (37→75) taken 945 times.
1095 if (fieldType.is(TY_STRUCT)) {
160
1/2
✓ Branch 0 (38→39) taken 150 times.
✗ Branch 1 (38→136) not taken.
150 Scope *bodyScope = fieldType.getBodyScope();
161
1/2
✓ Branch 0 (39→40) taken 150 times.
✗ Branch 1 (39→136) not taken.
150 const Struct *fieldStruct = fieldType.getStruct(node);
162 // Check if we are required to call a ctor
163
1/2
✓ Branch 0 (40→41) taken 150 times.
✗ Branch 1 (40→42) not taken.
150 const auto structDeclNode = spice_pointer_cast<StructDefNode *>(fieldStruct->declNode);
164
5/6
✓ Branch 0 (47→48) taken 150 times.
✗ Branch 1 (47→136) not taken.
✓ Branch 2 (48→49) taken 144 times.
✓ Branch 3 (48→50) taken 6 times.
✓ Branch 4 (49→50) taken 34 times.
✓ Branch 5 (49→51) taken 110 times.
150 const bool isCtorCallRequired = bodyScope->hasRefFields() || structDeclNode->emitVTable;
165 // Lookup copy ctor function
166
2/4
✓ Branch 0 (52→53) taken 150 times.
✗ Branch 1 (52→123) not taken.
✓ Branch 2 (56→57) taken 150 times.
✗ Branch 3 (56→119) not taken.
300 const ArgList args = {{fieldType.toConstRef(node), false /* we always have the field as storage */}};
167
2/4
✓ Branch 0 (61→62) taken 150 times.
✗ Branch 1 (61→127) not taken.
✓ Branch 2 (62→63) taken 150 times.
✗ Branch 3 (62→125) not taken.
450 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 0 (66→67) taken 81 times.
✓ Branch 1 (66→69) taken 69 times.
✓ Branch 2 (67→68) taken 11 times.
✓ Branch 3 (67→69) taken 70 times.
150 if (!ctorFct && isCtorCallRequired)
170 11 return;
171 139 copyCtorRequired |= ctorFct != nullptr;
172
2/2
✓ Branch 0 (71→72) taken 139 times.
✓ Branch 1 (71→74) taken 11 times.
150 }
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 0 (75→76) taken 1084 times.
✗ Branch 1 (75→151) not taken.
✓ Branch 2 (76→77) taken 27 times.
✓ Branch 3 (76→81) taken 1057 times.
1084 if (fieldType.isHeap()) {
176
2/4
✓ Branch 0 (77→78) taken 27 times.
✗ Branch 1 (77→151) not taken.
✗ Branch 2 (78→79) not taken.
✓ Branch 3 (78→80) taken 27 times.
27 assert(fieldType.isPtr());
177 27 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 0 (83→84) taken 436 times.
✓ Branch 1 (83→86) taken 67 times.
✓ Branch 2 (84→85) taken 319 times.
✓ Branch 3 (84→86) taken 117 times.
503 if (!copyCtorRequired && !node->emitVTable)
183 319 return;
184
185 // Create the default copy ctor function
186
1/2
✓ Branch 0 (86→87) taken 184 times.
✗ Branch 1 (86→151) not taken.
184 const std::string entryName = Function::getSymbolTableEntryNameDefaultCopyCtor(node->codeLoc);
187
2/4
✓ Branch 0 (87→88) taken 184 times.
✗ Branch 1 (87→140) not taken.
✓ Branch 2 (90→91) taken 184 times.
✗ Branch 3 (90→137) not taken.
552 const ParamList paramTypes = {{structType.toConstRef(node), false}};
188
2/4
✓ Branch 0 (94→95) taken 184 times.
✗ Branch 1 (94→143) not taken.
✓ Branch 2 (95→96) taken 184 times.
✗ Branch 3 (95→141) not taken.
184 createDefaultStructMethod(spiceStruct, entryName, CTOR_FUNCTION_NAME, paramTypes);
189
2/2
✓ Branch 0 (102→103) taken 184 times.
✓ Branch 1 (102→105) taken 449 times.
633 }
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 633 void TypeChecker::createDefaultDtorIfRequired(const Struct &spiceStruct, Scope *structScope) {
201 633 const ASTNode *node = spiceStruct.declNode;
202
2/4
✓ Branch 0 (2→3) taken 633 times.
✗ Branch 1 (2→5) not taken.
✓ Branch 2 (3→4) taken 633 times.
✗ Branch 3 (3→5) not taken.
633 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
203
204 // Abort if the struct already has a user-defined destructor
205 633 const SymbolTableEntry *structEntry = spiceStruct.entry;
206
1/2
✓ Branch 0 (6→7) taken 633 times.
✗ Branch 1 (6→143) not taken.
633 const QualType &structType = structEntry->getQualType();
207
3/6
✓ Branch 0 (7→8) taken 633 times.
✗ Branch 1 (7→98) not taken.
✓ Branch 2 (8→9) taken 633 times.
✗ Branch 3 (8→98) not taken.
✓ Branch 4 (9→10) taken 633 times.
✗ Branch 5 (9→96) not taken.
633 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + DTOR_FUNCTION_NAME;
208
3/4
✓ Branch 0 (11→12) taken 633 times.
✗ Branch 1 (11→141) not taken.
✓ Branch 2 (12→13) taken 106 times.
✓ Branch 3 (12→14) taken 527 times.
633 if (sourceFile->getNameRegistryEntry(fqFctName))
209 106 return;
210
211 // Check we have field types, that require use to do anything in the destructor
212
1/2
✓ Branch 0 (14→15) taken 527 times.
✗ Branch 1 (14→141) not taken.
527 const size_t fieldCount = structScope->getFieldCount();
213 527 bool hasFieldsToDeAllocate = false;
214 527 bool hasFieldsToDestruct = false;
215
2/2
✓ Branch 0 (41→16) taken 1195 times.
✓ Branch 1 (41→42) taken 527 times.
1722 for (size_t i = 0; i < fieldCount; i++) {
216
1/2
✗ Branch 0 (16→17) not taken.
✓ Branch 1 (16→18) taken 1195 times.
1195 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
217
2/4
✓ Branch 0 (21→22) taken 1195 times.
✗ Branch 1 (21→141) not taken.
✓ Branch 2 (22→23) taken 1195 times.
✗ Branch 3 (22→141) not taken.
1195 hasFieldsToDeAllocate |= fieldSymbol->getQualType().needsDeAllocation();
218
4/6
✓ Branch 0 (23→24) taken 1195 times.
✗ Branch 1 (23→141) not taken.
✓ Branch 2 (24→25) taken 1195 times.
✗ Branch 3 (24→141) not taken.
✓ Branch 4 (25→26) taken 149 times.
✓ Branch 5 (25→40) taken 1046 times.
1195 if (fieldSymbol->getQualType().is(TY_STRUCT)) {
219
2/4
✓ Branch 0 (26→27) taken 149 times.
✗ Branch 1 (26→141) not taken.
✓ Branch 2 (27→28) taken 149 times.
✗ Branch 3 (27→141) not taken.
149 Scope *fieldScope = fieldSymbol->getQualType().getBodyScope();
220 // Lookup dtor function
221
1/2
✓ Branch 0 (28→29) taken 149 times.
✗ Branch 1 (28→141) not taken.
149 const QualType &thisType = fieldSymbol->getQualType();
222
2/4
✓ Branch 0 (33→34) taken 149 times.
✗ Branch 1 (33→101) not taken.
✓ Branch 2 (34→35) taken 149 times.
✗ Branch 3 (34→99) not taken.
447 const Function *dtorFct = FunctionManager::match(this, fieldScope, DTOR_FUNCTION_NAME, thisType, {}, {}, true, node);
223 149 hasFieldsToDestruct |= dtorFct != nullptr;
224
1/2
✓ Branch 0 (39→40) taken 149 times.
✗ Branch 1 (39→141) not taken.
149 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 0 (42→43) taken 475 times.
✓ Branch 1 (42→45) taken 52 times.
✓ Branch 2 (43→44) taken 434 times.
✓ Branch 3 (43→45) taken 41 times.
527 if (!hasFieldsToDeAllocate && !hasFieldsToDestruct)
230 434 return;
231
232 // Create the default dtor function
233
1/2
✓ Branch 0 (45→46) taken 93 times.
✗ Branch 1 (45→141) not taken.
93 const std::string entryName = Function::getSymbolTableEntryNameDefaultDtor(node->codeLoc);
234
2/4
✓ Branch 0 (49→50) taken 93 times.
✗ Branch 1 (49→113) not taken.
✓ Branch 2 (50→51) taken 93 times.
✗ Branch 3 (50→111) not taken.
279 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 0 (54→55) taken 52 times.
✓ Branch 1 (54→60) taken 41 times.
✓ Branch 2 (55→56) taken 52 times.
✗ Branch 3 (55→139) not taken.
✓ Branch 4 (58→59) taken 52 times.
✗ Branch 5 (58→60) not taken.
✓ Branch 6 (61→62) taken 52 times.
✓ Branch 7 (61→88) taken 41 times.
145 if (hasFieldsToDeAllocate && !sourceFile->isStringRT()) {
239
1/2
✓ Branch 0 (62→63) taken 52 times.
✗ Branch 1 (62→138) not taken.
52 const SourceFile *memoryRT = sourceFile->requestRuntimeModule(MEMORY_RT);
240
1/2
✗ Branch 0 (63→64) not taken.
✓ Branch 1 (63→65) taken 52 times.
52 assert(memoryRT != nullptr);
241 52 Scope *matchScope = memoryRT->globalScope.get();
242 // Set dealloc function to used
243
1/2
✓ Branch 0 (66→67) taken 52 times.
✗ Branch 1 (66→138) not taken.
52 const QualType thisType(TY_DYN);
244
3/6
✓ Branch 0 (67→68) taken 52 times.
✗ Branch 1 (67→120) not taken.
✓ Branch 2 (68→69) taken 52 times.
✗ Branch 3 (68→120) not taken.
✓ Branch 4 (69→70) taken 52 times.
✗ Branch 5 (69→120) not taken.
52 QualType bytePtrRefType = QualType(TY_BYTE).toPtr(node).toRef(node);
245
1/2
✓ Branch 0 (70→71) taken 52 times.
✗ Branch 1 (70→138) not taken.
52 bytePtrRefType.makeHeap();
246
1/2
✓ Branch 0 (74→75) taken 52 times.
✗ Branch 1 (74→122) not taken.
104 const ArgList args = {{bytePtrRefType, false /* we always have the field as storage */}};
247
2/4
✓ Branch 0 (79→80) taken 52 times.
✗ Branch 1 (79→129) not taken.
✓ Branch 2 (80→81) taken 52 times.
✗ Branch 3 (80→127) not taken.
156 Function *deallocFct = FunctionManager::match(this, matchScope, FCT_NAME_DEALLOC, thisType, args, {}, true, node);
248
1/2
✗ Branch 0 (84→85) not taken.
✓ Branch 1 (84→86) taken 52 times.
52 assert(deallocFct != nullptr);
249 52 deallocFct->used = true;
250 52 }
251
2/2
✓ Branch 0 (91→92) taken 93 times.
✓ Branch 1 (91→94) taken 540 times.
633 }
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 1296 void TypeChecker::createCtorBodyPreamble(const Scope *bodyScope) {
258 // Retrieve struct scope
259 1296 Scope *structScope = bodyScope->parent;
260
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 1296 times.
1296 assert(structScope != nullptr);
261
262 1296 const size_t fieldCount = structScope->getFieldCount();
263
2/2
✓ Branch 0 (49→6) taken 3284 times.
✓ Branch 1 (49→50) taken 1296 times.
4580 for (size_t i = 0; i < fieldCount; i++) {
264
1/2
✗ Branch 0 (6→7) not taken.
✓ Branch 1 (6→8) taken 3284 times.
3284 SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
265
3/6
✓ Branch 0 (11→12) taken 3284 times.
✗ Branch 1 (11→15) not taken.
✓ Branch 2 (12→13) taken 3284 times.
✗ Branch 3 (12→64) not taken.
✓ Branch 4 (13→14) taken 3284 times.
✗ Branch 5 (13→15) not taken.
3284 assert(fieldSymbol != nullptr && fieldSymbol->isField());
266
2/2
✓ Branch 0 (16→17) taken 208 times.
✓ Branch 1 (16→18) taken 3076 times.
3284 if (fieldSymbol->isImplicitField)
267 208 continue;
268
1/2
✓ Branch 0 (18→19) taken 3076 times.
✗ Branch 1 (18→64) not taken.
3076 QualType fieldType = fieldSymbol->getQualType();
269
3/4
✓ Branch 0 (19→20) taken 3076 times.
✗ Branch 1 (19→64) not taken.
✓ Branch 2 (20→21) taken 451 times.
✓ Branch 3 (20→22) taken 2625 times.
3076 if (fieldType.hasAnyGenericParts())
270
1/2
✓ Branch 0 (21→22) taken 451 times.
✗ Branch 1 (21→64) not taken.
451 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
271
272
3/4
✓ Branch 0 (22→23) taken 3076 times.
✗ Branch 1 (22→64) not taken.
✓ Branch 2 (23→24) taken 407 times.
✓ Branch 3 (23→47) taken 2669 times.
3076 if (fieldType.is(TY_STRUCT)) {
273
1/2
✓ Branch 0 (24→25) taken 407 times.
✗ Branch 1 (24→26) not taken.
407 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 0 (31→32) taken 407 times.
✗ Branch 1 (31→64) not taken.
407 Scope *matchScope = fieldType.getBodyScope();
276 const Function *spiceFunc =
277
2/4
✓ Branch 0 (36→37) taken 407 times.
✗ Branch 1 (36→53) not taken.
✓ Branch 2 (37→38) taken 407 times.
✗ Branch 3 (37→51) not taken.
1221 FunctionManager::match(this, matchScope, CTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
278
2/2
✓ Branch 0 (42→43) taken 360 times.
✓ Branch 1 (42→47) taken 47 times.
407 if (spiceFunc != nullptr)
279
3/6
✓ Branch 0 (43→44) taken 360 times.
✗ Branch 1 (43→63) not taken.
✓ Branch 2 (44→45) taken 360 times.
✗ Branch 3 (44→63) not taken.
✓ Branch 4 (45→46) taken 360 times.
✗ Branch 5 (45→63) not taken.
360 fieldSymbol->updateType(fieldType.getWithBodyScope(spiceFunc->thisType.getBodyScope()), true);
280 }
281 }
282 1296 }
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 136 void TypeChecker::createCopyCtorBodyPreamble(const Scope *bodyScope) {
289 // Retrieve struct scope
290 136 Scope *structScope = bodyScope->parent;
291
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 136 times.
136 assert(structScope != nullptr);
292
293 136 const size_t fieldCount = structScope->getFieldCount();
294
2/2
✓ Branch 0 (55→6) taken 288 times.
✓ Branch 1 (55→56) taken 136 times.
424 for (size_t i = 0; i < fieldCount; i++) {
295
1/2
✗ Branch 0 (6→7) not taken.
✓ Branch 1 (6→8) taken 288 times.
288 SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
296
3/6
✓ Branch 0 (11→12) taken 288 times.
✗ Branch 1 (11→15) not taken.
✓ Branch 2 (12→13) taken 288 times.
✗ Branch 3 (12→76) not taken.
✓ Branch 4 (13→14) taken 288 times.
✗ Branch 5 (13→15) not taken.
288 assert(fieldSymbol != nullptr && fieldSymbol->isField());
297
2/2
✓ Branch 0 (16→17) taken 32 times.
✓ Branch 1 (16→18) taken 256 times.
288 if (fieldSymbol->isImplicitField)
298 32 continue;
299
300
1/2
✓ Branch 0 (18→19) taken 256 times.
✗ Branch 1 (18→76) not taken.
256 QualType fieldType = fieldSymbol->getQualType();
301
2/4
✓ Branch 0 (19→20) taken 256 times.
✗ Branch 1 (19→76) not taken.
✗ Branch 2 (20→21) not taken.
✓ Branch 3 (20→22) taken 256 times.
256 if (fieldType.hasAnyGenericParts())
302 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
303
304
3/4
✓ Branch 0 (22→23) taken 256 times.
✗ Branch 1 (22→76) not taken.
✓ Branch 2 (23→24) taken 117 times.
✓ Branch 3 (23→53) taken 139 times.
256 if (fieldType.is(TY_STRUCT)) {
305
1/2
✓ Branch 0 (24→25) taken 117 times.
✗ Branch 1 (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 0 (31→32) taken 117 times.
✗ Branch 1 (31→75) not taken.
117 Scope *matchScope = fieldType.getBodyScope();
308
2/4
✓ Branch 0 (32→33) taken 117 times.
✗ Branch 1 (32→61) not taken.
✓ Branch 2 (36→37) taken 117 times.
✗ Branch 3 (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 0 (41→42) taken 117 times.
✗ Branch 1 (41→65) not taken.
✓ Branch 2 (42→43) taken 117 times.
✗ Branch 3 (42→63) not taken.
351 FunctionManager::match(this, matchScope, CTOR_FUNCTION_NAME, fieldType, args, {}, false, fieldNode);
311
2/2
✓ Branch 0 (46→47) taken 106 times.
✓ Branch 1 (46→51) taken 11 times.
117 if (copyCtorFct != nullptr)
312
3/6
✓ Branch 0 (47→48) taken 106 times.
✗ Branch 1 (47→72) not taken.
✓ Branch 2 (48→49) taken 106 times.
✗ Branch 3 (48→72) not taken.
✓ Branch 4 (49→50) taken 106 times.
✗ Branch 5 (49→72) not taken.
106 fieldSymbol->updateType(fieldType.getWithBodyScope(copyCtorFct->thisType.getBodyScope()), true);
313 117 }
314 }
315 136 }
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 202 void TypeChecker::createDtorBodyPreamble(const Scope *bodyScope) {
321 // Retrieve struct scope
322 202 Scope *structScope = bodyScope->parent;
323
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 202 times.
202 assert(structScope != nullptr);
324
325 202 const size_t fieldCount = structScope->getFieldCount();
326
2/2
✓ Branch 0 (45→6) taken 713 times.
✓ Branch 1 (45→46) taken 202 times.
915 for (size_t i = 0; i < fieldCount; i++) {
327
1/2
✗ Branch 0 (6→7) not taken.
✓ Branch 1 (6→8) taken 713 times.
713 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
328
3/6
✓ Branch 0 (11→12) taken 713 times.
✗ Branch 1 (11→15) not taken.
✓ Branch 2 (12→13) taken 713 times.
✗ Branch 3 (12→59) not taken.
✓ Branch 4 (13→14) taken 713 times.
✗ Branch 5 (13→15) not taken.
713 assert(fieldSymbol != nullptr && fieldSymbol->isField());
329
2/2
✓ Branch 0 (16→17) taken 121 times.
✓ Branch 1 (16→18) taken 592 times.
713 if (fieldSymbol->isImplicitField)
330 121 continue;
331
1/2
✓ Branch 0 (18→19) taken 592 times.
✗ Branch 1 (18→59) not taken.
592 QualType fieldType = fieldSymbol->getQualType();
332
2/4
✓ Branch 0 (19→20) taken 592 times.
✗ Branch 1 (19→59) not taken.
✗ Branch 2 (20→21) not taken.
✓ Branch 3 (20→22) taken 592 times.
592 if (fieldType.hasAnyGenericParts())
333 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
334
335
3/4
✓ Branch 0 (22→23) taken 592 times.
✗ Branch 1 (22→59) not taken.
✓ Branch 2 (23→24) taken 150 times.
✓ Branch 3 (23→43) taken 442 times.
592 if (fieldType.is(TY_STRUCT)) {
336
1/2
✓ Branch 0 (24→25) taken 150 times.
✗ Branch 1 (24→26) not taken.
150 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 0 (31→32) taken 150 times.
✗ Branch 1 (31→59) not taken.
150 Scope *matchScope = fieldType.getBodyScope();
339
2/4
✓ Branch 0 (36→37) taken 150 times.
✗ Branch 1 (36→49) not taken.
✓ Branch 2 (37→38) taken 150 times.
✗ Branch 3 (37→47) not taken.
450 FunctionManager::match(this, matchScope, DTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
340 }
341 }
342 202 }
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 1313 Function *TypeChecker::implicitlyCallStructMethod(const SymbolTableEntry *entry, const std::string &methodName,
353 const ArgList &args, const ASTNode *node) {
354
3/6
✓ Branch 0 (2→3) taken 1313 times.
✗ Branch 1 (2→9) not taken.
✓ Branch 2 (3→4) taken 1313 times.
✗ Branch 3 (3→9) not taken.
✓ Branch 4 (4→5) taken 1313 times.
✗ Branch 5 (4→9) not taken.
1313 const QualType thisType = entry->getQualType().removeReferenceWrapper().toNonConst();
355
1/2
✓ Branch 0 (5→6) taken 1313 times.
✗ Branch 1 (5→10) not taken.
2626 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 1542 Function *TypeChecker::implicitlyCallStructMethod(QualType thisType, const std::string &methodName, const ArgList &args,
367 const ASTNode *node) {
368
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 1542 times.
1542 assert(thisType.is(TY_STRUCT));
369 1542 Scope *matchScope = thisType.getBodyScope();
370
1/2
✗ Branch 0 (6→7) not taken.
✓ Branch 1 (6→8) taken 1542 times.
1542 assert(matchScope->type == ScopeType::STRUCT);
371
372 // Search for dtor
373
2/2
✓ Branch 0 (9→10) taken 815 times.
✓ Branch 1 (9→12) taken 727 times.
1542 if (matchScope->isImportedBy(rootScope))
374
1/2
✓ Branch 0 (10→11) taken 815 times.
✗ Branch 1 (10→18) not taken.
815 thisType = mapLocalTypeToImportedScopeType(matchScope, thisType);
375
1/2
✓ Branch 0 (13→14) taken 1542 times.
✗ Branch 1 (13→19) not taken.
1542 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 0 (2→3) taken 5 times.
✗ Branch 1 (2→7) not taken.
✓ Branch 2 (5→6) taken 5 times.
✗ Branch 3 (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 229 Function *TypeChecker::implicitlyCallStructCopyCtor(const QualType &thisType, const ASTNode *node) {
396
2/4
✓ Branch 0 (2→3) taken 229 times.
✗ Branch 1 (2→19) not taken.
✓ Branch 2 (3→4) taken 229 times.
✗ Branch 3 (3→19) not taken.
229 const QualType argType = thisType.removeReferenceWrapper().toConstRef(node);
397
1/2
✓ Branch 0 (7→8) taken 229 times.
✗ Branch 1 (7→20) not taken.
687 const ArgList args = {{argType, false /* we always have an entry here */}};
398
2/4
✓ Branch 0 (11→12) taken 229 times.
✗ Branch 1 (11→27) not taken.
✓ Branch 2 (12→13) taken 229 times.
✗ Branch 3 (12→25) not taken.
458 return implicitlyCallStructMethod(thisType, CTOR_FUNCTION_NAME, args, node);
399 229 }
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 1313 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 0 (5→6) taken 1313 times.
✗ Branch 1 (5→16) not taken.
✓ Branch 2 (6→7) taken 1313 times.
✗ Branch 3 (6→14) not taken.
✓ Branch 4 (10→11) taken 969 times.
✓ Branch 5 (10→13) taken 344 times.
3939 if (Function *dtor = implicitlyCallStructMethod(entry, DTOR_FUNCTION_NAME, {}, node))
410
2/4
✓ Branch 0 (11→12) taken 969 times.
✗ Branch 1 (11→23) not taken.
✓ Branch 2 (12→13) taken 969 times.
✗ Branch 3 (12→23) not taken.
969 node->resourcesToCleanup.at(manIdx).dtorFunctionsToCall.emplace_back(entry, dtor);
411 1313 }
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 0 (2→3) taken 4 times.
✗ Branch 1 (2→46) not taken.
4 const SourceFile *memoryRT = sourceFile->requestRuntimeModule(MEMORY_RT);
420
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (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 0 (6→7) taken 4 times.
✗ Branch 1 (6→46) not taken.
4 const QualType thisType(TY_DYN);
424
3/6
✓ Branch 0 (7→8) taken 4 times.
✗ Branch 1 (7→28) not taken.
✓ Branch 2 (8→9) taken 4 times.
✗ Branch 3 (8→28) not taken.
✓ Branch 4 (9→10) taken 4 times.
✗ Branch 5 (9→28) not taken.
4 QualType bytePtrRefType = QualType(TY_BYTE).toPtr(node).toRef(node);
425
1/2
✓ Branch 0 (10→11) taken 4 times.
✗ Branch 1 (10→46) not taken.
4 bytePtrRefType.makeHeap();
426
1/2
✓ Branch 0 (14→15) taken 4 times.
✗ Branch 1 (14→30) not taken.
8 const ArgList args = {{bytePtrRefType, false /* we always have the field as storage */}};
427
2/4
✓ Branch 0 (19→20) taken 4 times.
✗ Branch 1 (19→37) not taken.
✓ Branch 2 (20→21) taken 4 times.
✗ Branch 3 (20→35) not taken.
12 Function *deallocFct = FunctionManager::match(this, matchScope, FCT_NAME_DEALLOC, thisType, args, {}, true, node);
428
1/2
✗ Branch 0 (24→25) not taken.
✓ Branch 1 (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 18654 void TypeChecker::doScopeCleanup(StmtLstNode *node) {
438 // Get all variables, that are approved for de-allocation
439
1/2
✓ Branch 0 (2→3) taken 18654 times.
✗ Branch 1 (2→61) not taken.
18654 std::vector<SymbolTableEntry *> vars = currentScope->getVarsGoingOutOfScope();
440 // Sort by reverse declaration order
441
2/2
✓ Branch 0 (2→3) taken 158 times.
✓ Branch 1 (2→4) taken 6221 times.
12758 auto comp = [](const SymbolTableEntry *a, const SymbolTableEntry *b) { return a->declNode->codeLoc > b->declNode->codeLoc; };
442
1/2
✓ Branch 0 (3→4) taken 18654 times.
✗ Branch 1 (3→59) not taken.
18654 std::ranges::sort(vars, comp);
443 // Call dtor for each variable. We call the dtor in reverse declaration order
444
2/2
✓ Branch 0 (54→6) taken 7628 times.
✓ Branch 1 (54→55) taken 18654 times.
26282 for (SymbolTableEntry *var : vars) {
445 // Check if we have a heap-allocated pointer
446
10/14
✓ Branch 0 (7→8) taken 7628 times.
✗ Branch 1 (7→57) not taken.
✓ Branch 2 (8→9) taken 7628 times.
✗ Branch 3 (8→57) not taken.
✓ Branch 4 (9→10) taken 1052 times.
✓ Branch 5 (9→14) taken 6576 times.
✓ Branch 6 (10→11) taken 1052 times.
✗ Branch 7 (10→57) not taken.
✓ Branch 8 (11→12) taken 1052 times.
✗ Branch 9 (11→57) not taken.
✓ Branch 10 (12→13) taken 1024 times.
✓ Branch 11 (12→14) taken 28 times.
✓ Branch 12 (15→16) taken 1024 times.
✓ Branch 13 (15→35) taken 6604 times.
7628 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 0 (16→17) taken 1024 times.
✗ Branch 1 (16→58) not taken.
✓ Branch 2 (19→20) taken 888 times.
✓ Branch 3 (19→24) taken 136 times.
✓ Branch 4 (20→21) taken 888 times.
✗ Branch 5 (20→58) not taken.
✓ Branch 6 (23→24) taken 850 times.
✓ Branch 7 (23→25) taken 38 times.
✓ Branch 8 (26→27) taken 986 times.
✓ Branch 9 (26→28) taken 38 times.
2936 if (sourceFile->isMemoryRT() || sourceFile->isStringRT())
450 986 continue;
451 // If the local variable currently does not have the ownership, we must not deallocate its memory
452
3/4
✓ Branch 0 (29→30) taken 38 times.
✗ Branch 1 (29→58) not taken.
✓ Branch 2 (30→31) taken 34 times.
✓ Branch 3 (30→32) taken 4 times.
38 if (!var->getLifecycle().isInOwningState())
453 34 continue;
454
455
1/2
✓ Branch 0 (32→33) taken 4 times.
✗ Branch 1 (32→58) not taken.
4 implicitlyCallDeallocate(node); // Required to request the memory runtime
456
2/4
✓ Branch 0 (33→34) taken 4 times.
✗ Branch 1 (33→58) not taken.
✓ Branch 2 (34→35) taken 4 times.
✗ Branch 3 (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 0 (35→36) taken 6608 times.
✗ Branch 1 (35→58) not taken.
✓ Branch 2 (36→37) taken 6608 times.
✗ Branch 3 (36→58) not taken.
✓ Branch 4 (37→38) taken 1414 times.
✓ Branch 5 (37→39) taken 5194 times.
✓ Branch 6 (38→39) taken 101 times.
✓ Branch 7 (38→40) taken 1313 times.
✓ Branch 8 (41→42) taken 5295 times.
✓ Branch 9 (41→43) taken 1313 times.
6608 if (!var->getQualType().is(TY_STRUCT) || var->omitDtorCall)
460 5295 continue;
461 // Variable must be either initialized or a struct field
462
3/8
✓ Branch 0 (44→45) taken 1313 times.
✗ Branch 1 (44→58) not taken.
✗ Branch 2 (45→46) not taken.
✓ Branch 3 (45→48) taken 1313 times.
✗ Branch 4 (46→47) not taken.
✗ Branch 5 (46→48) not taken.
✗ Branch 6 (49→50) not taken.
✓ Branch 7 (49→51) taken 1313 times.
1313 if (!var->getLifecycle().isInitialized() && var->scope->type != ScopeType::STRUCT)
463 continue;
464 // Call dtor
465
1/2
✓ Branch 0 (51→52) taken 1313 times.
✗ Branch 1 (51→58) not taken.
1313 implicitlyCallStructDtor(var, node);
466 }
467 18654 }
468
469 } // namespace spice::compiler
470