GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 93.0% 119 / 0 / 128
Functions: 92.9% 13 / 0 / 14
Branches: 63.9% 170 / 0 / 266

src/typechecker/TypeChecker.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "TypeChecker.h"
4
5 #include <unordered_set>
6
7 #include <SourceFile.h>
8 #include <ast/Attributes.h>
9 #include <global/GlobalResourceManager.h>
10 #include <symboltablebuilder/Scope.h>
11 #include <symboltablebuilder/SymbolTableBuilder.h>
12 #include <typechecker/FunctionManager.h>
13
14 namespace spice::compiler {
15
16 8603 TypeChecker::TypeChecker(GlobalResourceManager &resourceManager, SourceFile *sourceFile, TypeCheckerMode typeCheckerMode)
17
1/2
✓ Branch 4 → 5 taken 8603 times.
✗ Branch 4 → 7 not taken.
8603 : CompilerPass(resourceManager, sourceFile), typeCheckerMode(typeCheckerMode), warnings(sourceFile->compilerOutput.warnings) {
18 8603 }
19
20 /**
21 * Check whether the given struct and all of its by-value struct fields are manifested, transitively. While a circular
22 * import is still being prepared, a by-value struct field may (transitively) reference a struct that is not manifested
23 * yet; generating implicit special members for such a struct recurses through isTriviallyConstructible and would
24 * dereference a null struct lookup. A genuine infinite-size containment cycle among these structs is reported
25 * separately by the infinite-size check during struct preparation, so a containment cycle here is treated as manifested.
26 */
27 8607 static bool structFullyManifested(const Struct *spiceStruct, const ASTNode *node, std::unordered_set<const Scope *> &visited) {
28
2/2
✓ Branch 29 → 4 taken 20567 times.
✓ Branch 29 → 30 taken 8606 times.
37780 for (const QualType &fieldType : spiceStruct->fieldTypes) {
29
3/4
✓ Branch 6 → 7 taken 20567 times.
✗ Branch 6 → 33 not taken.
✓ Branch 7 → 8 taken 14850 times.
✓ Branch 7 → 9 taken 5717 times.
20567 if (!fieldType.is(TY_STRUCT))
30 14850 continue;
31
1/2
✓ Branch 9 → 10 taken 5717 times.
✗ Branch 9 → 33 not taken.
5717 const Struct *fieldStruct = fieldType.getStruct(node);
32
2/2
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 12 taken 5716 times.
5717 if (fieldStruct == nullptr)
33 1 return false;
34 // Recurse into each field struct once. A containment cycle (already visited) is fine here - it is reported
35 // separately as an infinite-size error. Leaf structs never touch the set, so the common case stays allocation-free.
36
6/10
✓ Branch 12 → 13 taken 5716 times.
✗ Branch 12 → 33 not taken.
✓ Branch 13 → 14 taken 5622 times.
✓ Branch 13 → 17 taken 94 times.
✓ Branch 14 → 15 taken 5622 times.
✗ Branch 14 → 33 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 5622 times.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 5716 times.
5716 if (visited.insert(fieldStruct->scope).second && !structFullyManifested(fieldStruct, node, visited))
37 return false;
38 }
39 8606 return true;
40 }
41
42 5925 std::any TypeChecker::visitEntry(EntryNode *node) {
43 // Initialize
44 5925 currentScope = rootScope;
45
46 // Initialize AST nodes with size of 1
47 5925 const bool isPrepare = typeCheckerMode == TC_MODE_PRE;
48
2/2
✓ Branch 2 → 3 taken 2400 times.
✓ Branch 2 → 4 taken 3525 times.
5925 if (isPrepare)
49 2400 node->resizeToNumberOfManifestations(1);
50
51 // Visit children
52
2/2
✓ Branch 4 → 5 taken 5878 times.
✓ Branch 4 → 42 taken 47 times.
5925 visitChildren(node);
53
54 // Check which implicit structures we need for each struct, defined in this source file
55
2/2
✓ Branch 6 → 7 taken 2385 times.
✓ Branch 6 → 38 taken 3493 times.
5878 if (isPrepare) {
56
1/2
✓ Branch 7 → 8 taken 2385 times.
✗ Branch 7 → 49 not taken.
2385 const std::vector<const Struct *> manifestations = rootScope->getAllStructManifestationsInDeclarationOrder();
57
2/2
✓ Branch 35 → 10 taken 2985 times.
✓ Branch 35 → 36 taken 2385 times.
7755 for (const Struct *manifestation : manifestations) {
58 // Skip while a by-value struct field is (transitively) not manifested yet (circular import still in progress). A
59 // genuine infinite-size cycle among such structs is reported by the infinite-size check during preparation.
60 2985 std::unordered_set<const Scope *> visitedScopes;
61
3/4
✓ Branch 13 → 14 taken 2985 times.
✗ Branch 13 → 43 not taken.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 16 taken 2984 times.
2985 if (!structFullyManifested(manifestation, node, visitedScopes))
62 1 continue;
63 // Check if we need to create a default ctor, copy ctor, move ctor or dtor
64
1/2
✓ Branch 16 → 17 taken 2984 times.
✗ Branch 16 → 43 not taken.
2984 createDefaultCtorIfRequired(*manifestation, manifestation->scope);
65
1/2
✓ Branch 17 → 18 taken 2984 times.
✗ Branch 17 → 43 not taken.
2984 createDefaultCopyCtorIfRequired(*manifestation, manifestation->scope);
66
1/2
✓ Branch 18 → 19 taken 2984 times.
✗ Branch 18 → 43 not taken.
2984 createDefaultMoveCtorIfRequired(*manifestation, manifestation->scope);
67
1/2
✓ Branch 19 → 20 taken 2984 times.
✗ Branch 19 → 43 not taken.
2984 createDefaultDtorIfRequired(*manifestation, manifestation->scope);
68
2/2
✓ Branch 22 → 23 taken 2984 times.
✓ Branch 22 → 25 taken 1 time.
2985 }
69 2385 }
70
71
1/2
✓ Branch 38 → 39 taken 5878 times.
✗ Branch 38 → 50 not taken.
11756 return nullptr;
72 }
73
74 /**
75 * Check if the capture rules for async lambdas are enforced if the async attribute is set
76 *
77 * Only one capture with pointer type, pass-by-val is allowed, since only then we can store it in the second field of the
78 * fat pointer and can ensure, that no stack variable is referenced inside the lambda.
79 *
80 * @param node Lambda base node
81 * @param attrs Lambda attributes
82 * @return False if the rules are violated, true otherwise
83 */
84 62 bool TypeChecker::checkAsyncLambdaCaptureRules(const LambdaBaseNode *node, const LambdaAttrNode *attrs) const {
85 // If the async attribute is not set, we can return early
86
18/32
✓ Branch 2 → 3 taken 6 times.
✓ Branch 2 → 13 taken 56 times.
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 53 not taken.
✓ Branch 6 → 7 taken 6 times.
✗ Branch 6 → 53 not taken.
✓ Branch 7 → 8 taken 6 times.
✗ Branch 7 → 13 not taken.
✓ Branch 10 → 11 taken 6 times.
✗ Branch 10 → 53 not taken.
✓ Branch 11 → 12 taken 6 times.
✗ Branch 11 → 53 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 6 times.
✓ Branch 15 → 16 taken 6 times.
✓ Branch 15 → 17 taken 56 times.
✓ Branch 17 → 18 taken 6 times.
✓ Branch 17 → 20 taken 56 times.
✓ Branch 20 → 21 taken 6 times.
✓ Branch 20 → 22 taken 56 times.
✓ Branch 22 → 23 taken 6 times.
✓ Branch 22 → 25 taken 56 times.
✓ Branch 25 → 26 taken 56 times.
✓ Branch 25 → 27 taken 6 times.
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 55 not taken.
✗ Branch 57 → 58 not taken.
✗ Branch 57 → 60 not taken.
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 64 not taken.
✗ Branch 66 → 67 not taken.
✗ Branch 66 → 69 not taken.
86 if (!attrs || !attrs->attrLst->hasAttr(ATTR_ASYNC) || !attrs->attrLst->getAttrValueByName(ATTR_ASYNC)->boolValue)
87 56 return true; // Not violated
88
89 // If we don't have any captures, we can return early
90 6 const CaptureMap &captures = node->bodyScope->symbolTable.captures;
91
1/2
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 6 times.
6 if (captures.empty())
92 return true; // Not violated
93
94 // Check for the capture rules
95 6 if (const Capture &capture = captures.begin()->second;
96
8/8
✓ Branch 33 → 34 taken 4 times.
✓ Branch 33 → 39 taken 2 times.
✓ Branch 36 → 37 taken 2 times.
✓ Branch 36 → 39 taken 2 times.
✓ Branch 38 → 39 taken 1 time.
✓ Branch 38 → 40 taken 1 time.
✓ Branch 41 → 42 taken 5 times.
✓ Branch 41 → 51 taken 1 time.
6 captures.size() > 1 || !capture.capturedSymbol->getQualType().isPtr() || capture.getMode() != BY_VALUE) {
97 5 const auto warningMessage =
98 "Async lambdas can only capture one pointer by value without storing captures in the caller stack frame, which can lead "
99 "to bugs due to references, outliving the validity scope of the referenced variable.";
100
2/4
✓ Branch 44 → 45 taken 5 times.
✗ Branch 44 → 73 not taken.
✓ Branch 45 → 46 taken 5 times.
✗ Branch 45 → 71 not taken.
10 const CompilerWarning warning(node->codeLoc, ASYNC_LAMBDA_CAPTURE_RULE_VIOLATION, warningMessage);
101
1/2
✓ Branch 48 → 49 taken 5 times.
✗ Branch 48 → 77 not taken.
5 currentScope->sourceFile->compilerOutput.warnings.push_back(warning);
102 5 }
103
104 6 return false; // Violated
105 }
106
107 70 Function *TypeChecker::matchCopyCtor(const QualType &thisType, const ASTNode *node) const {
108
1/2
✓ Branch 2 → 3 taken 70 times.
✗ Branch 2 → 40 not taken.
70 Scope *matchScope = thisType.getBodyScope();
109
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 70 times.
70 assert(matchScope != nullptr);
110
2/4
✓ Branch 5 → 6 taken 70 times.
✗ Branch 5 → 27 not taken.
✓ Branch 9 → 10 taken 70 times.
✗ Branch 9 → 23 not taken.
140 const ArgList args = {{thisType.toConstRef(node), false}};
111
2/4
✓ Branch 14 → 15 taken 70 times.
✗ Branch 14 → 31 not taken.
✓ Branch 15 → 16 taken 70 times.
✗ Branch 15 → 29 not taken.
280 return FunctionManager::match(matchScope, CTOR_FUNCTION_NAME, thisType, args, {}, true, node);
112 70 }
113
114 Function *TypeChecker::matchMoveCtor(const QualType &thisType, const ASTNode *node) const {
115 Scope *matchScope = thisType.getBodyScope();
116 assert(matchScope != nullptr);
117 const ArgList args = {{thisType.toNonConst().toRef(node), false}};
118 return FunctionManager::match(matchScope, CTOR_FUNCTION_NAME, thisType, args, {}, true, node);
119 }
120
121 768275 QualType TypeChecker::mapLocalTypeToImportedScopeType(const Scope *targetScope, const QualType &symbolType) const {
122 // Skip all types, except structs
123
3/4
✓ Branch 2 → 3 taken 768275 times.
✗ Branch 2 → 62 not taken.
✓ Branch 3 → 4 taken 669938 times.
✓ Branch 3 → 5 taken 98337 times.
768275 if (!symbolType.isBase(TY_STRUCT))
124 669938 return symbolType;
125
126 // If the target scope is in the current source file, we can return the symbol type as is
127 98337 SourceFile *targetSourceFile = targetScope->sourceFile;
128
2/2
✓ Branch 5 → 6 taken 22608 times.
✓ Branch 5 → 7 taken 75729 times.
98337 if (targetSourceFile == sourceFile)
129 22608 return symbolType;
130
131 // Match the scope of the symbol type against all scopes in the name registry of the target file
132
5/8
✓ Branch 7 → 8 taken 75729 times.
✗ Branch 7 → 58 not taken.
✓ Branch 8 → 9 taken 75729 times.
✗ Branch 8 → 58 not taken.
✓ Branch 9 → 10 taken 75729 times.
✗ Branch 9 → 58 not taken.
✓ Branch 41 → 11 taken 10773624 times.
✓ Branch 41 → 42 taken 5430 times.
10779054 for (const NameRegistryEntry &entry : targetSourceFile->exportedNameRegistry | std::views::values)
133
7/10
✓ Branch 12 → 13 taken 10773624 times.
✗ Branch 12 → 17 not taken.
✓ Branch 13 → 14 taken 10773624 times.
✗ Branch 13 → 58 not taken.
✓ Branch 14 → 15 taken 10773624 times.
✗ Branch 14 → 58 not taken.
✓ Branch 15 → 16 taken 1533181 times.
✓ Branch 15 → 17 taken 9240443 times.
✓ Branch 18 → 19 taken 1533181 times.
✓ Branch 18 → 39 taken 9240443 times.
10773624 if (entry.targetEntry != nullptr && entry.targetEntry->getQualType().isBase(TY_STRUCT))
134
3/4
✓ Branch 19 → 20 taken 1533181 times.
✗ Branch 19 → 57 not taken.
✓ Branch 37 → 22 taken 2075146 times.
✓ Branch 37 → 38 taken 1462882 times.
5071209 for (const Struct *manifestation : *entry.targetEntry->declNode->getStructManifestations())
135
4/6
✓ Branch 24 → 25 taken 2075146 times.
✗ Branch 24 → 56 not taken.
✓ Branch 25 → 26 taken 2075146 times.
✗ Branch 25 → 56 not taken.
✓ Branch 26 → 27 taken 70299 times.
✓ Branch 26 → 28 taken 2004847 times.
2075146 if (manifestation->scope == symbolType.getBase().getBodyScope())
136 70299 return symbolType;
137
138 // The target file does not know about the struct at all
139 // -> show it how to find the struct
140
3/6
✓ Branch 42 → 43 taken 5430 times.
✗ Branch 42 → 59 not taken.
✓ Branch 43 → 44 taken 5430 times.
✗ Branch 43 → 59 not taken.
✓ Branch 44 → 45 taken 5430 times.
✗ Branch 44 → 59 not taken.
5430 const std::string structName = symbolType.getBase().getSubType();
141
1/2
✓ Branch 45 → 46 taken 5430 times.
✗ Branch 45 → 60 not taken.
5430 const NameRegistryEntry *origRegistryEntry = sourceFile->getNameRegistryEntry(structName);
142 // If even this file does not know the struct by its unqualified name (deep transitive import), there is
143 // nothing to copy over. Skip teaching the target file; the type identity itself is unaffected, and member
144 // access falls back to the resolved body scope.
145
2/2
✓ Branch 46 → 47 taken 32 times.
✓ Branch 46 → 48 taken 5398 times.
5430 if (origRegistryEntry == nullptr)
146 32 return symbolType;
147 // Do not clobber an entry the target file already has under this name (e.g. its OWN same-named struct, like
148 // llvm's `Function` vs the model's `Function`). Teaching uses keepNewOnCollision=false, which would otherwise
149 // ERASE the target's existing entry and break resolution of its own type. The struct's QualType identity is
150 // carried by pointer regardless, so a name that is already taken does not need (re-)teaching here.
151
3/4
✓ Branch 48 → 49 taken 5398 times.
✗ Branch 48 → 60 not taken.
✓ Branch 49 → 50 taken 723 times.
✓ Branch 49 → 51 taken 4675 times.
5398 if (targetSourceFile->exportedNameRegistry.contains(structName))
152 723 return symbolType;
153 4675 const uint64_t targetTypeId = origRegistryEntry->typeId;
154 4675 SymbolTableEntry *targetEntry = origRegistryEntry->targetEntry;
155
1/2
✓ Branch 51 → 52 taken 4675 times.
✗ Branch 51 → 60 not taken.
4675 targetSourceFile->addNameRegistryEntry(structName, targetTypeId, targetEntry, origRegistryEntry->targetScope, false);
156
157 4675 return symbolType;
158 5430 }
159
160 22759 QualType TypeChecker::mapImportedScopeTypeToLocalType(const Scope *sourceScope, const QualType &symbolType) const {
161 // Skip all types, except structs
162
3/4
✓ Branch 2 → 3 taken 22759 times.
✗ Branch 2 → 57 not taken.
✓ Branch 3 → 4 taken 1736 times.
✓ Branch 3 → 5 taken 21023 times.
22759 if (!symbolType.isBase(TY_STRUCT))
163 1736 return symbolType;
164
165 // If the given source file is in the current one, we can return the symbol type as is
166 21023 const SourceFile *sourceSourceFile = sourceScope->sourceFile;
167
2/2
✓ Branch 5 → 6 taken 4911 times.
✓ Branch 5 → 7 taken 16112 times.
21023 if (sourceSourceFile == sourceFile)
168 4911 return symbolType;
169
170 // Match the scope of the symbol type against all scopes in the name registry of this source file
171
1/2
✓ Branch 7 → 8 taken 16112 times.
✗ Branch 7 → 57 not taken.
16112 const QualType baseType = symbolType.getBase();
172
5/8
✓ Branch 8 → 9 taken 16112 times.
✗ Branch 8 → 56 not taken.
✓ Branch 9 → 10 taken 16112 times.
✗ Branch 9 → 56 not taken.
✓ Branch 10 → 11 taken 16112 times.
✗ Branch 10 → 56 not taken.
✓ Branch 41 → 12 taken 2976344 times.
✓ Branch 41 → 42 taken 201 times.
2976545 for (const auto &entry : sourceFile->exportedNameRegistry | std::views::values)
173
7/10
✓ Branch 13 → 14 taken 2976344 times.
✗ Branch 13 → 18 not taken.
✓ Branch 14 → 15 taken 2976344 times.
✗ Branch 14 → 56 not taken.
✓ Branch 15 → 16 taken 2976344 times.
✗ Branch 15 → 56 not taken.
✓ Branch 16 → 17 taken 527382 times.
✓ Branch 16 → 18 taken 2448962 times.
✓ Branch 19 → 20 taken 527382 times.
✓ Branch 19 → 39 taken 2448962 times.
2976344 if (entry.targetEntry != nullptr && entry.targetEntry->getQualType().isBase(TY_STRUCT))
174
3/4
✓ Branch 20 → 21 taken 527382 times.
✗ Branch 20 → 55 not taken.
✓ Branch 37 → 23 taken 593498 times.
✓ Branch 37 → 38 taken 511471 times.
1632351 for (const Struct *manifestation : *entry.targetEntry->declNode->getStructManifestations())
175
3/4
✓ Branch 25 → 26 taken 593498 times.
✗ Branch 25 → 55 not taken.
✓ Branch 26 → 27 taken 15911 times.
✓ Branch 26 → 28 taken 577587 times.
593498 if (manifestation->scope == baseType.getBodyScope())
176 15911 return symbolType;
177
178 // This source file does not know about the struct at all
179 // -> show it how to find the struct
180
2/4
✓ Branch 42 → 43 taken 201 times.
✗ Branch 42 → 57 not taken.
✓ Branch 43 → 44 taken 201 times.
✗ Branch 43 → 57 not taken.
201 const NameRegistryEntry *origRegistryEntry = sourceSourceFile->getNameRegistryEntry(baseType.getSubType());
181 // If even the source file does not know the struct by its unqualified name (deep transitive import), there is
182 // nothing to copy over. Skip teaching this file; the type identity itself is unaffected, and member access
183 // falls back to the resolved body scope.
184
1/2
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 46 taken 201 times.
201 if (origRegistryEntry == nullptr)
185 return symbolType;
186 // Do not clobber an entry this file already has under this name (see mapLocalTypeToImportedScopeType): teaching
187 // with keepNewOnCollision=false would ERASE this file's own same-named struct entry. The QualType identity is
188 // carried by pointer, so an already-taken name needs no (re-)teaching here.
189
4/6
✓ Branch 46 → 47 taken 201 times.
✗ Branch 46 → 57 not taken.
✓ Branch 47 → 48 taken 201 times.
✗ Branch 47 → 57 not taken.
✓ Branch 48 → 49 taken 16 times.
✓ Branch 48 → 50 taken 185 times.
201 if (sourceFile->exportedNameRegistry.contains(baseType.getSubType()))
190 16 return symbolType;
191 185 const uint64_t typeId = origRegistryEntry->typeId;
192 185 SymbolTableEntry *targetEntry = origRegistryEntry->targetEntry;
193
2/4
✓ Branch 50 → 51 taken 185 times.
✗ Branch 50 → 57 not taken.
✓ Branch 51 → 52 taken 185 times.
✗ Branch 51 → 57 not taken.
185 sourceFile->addNameRegistryEntry(baseType.getSubType(), typeId, targetEntry, origRegistryEntry->targetScope, false);
194
195 185 return symbolType;
196 }
197
198 /**
199 * Returns the operator function list for the current manifestation and the given node
200 *
201 * @param node Node to retrieve the op fct pointer list from
202 * @return Op fct pointer list
203 */
204 5361 std::vector<const Function *> &TypeChecker::getOpFctPointers(ASTNode *node) const {
205
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 5361 times.
5361 assert(node->getOpFctPointers()->size() > manIdx);
206 5361 return node->getOpFctPointers()->at(manIdx);
207 }
208
209 /**
210 * Check if a function has been type-checked already. If not, request a revisit
211 *
212 * @param fct Function to check
213 */
214 91111 void TypeChecker::requestRevisitIfRequired(const Function *fct) {
215
4/4
✓ Branch 2 → 3 taken 90804 times.
✓ Branch 2 → 5 taken 307 times.
✓ Branch 3 → 4 taken 59006 times.
✓ Branch 3 → 5 taken 31798 times.
91111 if (fct && !fct->alreadyTypeChecked)
216 59006 fct->entry->scope->sourceFile->reVisitRequested = true;
217 91111 }
218
219 /**
220 * Check type name against well-known type names that require a runtime import. If found one, auto-import the runtime module.
221 *
222 * @param typeName Given type name
223 */
224 118688 void TypeChecker::ensureLoadedRuntimeForTypeName(const std::string &typeName) const {
225
2/2
✓ Branch 18 → 4 taken 349146 times.
✓ Branch 18 → 19 taken 109737 times.
458883 for (const auto &[wellKnownTypeName, runtimeModule] : TYPE_NAME_TO_RT_MODULE_MAPPING) {
226
8/10
✓ Branch 7 → 8 taken 349146 times.
✗ Branch 7 → 20 not taken.
✓ Branch 8 → 9 taken 18689 times.
✓ Branch 8 → 12 taken 330457 times.
✓ Branch 9 → 10 taken 18689 times.
✗ Branch 9 → 20 not taken.
✓ Branch 10 → 11 taken 8951 times.
✓ Branch 10 → 12 taken 9738 times.
✓ Branch 13 → 14 taken 8951 times.
✓ Branch 13 → 16 taken 340195 times.
349146 if (typeName == wellKnownTypeName && !sourceFile->isRT(runtimeModule)) {
227
1/2
✓ Branch 14 → 15 taken 8951 times.
✗ Branch 14 → 20 not taken.
8951 sourceFile->requestRuntimeModule(runtimeModule);
228 8951 break;
229 }
230 }
231 118688 }
232
233 /**
234 * Check type name against well-known function names that require a runtime import. If found one, auto-import the runtime module.
235 *
236 * @param functionName Given function name
237 */
238 27181 void TypeChecker::ensureLoadedRuntimeForFunctionName(const std::string &functionName) const {
239
2/2
✓ Branch 18 → 4 taken 362203 times.
✓ Branch 18 → 19 taken 24886 times.
387089 for (const auto &[wellKnownFunctionName, runtimeModule] : FCT_NAME_TO_RT_MODULE_MAPPING) {
240
8/10
✓ Branch 7 → 8 taken 362203 times.
✗ Branch 7 → 20 not taken.
✓ Branch 8 → 9 taken 2335 times.
✓ Branch 8 → 12 taken 359868 times.
✓ Branch 9 → 10 taken 2335 times.
✗ Branch 9 → 20 not taken.
✓ Branch 10 → 11 taken 2295 times.
✓ Branch 10 → 12 taken 40 times.
✓ Branch 13 → 14 taken 2295 times.
✓ Branch 13 → 16 taken 359908 times.
362203 if (functionName == wellKnownFunctionName && !sourceFile->isRT(runtimeModule)) {
241
1/2
✓ Branch 14 → 15 taken 2295 times.
✗ Branch 14 → 20 not taken.
2295 sourceFile->requestRuntimeModule(runtimeModule);
242 2295 break;
243 }
244 }
245 27181 }
246
247 /**
248 * Add a soft error to the error list
249 */
250 25 void TypeChecker::softError(const ASTNode *node, const SemanticErrorType errorType, const std::string &message) const {
251 25 resourceManager.errorManager.addSoftError(node, errorType, message);
252 25 }
253
254 14 bool TypeChecker::isCopyCtorCall(const FctCallNode *node, const QualType &thisType) const {
255
1/2
✓ Branch 2 → 3 taken 14 times.
✗ Branch 2 → 14 not taken.
14 const FctCallNode::FctCallData &data = node->data.at(manIdx);
256
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 12 times.
14 if (data.args.size() != 2)
257 2 return false;
258
2/4
✓ Branch 7 → 8 taken 12 times.
✗ Branch 7 → 13 not taken.
✓ Branch 8 → 9 taken 12 times.
✗ Branch 8 → 13 not taken.
12 const QualType &secondArgType = data.args.back().first.removeReferenceWrapper().toNonConst();
259
1/2
✓ Branch 9 → 10 taken 12 times.
✗ Branch 9 → 14 not taken.
12 return thisType.matches(secondArgType, false, false, true);
260 }
261
262 } // namespace spice::compiler
263