GCC Code Coverage Report


Directory: ../
File: src/typechecker/TypeCheckerStatements.cpp
Date: 2025-03-05 01:50: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 17255 std::any TypeChecker::visitStmtLst(StmtLstNode *node) {
14 // Visit nodes in this scope
15
2/2
✓ Branch 0 (15→4) taken 33207 times.
✓ Branch 1 (15→16) taken 17224 times.
50431 for (StmtNode *stmt : node->statements) {
16
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 33207 times.
33207 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 33200 times.
33207 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 33169 times.
✓ Branch 1 (10→21) taken 31 times.
33200 visit(stmt);
25 }
26
27 // Do cleanup of this scope, e.g. dtor calls for struct instances
28 17224 doScopeCleanup(node);
29
30
1/2
✓ Branch 0 (17→18) taken 17224 times.
✗ Branch 1 (17→23) not taken.
17224 return nullptr;
31 }
32
33 28215 std::any TypeChecker::visitDeclStmt(DeclStmtNode *node) {
34 // Retrieve entry of the lhs variable
35
1/2
✓ Branch 0 (2→3) taken 28215 times.
✗ Branch 1 (2→179) not taken.
28215 SymbolTableEntry *localVarEntry = currentScope->lookupStrict(node->varName);
36
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 28215 times.
28215 assert(localVarEntry != nullptr);
37
38 28215 QualType localVarType;
39
2/2
✓ Branch 0 (7→8) taken 8690 times.
✓ Branch 1 (7→56) taken 19525 times.
28215 if (node->hasAssignment) {
40 // Visit the right side
41
3/4
✓ Branch 0 (8→9) taken 8685 times.
✓ Branch 1 (8→129) taken 5 times.
✓ Branch 2 (9→10) taken 8685 times.
✗ Branch 3 (9→127) not taken.
8690 auto rhs = std::any_cast<ExprResult>(visit(node->assignExpr));
42 8685 auto [rhsTy, rhsEntry] = rhs;
43
44 // Visit data type
45
3/4
✓ Branch 0 (11→12) taken 8682 times.
✓ Branch 1 (11→132) taken 3 times.
✓ Branch 2 (12→13) taken 8682 times.
✗ Branch 3 (12→130) not taken.
8685 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 8682 times.
✗ Branch 1 (14→148) not taken.
✓ Branch 2 (15→16) taken 8678 times.
✓ Branch 3 (15→19) taken 4 times.
✓ Branch 4 (16→17) taken 8678 times.
✗ Branch 5 (16→148) not taken.
✓ Branch 6 (17→18) taken 8657 times.
✓ Branch 7 (17→19) taken 21 times.
✓ Branch 8 (20→21) taken 8657 times.
✓ Branch 9 (20→45) taken 25 times.
8682 if (!localVarType.is(TY_UNRESOLVED) && !rhsTy.is(TY_UNRESOLVED)) {
49 8657 const ExprResult lhsResult = {localVarType, localVarEntry};
50
2/2
✓ Branch 0 (21→22) taken 8647 times.
✓ Branch 1 (21→146) taken 10 times.
8657 const auto [type, copyCtor] = opRuleManager.getAssignResultType(node, lhsResult, rhs, true);
51 8647 localVarType = type;
52 8647 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 8647 times.
✗ Branch 1 (24→134) not taken.
✓ Branch 2 (25→26) taken 1072 times.
✓ Branch 3 (25→31) taken 7575 times.
✓ Branch 4 (26→27) taken 1072 times.
✗ Branch 5 (26→134) not taken.
✓ Branch 6 (27→28) taken 1072 times.
✗ Branch 7 (27→134) not taken.
✓ Branch 8 (28→29) taken 1072 times.
✗ Branch 9 (28→134) not taken.
✗ Branch 10 (29→30) not taken.
✓ Branch 11 (29→31) taken 1072 times.
✗ Branch 12 (32→33) not taken.
✓ Branch 13 (32→44) taken 8647 times.
8647 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 8672 times.
✗ Branch 1 (47→148) not taken.
✓ Branch 2 (48→49) taken 8533 times.
✓ Branch 3 (48→52) taken 139 times.
✓ Branch 4 (49→50) taken 1634 times.
✓ Branch 5 (49→52) taken 6899 times.
✓ Branch 6 (50→51) taken 737 times.
✓ Branch 7 (50→52) taken 897 times.
✓ Branch 8 (53→54) taken 737 times.
✓ Branch 9 (53→55) taken 7935 times.
8672 if (!localVarType.isRef() && rhsEntry != nullptr && rhsEntry->anonymous)
66
1/2
✓ Branch 0 (54→55) taken 737 times.
✗ Branch 1 (54→148) not taken.
737 currentScope->symbolTable.deleteAnonymous(rhsEntry->name);
67 } else {
68 // Visit data type
69
2/4
✓ Branch 0 (56→57) taken 19525 times.
✗ Branch 1 (56→151) not taken.
✓ Branch 2 (57→58) taken 19525 times.
✗ Branch 3 (57→149) not taken.
19525 localVarType = std::any_cast<QualType>(visit(node->dataType));
70
71 // References with no initialization are illegal
72
9/10
✓ Branch 0 (59→60) taken 19525 times.
✗ Branch 1 (59→179) not taken.
✓ Branch 2 (60→61) taken 5757 times.
✓ Branch 3 (60→64) taken 13768 times.
✓ Branch 4 (61→62) taken 70 times.
✓ Branch 5 (61→64) taken 5687 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 19524 times.
19525 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 19525 times.
✗ Branch 1 (73→179) not taken.
✓ Branch 2 (74→75) taken 657 times.
✓ Branch 3 (74→78) taken 18868 times.
✓ Branch 4 (75→76) taken 163 times.
✓ Branch 5 (75→78) taken 494 times.
✓ Branch 6 (76→77) taken 154 times.
✓ Branch 7 (76→78) taken 9 times.
✓ Branch 8 (79→80) taken 154 times.
✓ Branch 9 (79→120) taken 19371 times.
19525 if (localVarType.is(TY_STRUCT) && !node->isFctParam && !node->isForEachItem) {
77
1/2
✓ Branch 0 (80→81) taken 154 times.
✗ Branch 1 (80→179) not taken.
154 Scope *matchScope = localVarType.getBodyScope();
78
1/2
✗ Branch 0 (81→82) not taken.
✓ Branch 1 (81→83) taken 154 times.
154 assert(matchScope != nullptr);
79 // Check if we are required to call a ctor
80
1/2
✓ Branch 0 (83→84) taken 154 times.
✗ Branch 1 (83→179) not taken.
154 const Struct *spiceStruct = localVarType.getStruct(node);
81
1/2
✗ Branch 0 (84→85) not taken.
✓ Branch 1 (84→86) taken 154 times.
154 assert(spiceStruct != nullptr);
82
1/2
✓ Branch 0 (86→87) taken 154 times.
✗ Branch 1 (86→88) not taken.
154 auto structDeclNode = spice_pointer_cast<StructDefNode *>(spiceStruct->declNode);
83
5/6
✓ Branch 0 (93→94) taken 154 times.
✗ Branch 1 (93→179) not taken.
✓ Branch 2 (94→95) taken 153 times.
✓ Branch 3 (94→96) taken 1 times.
✓ Branch 4 (95→96) taken 20 times.
✓ Branch 5 (95→97) taken 133 times.
154 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 154 times.
✗ Branch 1 (98→179) not taken.
154 const std::string &structName = localVarType.getSubType();
86 154 const QualType &thisType = localVarType;
87
2/4
✓ Branch 0 (103→104) taken 154 times.
✗ Branch 1 (103→161) not taken.
✓ Branch 2 (104→105) taken 154 times.
✗ Branch 3 (104→159) not taken.
462 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 139 times.
✓ Branch 2 (110→111) taken 2 times.
✓ Branch 3 (110→120) taken 13 times.
154 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 28195 times.
✗ Branch 1 (120→179) not taken.
28195 localVarEntry->updateType(localVarType, true);
95
1/2
✓ Branch 0 (121→122) taken 28195 times.
✗ Branch 1 (121→179) not taken.
28195 node->entries.at(manIdx) = localVarEntry;
96
97 // Update the state of the variable
98
1/2
✓ Branch 0 (122→123) taken 28195 times.
✗ Branch 1 (122→178) not taken.
28195 localVarEntry->updateState(INITIALIZED, node);
99
100
1/2
✓ Branch 0 (123→124) taken 28195 times.
✗ Branch 1 (123→179) not taken.
28195 return localVarType;
101 }
102
103 8103 std::any TypeChecker::visitReturnStmt(ReturnStmtNode *node) {
104 // Retrieve return variable entry
105
1/2
✓ Branch 0 (4→5) taken 8103 times.
✗ Branch 1 (4→68) not taken.
24309 SymbolTableEntry *returnVar = currentScope->lookup(RETURN_VARIABLE_NAME);
106 8103 const bool isFunction = returnVar != nullptr;
107
4/6
✓ Branch 0 (10→11) taken 8052 times.
✓ Branch 1 (10→13) taken 51 times.
✓ Branch 2 (11→12) taken 8052 times.
✗ Branch 3 (11→91) not taken.
✓ Branch 4 (13→14) taken 51 times.
✗ Branch 5 (13→91) not taken.
8103 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 51 times.
✓ Branch 1 (14→28) taken 8052 times.
8103 if (!isFunction) {
111
2/2
✓ Branch 0 (15→16) taken 2 times.
✓ Branch 1 (15→26) taken 49 times.
51 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 49 times.
✗ Branch 1 (26→79) not taken.
49 return nullptr;
114 }
115
116
7/8
✓ Branch 0 (28→29) taken 6 times.
✓ Branch 1 (28→33) taken 8046 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 8050 times.
8052 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 8046 times.
8050 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 8046 times.
✗ Branch 1 (48→90) not taken.
✓ Branch 2 (49→50) taken 8046 times.
✗ Branch 3 (49→88) not taken.
8046 const auto rhs = std::any_cast<ExprResult>(visit(node->assignExpr));
124
2/6
✓ Branch 0 (51→52) taken 8046 times.
✗ Branch 1 (51→91) not taken.
✗ Branch 2 (52→53) not taken.
✓ Branch 3 (52→55) taken 8046 times.
✗ Branch 4 (53→54) not taken.
✗ Branch 5 (53→91) not taken.
8046 HANDLE_UNRESOLVED_TYPE_QT(rhs.type)
125
126 // Check if types match
127 8046 const ExprResult returnResult = {returnType, returnVar};
128
2/2
✓ Branch 0 (55→56) taken 8043 times.
✓ Branch 1 (55→91) taken 3 times.
8046 auto [_, copyCtor] = opRuleManager.getAssignResultType(node->assignExpr, returnResult, rhs, false, true, ERROR_MSG_RETURN);
129 8043 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 2074 times.
✓ Branch 1 (58→62) taken 5969 times.
8043 if (rhs.entry != nullptr) {
133
2/2
✓ Branch 0 (59→60) taken 704 times.
✓ Branch 1 (59→61) taken 1370 times.
2074 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 704 times.
✗ Branch 1 (60→91) not taken.
704 currentScope->symbolTable.deleteAnonymous(rhs.entry->name);
136 } else {
137 // Otherwise omit the destructor call, because the caller destructs the value
138 1370 rhs.entry->omitDtorCall = true;
139 }
140 }
141
142
1/2
✓ Branch 0 (62→63) taken 8043 times.
✗ Branch 1 (62→91) not taken.
8043 return node->returnType = returnType;
143 }
144
145 107 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 106 times.
107 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 106 const unsigned int maxBreaks = currentScope->getLoopNestingDepth();
152
2/2
✓ Branch 0 (13→14) taken 1 times.
✓ Branch 1 (13→25) taken 105 times.
106 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 105 times.
✗ Branch 1 (25→45) not taken.
105 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 709 std::any TypeChecker::visitAssertStmt(AssertStmtNode *node) {
181 // Visit condition
182
2/4
✓ Branch 0 (2→3) taken 709 times.
✗ Branch 1 (2→29) not taken.
✓ Branch 2 (3→4) taken 709 times.
✗ Branch 3 (3→27) not taken.
709 const QualType conditionType = std::any_cast<ExprResult>(visit(node->assignExpr)).type;
183
2/8
✓ Branch 0 (5→6) taken 709 times.
✗ Branch 1 (5→40) not taken.
✗ Branch 2 (6→7) not taken.
✓ Branch 3 (6→11) taken 709 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.
709 HANDLE_UNRESOLVED_TYPE_ER(conditionType)
184
185 // Check if condition evaluates to bool
186
3/4
✓ Branch 0 (11→12) taken 709 times.
✗ Branch 1 (11→40) not taken.
✓ Branch 2 (12→13) taken 1 times.
✓ Branch 3 (12→23) taken 708 times.
709 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 708 times.
✗ Branch 1 (23→39) not taken.
708 return nullptr;
190 }
191
192 } // namespace spice::compiler
193