GCC Code Coverage Report


Directory: ../
File: src/typechecker/TypeCheckerStatements.cpp
Date: 2025-08-26 18:26:32
Exec Total Coverage
Lines: 91 96 94.8%
Functions: 7 7 100.0%
Branches: 183 300 61.0%

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/ASTNodes.h>
7 #include <global/GlobalResourceManager.h>
8 #include <symboltablebuilder/SymbolTableBuilder.h>
9 #include <typechecker/MacroDefs.h>
10
11 namespace spice::compiler {
12
13 18095 std::any TypeChecker::visitStmtLst(StmtLstNode *node) {
14 // Visit nodes in this scope
15
2/2
✓ Branch 0 (15→4) taken 34458 times.
✓ Branch 1 (15→16) taken 18064 times.
52522 for (StmtNode *stmt : node->statements) {
16
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 34458 times.
34458 if (!stmt)
17 continue;
18 // Print warning if statement is unreachable
19
2/2
✓ Branch 0 (7→8) taken 7 times.
✓ Branch 1 (7→10) taken 34451 times.
34458 if (stmt->unreachable) {
20
1/2
✓ Branch 0 (8→9) taken 7 times.
✗ Branch 1 (8→20) not taken.
7 warnings.emplace_back(stmt->codeLoc, UNREACHABLE_CODE, "This statement is unreachable");
21 7 continue;
22 }
23 // Visit the statement
24
2/2
✓ Branch 0 (10→11) taken 34420 times.
✓ Branch 1 (10→21) taken 31 times.
34451 visit(stmt);
25 }
26
27 // Do cleanup of this scope, e.g. dtor calls for struct instances
28 18064 doScopeCleanup(node);
29
30
1/2
✓ Branch 0 (17→18) taken 18064 times.
✗ Branch 1 (17→23) not taken.
18064 return nullptr;
31 }
32
33 30136 std::any TypeChecker::visitDeclStmt(DeclStmtNode *node) {
34 // Retrieve entry of the lhs variable
35
1/2
✓ Branch 0 (2→3) taken 30136 times.
✗ Branch 1 (2→179) not taken.
30136 SymbolTableEntry *localVarEntry = currentScope->lookupStrict(node->varName);
36
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 30136 times.
30136 assert(localVarEntry != nullptr);
37
38 30136 QualType localVarType;
39
2/2
✓ Branch 0 (7→8) taken 8975 times.
✓ Branch 1 (7→56) taken 21161 times.
30136 if (node->hasAssignment) {
40 // Visit the right side
41
3/4
✓ Branch 0 (8→9) taken 8970 times.
✓ Branch 1 (8→129) taken 5 times.
✓ Branch 2 (9→10) taken 8970 times.
✗ Branch 3 (9→127) not taken.
8975 auto rhs = std::any_cast<ExprResult>(visit(node->assignExpr));
42 8970 auto [rhsTy, rhsEntry] = rhs;
43
44 // Visit data type
45
3/4
✓ Branch 0 (11→12) taken 8967 times.
✓ Branch 1 (11→132) taken 3 times.
✓ Branch 2 (12→13) taken 8967 times.
✗ Branch 3 (12→130) not taken.
8970 localVarType = std::any_cast<QualType>(visit(node->dataType));
46
47 // Check if type has to be inferred or both types are fixed
48
8/10
✓ Branch 0 (14→15) taken 8967 times.
✗ Branch 1 (14→148) not taken.
✓ Branch 2 (15→16) taken 8963 times.
✓ Branch 3 (15→19) taken 4 times.
✓ Branch 4 (16→17) taken 8963 times.
✗ Branch 5 (16→148) not taken.
✓ Branch 6 (17→18) taken 8942 times.
✓ Branch 7 (17→19) taken 21 times.
✓ Branch 8 (20→21) taken 8942 times.
✓ Branch 9 (20→45) taken 25 times.
8967 if (!localVarType.is(TY_UNRESOLVED) && !rhsTy.is(TY_UNRESOLVED)) {
49 8942 const ExprResult lhsResult = {localVarType, localVarEntry};
50
2/2
✓ Branch 0 (21→22) taken 8932 times.
✓ Branch 1 (21→146) taken 10 times.
8942 const auto [type, copyCtor] = opRuleManager.getAssignResultType(node, lhsResult, rhs, true);
51 8932 localVarType = type;
52 8932 node->calledCopyCtor = copyCtor;
53
54 // If this is a struct type, check if the type is known. If not, error out
55
8/14
✓ Branch 0 (24→25) taken 8932 times.
✗ Branch 1 (24→134) not taken.
✓ Branch 2 (25→26) taken 1087 times.
✓ Branch 3 (25→31) taken 7845 times.
✓ Branch 4 (26→27) taken 1087 times.
✗ Branch 5 (26→134) not taken.
✓ Branch 6 (27→28) taken 1087 times.
✗ Branch 7 (27→134) not taken.
✓ Branch 8 (28→29) taken 1087 times.
✗ Branch 9 (28→134) not taken.
✗ Branch 10 (29→30) not taken.
✓ Branch 11 (29→31) taken 1087 times.
✗ Branch 12 (32→33) not taken.
✓ Branch 13 (32→44) taken 8932 times.
8932 if (localVarType.isBase(TY_STRUCT) && !sourceFile->getNameRegistryEntry(localVarType.getBase().getSubType())) {
56 const std::string structName = localVarType.getBase().getSubType();
57 softError(node->dataType, UNKNOWN_DATATYPE, "Unknown struct type '" + structName + "'. Forgot to import?");
58 localVarType = QualType(TY_UNRESOLVED);
59 }
60 } else {
61
1/2
✓ Branch 0 (45→46) taken 25 times.
✗ Branch 1 (45→147) not taken.
25 localVarType = QualType(TY_UNRESOLVED);
62 }
63
64 // If there is an anonymous entry attached (e.g. for struct instantiation) and we take over ownership, delete it
65
9/10
✓ Branch 0 (47→48) taken 8957 times.
✗ Branch 1 (47→148) not taken.
✓ Branch 2 (48→49) taken 8818 times.
✓ Branch 3 (48→52) taken 139 times.
✓ Branch 4 (49→50) taken 1696 times.
✓ Branch 5 (49→52) taken 7122 times.
✓ Branch 6 (50→51) taken 741 times.
✓ Branch 7 (50→52) taken 955 times.
✓ Branch 8 (53→54) taken 741 times.
✓ Branch 9 (53→55) taken 8216 times.
8957 if (!localVarType.isRef() && rhsEntry != nullptr && rhsEntry->anonymous)
66
1/2
✓ Branch 0 (54→55) taken 741 times.
✗ Branch 1 (54→148) not taken.
741 currentScope->symbolTable.deleteAnonymous(rhsEntry->name);
67 } else {
68 // Visit data type
69
2/4
✓ Branch 0 (56→57) taken 21161 times.
✗ Branch 1 (56→151) not taken.
✓ Branch 2 (57→58) taken 21161 times.
✗ Branch 3 (57→149) not taken.
21161 localVarType = std::any_cast<QualType>(visit(node->dataType));
70
71 // References with no initialization are illegal
72
9/10
✓ Branch 0 (59→60) taken 21161 times.
✗ Branch 1 (59→179) not taken.
✓ Branch 2 (60→61) taken 5847 times.
✓ Branch 3 (60→64) taken 15314 times.
✓ Branch 4 (61→62) taken 70 times.
✓ Branch 5 (61→64) taken 5777 times.
✓ Branch 6 (62→63) taken 1 times.
✓ Branch 7 (62→64) taken 69 times.
✓ Branch 8 (65→66) taken 1 times.
✓ Branch 9 (65→73) taken 21160 times.
21161 if (localVarType.isRef() && !node->isFctParam && !node->isForEachItem)
73
2/4
✓ Branch 0 (68→69) taken 1 times.
✗ Branch 1 (68→155) not taken.
✓ Branch 2 (69→70) taken 1 times.
✗ Branch 3 (69→153) not taken.
2 softError(node, REFERENCE_WITHOUT_INITIALIZER, "References must always be initialized directly");
74
75 // If this is a struct, check for the default ctor
76
9/10
✓ Branch 0 (73→74) taken 21161 times.
✗ Branch 1 (73→179) not taken.
✓ Branch 2 (74→75) taken 670 times.
✓ Branch 3 (74→78) taken 20491 times.
✓ Branch 4 (75→76) taken 165 times.
✓ Branch 5 (75→78) taken 505 times.
✓ Branch 6 (76→77) taken 156 times.
✓ Branch 7 (76→78) taken 9 times.
✓ Branch 8 (79→80) taken 156 times.
✓ Branch 9 (79→120) taken 21005 times.
21161 if (localVarType.is(TY_STRUCT) && !node->isFctParam && !node->isForEachItem) {
77
1/2
✓ Branch 0 (80→81) taken 156 times.
✗ Branch 1 (80→179) not taken.
156 Scope *matchScope = localVarType.getBodyScope();
78
1/2
✗ Branch 0 (81→82) not taken.
✓ Branch 1 (81→83) taken 156 times.
156 assert(matchScope != nullptr);
79 // Check if we are required to call a ctor
80
1/2
✓ Branch 0 (83→84) taken 156 times.
✗ Branch 1 (83→179) not taken.
156 const Struct *spiceStruct = localVarType.getStruct(node);
81
1/2
✗ Branch 0 (84→85) not taken.
✓ Branch 1 (84→86) taken 156 times.
156 assert(spiceStruct != nullptr);
82
1/2
✓ Branch 0 (86→87) taken 156 times.
✗ Branch 1 (86→88) not taken.
156 auto structDeclNode = spice_pointer_cast<StructDefNode *>(spiceStruct->declNode);
83
5/6
✓ Branch 0 (93→94) taken 156 times.
✗ Branch 1 (93→179) not taken.
✓ Branch 2 (94→95) taken 155 times.
✓ Branch 3 (94→96) taken 1 times.
✓ Branch 4 (95→96) taken 20 times.
✓ Branch 5 (95→97) taken 135 times.
156 node->isCtorCallRequired = matchScope->hasRefFields() || structDeclNode->emitVTable;
84 // Check if we have a no-args ctor to call
85
1/2
✓ Branch 0 (98→99) taken 156 times.
✗ Branch 1 (98→179) not taken.
156 const std::string &structName = localVarType.getSubType();
86 156 const QualType &thisType = localVarType;
87
2/4
✓ Branch 0 (103→104) taken 156 times.
✗ Branch 1 (103→161) not taken.
✓ Branch 2 (104→105) taken 156 times.
✗ Branch 3 (104→159) not taken.
468 node->calledInitCtor = FunctionManager::match(this, matchScope, CTOR_FUNCTION_NAME, thisType, {}, {}, false, node);
88
4/4
✓ Branch 0 (109→110) taken 15 times.
✓ Branch 1 (109→120) taken 141 times.
✓ Branch 2 (110→111) taken 2 times.
✓ Branch 3 (110→120) taken 13 times.
156 if (!node->calledInitCtor && node->isCtorCallRequired)
89
5/10
✓ Branch 0 (111→112) taken 2 times.
✗ Branch 1 (111→175) not taken.
✓ Branch 2 (112→113) taken 2 times.
✗ Branch 3 (112→173) not taken.
✓ Branch 4 (113→114) taken 2 times.
✗ Branch 5 (113→171) not taken.
✓ Branch 6 (116→117) taken 2 times.
✗ Branch 7 (116→177) not taken.
✓ Branch 8 (117→118) taken 2 times.
✗ Branch 9 (117→177) not taken.
2 SOFT_ERROR_QT(node, MISSING_NO_ARGS_CTOR, "Struct '" + structName + "' misses a no-args constructor")
90 }
91 }
92
93 // Update the type of the variable
94
1/2
✓ Branch 0 (120→121) taken 30116 times.
✗ Branch 1 (120→179) not taken.
30116 localVarEntry->updateType(localVarType, true);
95
1/2
✓ Branch 0 (121→122) taken 30116 times.
✗ Branch 1 (121→179) not taken.
30116 node->entries.at(manIdx) = localVarEntry;
96
97 // Update the state of the variable
98
1/2
✓ Branch 0 (122→123) taken 30116 times.
✗ Branch 1 (122→178) not taken.
30116 localVarEntry->updateState(INITIALIZED, node);
99
100
1/2
✓ Branch 0 (123→124) taken 30116 times.
✗ Branch 1 (123→179) not taken.
30116 return localVarType;
101 }
102
103 8836 std::any TypeChecker::visitReturnStmt(ReturnStmtNode *node) {
104 // Retrieve return variable entry
105
1/2
✓ Branch 0 (4→5) taken 8836 times.
✗ Branch 1 (4→68) not taken.
26508 SymbolTableEntry *returnVar = currentScope->lookup(RETURN_VARIABLE_NAME);
106 8836 const bool isFunction = returnVar != nullptr;
107
4/6
✓ Branch 0 (10→11) taken 8784 times.
✓ Branch 1 (10→13) taken 52 times.
✓ Branch 2 (11→12) taken 8784 times.
✗ Branch 3 (11→91) not taken.
✓ Branch 4 (13→14) taken 52 times.
✗ Branch 5 (13→91) not taken.
8836 const QualType returnType = isFunction ? returnVar->getQualType() : QualType(TY_DYN);
108
109 // Check if procedure with return value
110
2/2
✓ Branch 0 (14→15) taken 52 times.
✓ Branch 1 (14→28) taken 8784 times.
8836 if (!isFunction) {
111
2/2
✓ Branch 0 (15→16) taken 2 times.
✓ Branch 1 (15→26) taken 50 times.
52 if (node->hasReturnValue)
112
4/8
✓ Branch 0 (18→19) taken 2 times.
✗ Branch 1 (18→74) not taken.
✓ Branch 2 (19→20) taken 2 times.
✗ Branch 3 (19→72) not taken.
✓ Branch 4 (22→23) taken 2 times.
✗ Branch 5 (22→78) not taken.
✓ Branch 6 (23→24) taken 2 times.
✗ Branch 7 (23→78) not taken.
6 SOFT_ERROR_ER(node->assignExpr, RETURN_WITH_VALUE_IN_PROCEDURE, "Return with value in procedure is not allowed")
113
1/2
✓ Branch 0 (26→27) taken 50 times.
✗ Branch 1 (26→79) not taken.
50 return nullptr;
114 }
115
116
7/8
✓ Branch 0 (28→29) taken 6 times.
✓ Branch 1 (28→33) taken 8778 times.
✓ Branch 2 (30→31) taken 6 times.
✗ Branch 3 (30→91) not taken.
✓ Branch 4 (31→32) taken 2 times.
✓ Branch 5 (31→33) taken 4 times.
✓ Branch 6 (34→35) taken 2 times.
✓ Branch 7 (34→45) taken 8782 times.
8784 if (!node->hasReturnValue && !returnVar->getLifecycle().isInitialized())
117
4/8
✓ Branch 0 (37→38) taken 2 times.
✗ Branch 1 (37→82) not taken.
✓ Branch 2 (38→39) taken 2 times.
✗ Branch 3 (38→80) not taken.
✓ Branch 4 (41→42) taken 2 times.
✗ Branch 5 (41→86) not taken.
✓ Branch 6 (42→43) taken 2 times.
✗ Branch 7 (42→86) not taken.
6 SOFT_ERROR_QT(node, RETURN_WITHOUT_VALUE_RESULT, "Return without value, but result variable is not initialized yet")
118
119
2/2
✓ Branch 0 (45→46) taken 4 times.
✓ Branch 1 (45→48) taken 8778 times.
8782 if (!node->hasReturnValue)
120
1/2
✓ Branch 0 (46→47) taken 4 times.
✗ Branch 1 (46→87) not taken.
4 return nullptr;
121
122 // Visit right side
123
2/4
✓ Branch 0 (48→49) taken 8778 times.
✗ Branch 1 (48→90) not taken.
✓ Branch 2 (49→50) taken 8778 times.
✗ Branch 3 (49→88) not taken.
8778 const auto rhs = std::any_cast<ExprResult>(visit(node->assignExpr));
124
2/6
✓ Branch 0 (51→52) taken 8778 times.
✗ Branch 1 (51→91) not taken.
✗ Branch 2 (52→53) not taken.
✓ Branch 3 (52→55) taken 8778 times.
✗ Branch 4 (53→54) not taken.
✗ Branch 5 (53→91) not taken.
8778 HANDLE_UNRESOLVED_TYPE_QT(rhs.type)
125
126 // Check if types match
127 8778 const ExprResult returnResult = {returnType, returnVar};
128
2/2
✓ Branch 0 (55→56) taken 8775 times.
✓ Branch 1 (55→91) taken 3 times.
8778 auto [_, copyCtor] = opRuleManager.getAssignResultType(node->assignExpr, returnResult, rhs, false, true, ERROR_MSG_RETURN);
129 8775 node->calledCopyCtor = copyCtor;
130
131 // Check if the dtor call on the return value can be skipped
132
2/2
✓ Branch 0 (58→59) taken 2108 times.
✓ Branch 1 (58→62) taken 6667 times.
8775 if (rhs.entry != nullptr) {
133
2/2
✓ Branch 0 (59→60) taken 737 times.
✓ Branch 1 (59→61) taken 1371 times.
2108 if (rhs.entry->anonymous) {
134 // If there is an anonymous entry attached (e.g. for struct instantiation), delete it
135
1/2
✓ Branch 0 (60→62) taken 737 times.
✗ Branch 1 (60→91) not taken.
737 currentScope->symbolTable.deleteAnonymous(rhs.entry->name);
136 } else {
137 // Otherwise omit the destructor call, because the caller destructs the value
138 1371 rhs.entry->omitDtorCall = true;
139 }
140 }
141
142
1/2
✓ Branch 0 (62→63) taken 8775 times.
✗ Branch 1 (62→91) not taken.
8775 return node->returnType = returnType;
143 }
144
145 108 std::any TypeChecker::visitBreakStmt(BreakStmtNode *node) {
146 // Check if the stated number is valid
147
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→12) taken 107 times.
108 if (node->breakTimes < 1)
148
4/8
✓ Branch 0 (4→5) taken 1 times.
✗ Branch 1 (4→30) not taken.
✓ Branch 2 (5→6) taken 1 times.
✗ Branch 3 (5→28) not taken.
✓ Branch 4 (8→9) taken 1 times.
✗ Branch 5 (8→34) not taken.
✓ Branch 6 (9→10) taken 1 times.
✗ Branch 7 (9→34) not taken.
1 SOFT_ERROR_ER(node, INVALID_BREAK_NUMBER, "Break count must be >= 1, you provided " + std::to_string(node->breakTimes))
149
150 // Check if we can break this often
151 107 const unsigned int maxBreaks = currentScope->getLoopNestingDepth();
152
2/2
✓ Branch 0 (13→14) taken 1 times.
✓ Branch 1 (13→25) taken 106 times.
107 if (static_cast<unsigned int>(node->breakTimes) > maxBreaks)
153
5/10
✓ Branch 0 (15→16) taken 1 times.
✗ Branch 1 (15→39) not taken.
✓ Branch 2 (16→17) taken 1 times.
✗ Branch 3 (16→37) not taken.
✓ Branch 4 (17→18) taken 1 times.
✗ Branch 5 (17→35) not taken.
✓ Branch 6 (21→22) taken 1 times.
✗ Branch 7 (21→44) not taken.
✓ Branch 8 (22→23) taken 1 times.
✗ Branch 9 (22→44) not taken.
1 SOFT_ERROR_ER(node, INVALID_BREAK_NUMBER, "We can only break " + std::to_string(maxBreaks) + " time(s) here")
154
155
1/2
✓ Branch 0 (25→26) taken 106 times.
✗ Branch 1 (25→45) not taken.
106 return nullptr;
156 }
157
158 359 std::any TypeChecker::visitContinueStmt(ContinueStmtNode *node) {
159 // Check if the stated number is valid
160
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→12) taken 358 times.
359 if (node->continueTimes < 1)
161
4/8
✓ Branch 0 (4→5) taken 1 times.
✗ Branch 1 (4→30) not taken.
✓ Branch 2 (5→6) taken 1 times.
✗ Branch 3 (5→28) not taken.
✓ Branch 4 (8→9) taken 1 times.
✗ Branch 5 (8→34) not taken.
✓ Branch 6 (9→10) taken 1 times.
✗ Branch 7 (9→34) not taken.
1 SOFT_ERROR_ER(node, INVALID_CONTINUE_NUMBER,
162 "Continue count must be >= 1, you provided " + std::to_string(node->continueTimes))
163
164 // Check if we can continue this often
165 358 const unsigned int maxContinues = currentScope->getLoopNestingDepth();
166
2/2
✓ Branch 0 (13→14) taken 1 times.
✓ Branch 1 (13→25) taken 357 times.
358 if (static_cast<unsigned int>(node->continueTimes) > maxContinues)
167
5/10
✓ Branch 0 (15→16) taken 1 times.
✗ Branch 1 (15→39) not taken.
✓ Branch 2 (16→17) taken 1 times.
✗ Branch 3 (16→37) not taken.
✓ Branch 4 (17→18) taken 1 times.
✗ Branch 5 (17→35) not taken.
✓ Branch 6 (21→22) taken 1 times.
✗ Branch 7 (21→44) not taken.
✓ Branch 8 (22→23) taken 1 times.
✗ Branch 9 (22→44) not taken.
1 SOFT_ERROR_ER(node, INVALID_CONTINUE_NUMBER, "We can only continue " + std::to_string(maxContinues) + " time(s) here")
168
169
1/2
✓ Branch 0 (25→26) taken 357 times.
✗ Branch 1 (25→45) not taken.
357 return nullptr;
170 }
171
172 6 std::any TypeChecker::visitFallthroughStmt(FallthroughStmtNode *node) {
173 // Check if we can do a fallthrough here
174
2/2
✓ Branch 0 (3→4) taken 2 times.
✓ Branch 1 (3→14) taken 4 times.
6 if (!currentScope->isInCaseBranch())
175
4/8
✓ Branch 0 (6→7) taken 2 times.
✗ Branch 1 (6→19) not taken.
✓ Branch 2 (7→8) taken 2 times.
✗ Branch 3 (7→17) not taken.
✓ Branch 4 (10→11) taken 2 times.
✗ Branch 5 (10→23) not taken.
✓ Branch 6 (11→12) taken 2 times.
✗ Branch 7 (11→23) not taken.
6 SOFT_ERROR_ER(node, FALLTHROUGH_NOT_ALLOWED, "Fallthrough is only allowed in case branches")
176
177
1/2
✓ Branch 0 (14→15) taken 4 times.
✗ Branch 1 (14→24) not taken.
4 return nullptr;
178 }
179
180 743 std::any TypeChecker::visitAssertStmt(AssertStmtNode *node) {
181 // Visit condition
182
2/4
✓ Branch 0 (2→3) taken 743 times.
✗ Branch 1 (2→29) not taken.
✓ Branch 2 (3→4) taken 743 times.
✗ Branch 3 (3→27) not taken.
743 const QualType conditionType = std::any_cast<ExprResult>(visit(node->assignExpr)).type;
183
2/8
✓ Branch 0 (5→6) taken 743 times.
✗ Branch 1 (5→40) not taken.
✗ Branch 2 (6→7) not taken.
✓ Branch 3 (6→11) taken 743 times.
✗ Branch 4 (7→8) not taken.
✗ Branch 5 (7→31) not taken.
✗ Branch 6 (8→9) not taken.
✗ Branch 7 (8→31) not taken.
743 HANDLE_UNRESOLVED_TYPE_ER(conditionType)
184
185 // Check if condition evaluates to bool
186
3/4
✓ Branch 0 (11→12) taken 743 times.
✗ Branch 1 (11→40) not taken.
✓ Branch 2 (12→13) taken 1 times.
✓ Branch 3 (12→23) taken 742 times.
743 if (!conditionType.is(TY_BOOL))
187
4/8
✓ Branch 0 (15→16) taken 1 times.
✗ Branch 1 (15→34) not taken.
✓ Branch 2 (16→17) taken 1 times.
✗ Branch 3 (16→32) not taken.
✓ Branch 4 (19→20) taken 1 times.
✗ Branch 5 (19→38) not taken.
✓ Branch 6 (20→21) taken 1 times.
✗ Branch 7 (20→38) not taken.
3 SOFT_ERROR_ER(node->assignExpr, ASSERTION_CONDITION_BOOL, "The asserted condition must be of type bool")
188
189
1/2
✓ Branch 0 (23→24) taken 742 times.
✗ Branch 1 (23→39) not taken.
742 return nullptr;
190 }
191
192 } // namespace spice::compiler
193