GCC Code Coverage Report


Directory: ../
File: src/typechecker/TypeCheckerImplicit.cpp
Date: 2024-12-24 01:17:15
Exec Total Coverage
Lines: 228 231 98.7%
Functions: 13 13 100.0%
Branches: 323 534 60.5%

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