GCC Code Coverage Report


Directory: ../
File: src/typechecker/TypeCheckerControlStructures.cpp
Date: 2025-03-05 01:50:32
Exec Total Coverage
Lines: 169 171 98.8%
Functions: 12 12 100.0%
Branches: 238 442 53.8%

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 <global/GlobalResourceManager.h>
7 #include <symboltablebuilder/ScopeHandle.h>
8 #include <typechecker/MacroDefs.h>
9
10 namespace spice::compiler {
11
12 2106 std::any TypeChecker::visitUnsafeBlock(UnsafeBlockNode *node) {
13 // Change to unsafe block body scope
14
2/4
✓ Branch 0 (2→3) taken 2106 times.
✗ Branch 1 (2→13) not taken.
✓ Branch 2 (3→4) taken 2106 times.
✗ Branch 3 (3→11) not taken.
2106 ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::UNSAFE_BODY);
15
16 // Visit body
17
1/2
✓ Branch 0 (5→6) taken 2106 times.
✗ Branch 1 (5→15) not taken.
2106 visit(node->body);
18
19
1/2
✓ Branch 0 (7→8) taken 2106 times.
✗ Branch 1 (7→16) not taken.
4212 return nullptr;
20 2106 }
21
22 1212 std::any TypeChecker::visitForLoop(ForLoopNode *node) {
23 // Change to for body scope
24
2/4
✓ Branch 0 (2→3) taken 1212 times.
✗ Branch 1 (2→37) not taken.
✓ Branch 2 (3→4) taken 1212 times.
✗ Branch 3 (3→35) not taken.
1212 ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::FOR_BODY);
25
26 // Visit loop variable declaration
27
1/2
✓ Branch 0 (5→6) taken 1212 times.
✗ Branch 1 (5→39) not taken.
1212 visit(node->initDecl);
28
29 // Visit condition
30
2/4
✓ Branch 0 (7→8) taken 1212 times.
✗ Branch 1 (7→42) not taken.
✓ Branch 2 (8→9) taken 1212 times.
✗ Branch 3 (8→40) not taken.
1212 const QualType conditionType = std::any_cast<ExprResult>(visit(node->condAssign)).type;
31
2/6
✓ Branch 0 (10→11) taken 1212 times.
✗ Branch 1 (10→55) not taken.
✗ Branch 2 (11→12) not taken.
✓ Branch 3 (11→14) taken 1212 times.
✗ Branch 4 (12→13) not taken.
✗ Branch 5 (12→44) not taken.
1212 HANDLE_UNRESOLVED_TYPE_PTR(conditionType)
32 // Check if condition evaluates to bool
33
3/4
✓ Branch 0 (14→15) taken 1212 times.
✗ Branch 1 (14→55) not taken.
✓ Branch 2 (15→16) taken 1 times.
✓ Branch 3 (15→26) taken 1211 times.
1212 if (!conditionType.is(TY_BOOL))
34
4/8
✓ Branch 0 (18→19) taken 1 times.
✗ Branch 1 (18→47) not taken.
✓ Branch 2 (19→20) taken 1 times.
✗ Branch 3 (19→45) not taken.
✓ Branch 4 (22→23) taken 1 times.
✗ Branch 5 (22→51) not taken.
✓ Branch 6 (23→24) taken 1 times.
✗ Branch 7 (23→51) not taken.
3 SOFT_ERROR_ER(node->condAssign, CONDITION_MUST_BE_BOOL, "For loop condition must be of type bool")
35
36 // Visit incrementer
37
1/2
✓ Branch 0 (26→27) taken 1211 times.
✗ Branch 1 (26→52) not taken.
1211 visit(node->incAssign);
38
39 // Visit body
40
1/2
✓ Branch 0 (28→29) taken 1211 times.
✗ Branch 1 (28→53) not taken.
1211 visit(node->body);
41
42
1/2
✓ Branch 0 (30→31) taken 1211 times.
✗ Branch 1 (30→54) not taken.
1211 return nullptr;
43 1212 }
44
45 106 std::any TypeChecker::visitForeachLoop(ForeachLoopNode *node) {
46 // Visit iterator assignment
47 106 AssignExprNode *iteratorNode = node->iteratorAssign;
48
2/4
✓ Branch 0 (2→3) taken 106 times.
✗ Branch 1 (2→202) not taken.
✓ Branch 2 (3→4) taken 106 times.
✗ Branch 3 (3→200) not taken.
106 QualType iteratorOrIterableType = std::any_cast<ExprResult>(visit(iteratorNode)).type;
49
2/6
✓ Branch 0 (5→6) taken 106 times.
✗ Branch 1 (5→346) not taken.
✗ Branch 2 (6→7) not taken.
✓ Branch 3 (6→9) taken 106 times.
✗ Branch 4 (7→8) not taken.
✗ Branch 5 (7→204) not taken.
106 HANDLE_UNRESOLVED_TYPE_PTR(iteratorOrIterableType)
50
1/2
✓ Branch 0 (9→10) taken 106 times.
✗ Branch 1 (9→205) not taken.
106 iteratorOrIterableType = iteratorOrIterableType.removeReferenceWrapper();
51
52 // Retrieve iterator type
53 106 QualType iteratorType = iteratorOrIterableType;
54
55
3/4
✓ Branch 0 (10→11) taken 106 times.
✗ Branch 1 (10→346) not taken.
✓ Branch 2 (11→12) taken 87 times.
✓ Branch 3 (11→74) taken 19 times.
106 if (iteratorOrIterableType.isIterable(node)) {
56 87 const QualType &iterableType = iteratorOrIterableType;
57
3/4
✓ Branch 0 (12→13) taken 87 times.
✗ Branch 1 (12→346) not taken.
✓ Branch 2 (13→14) taken 8 times.
✓ Branch 3 (13→50) taken 79 times.
87 if (iteratorOrIterableType.isArray()) { // Array
58
2/4
✓ Branch 0 (16→17) taken 8 times.
✗ Branch 1 (16→208) not taken.
✓ Branch 2 (17→18) taken 8 times.
✗ Branch 3 (17→206) not taken.
16 const NameRegistryEntry *nameRegistryEntry = sourceFile->getNameRegistryEntry(ARRAY_ITERATOR_NAME);
59
2/2
✓ Branch 0 (20→21) taken 1 times.
✓ Branch 1 (20→29) taken 7 times.
8 if (!nameRegistryEntry) {
60
2/4
✓ Branch 0 (23→24) taken 1 times.
✗ Branch 1 (23→214) not taken.
✓ Branch 2 (24→25) taken 1 times.
✗ Branch 3 (24→212) not taken.
1 softError(node, UNKNOWN_DATATYPE, "Forgot to import \"std/iterator/array-iterator\"?");
61
1/2
✓ Branch 0 (27→28) taken 1 times.
✗ Branch 1 (27→218) not taken.
1 return nullptr;
62 }
63 7 nameRegistryEntry->targetEntry->used = nameRegistryEntry->importEntry->used = true;
64 7 Scope *matchScope = nameRegistryEntry->targetScope->parent;
65
1/2
✗ Branch 0 (29→30) not taken.
✓ Branch 1 (29→31) taken 7 times.
7 assert(matchScope->type == ScopeType::GLOBAL);
66
1/2
✓ Branch 0 (31→32) taken 7 times.
✗ Branch 1 (31→236) not taken.
7 QualType unsignedLongType(TY_LONG);
67
1/2
✓ Branch 0 (32→33) taken 7 times.
✗ Branch 1 (32→236) not taken.
7 unsignedLongType.makeUnsigned(true);
68
1/2
✓ Branch 0 (37→38) taken 7 times.
✗ Branch 1 (37→219) not taken.
14 const ArgList argTypes = {Arg(iterableType, false), Arg(unsignedLongType, false)};
69
1/2
✓ Branch 0 (39→40) taken 7 times.
✗ Branch 1 (39→234) not taken.
7 const QualType thisType(TY_DYN);
70
2/4
✓ Branch 0 (43→44) taken 7 times.
✗ Branch 1 (43→227) not taken.
✓ Branch 2 (44→45) taken 7 times.
✗ Branch 3 (44→225) not taken.
21 node->getIteratorFct = FunctionManager::match(this, matchScope, "iterate", thisType, argTypes, {}, true, iteratorNode);
71 7 } else { // Struct, implementing Iterator interface
72
1/2
✓ Branch 0 (50→51) taken 79 times.
✗ Branch 1 (50→346) not taken.
79 Scope *matchScope = iterableType.getBodyScope();
73
2/4
✓ Branch 0 (55→56) taken 79 times.
✗ Branch 1 (55→239) not taken.
✓ Branch 2 (56→57) taken 79 times.
✗ Branch 3 (56→237) not taken.
237 node->getIteratorFct = FunctionManager::match(this, matchScope, "getIterator", iterableType, {}, {}, true, iteratorNode);
74 }
75
2/2
✓ Branch 0 (62→63) taken 1 times.
✓ Branch 1 (62→71) taken 85 times.
86 if (node->getIteratorFct == nullptr)
76
2/4
✓ Branch 0 (66→67) taken 1 times.
✗ Branch 1 (66→252) not taken.
✓ Branch 2 (67→68) taken 1 times.
✗ Branch 3 (67→249) not taken.
3 throw SemanticError(iteratorNode, INVALID_ITERATOR, "No getIterator() function found for the given iterable type");
77
78 85 iteratorType = QualType(node->getIteratorFct->returnType);
79 // Add anonymous symbol to keep track of dtor call, if non-trivially destructible
80
2/4
✓ Branch 0 (71→72) taken 85 times.
✗ Branch 1 (71→346) not taken.
✗ Branch 2 (72→73) not taken.
✓ Branch 3 (72→74) taken 85 times.
85 if (!iteratorType.isTriviallyDestructible(iteratorNode))
81 currentScope->symbolTable.insertAnonymous(iteratorType, iteratorNode);
82 }
83
84 // Change to foreach body scope
85
2/4
✓ Branch 0 (74→75) taken 104 times.
✗ Branch 1 (74→260) not taken.
✓ Branch 2 (75→76) taken 104 times.
✗ Branch 3 (75→258) not taken.
104 ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::FOREACH_BODY);
86
87 // Check iterator type
88
3/4
✓ Branch 0 (77→78) taken 104 times.
✗ Branch 1 (77→344) not taken.
✓ Branch 2 (78→79) taken 1 times.
✓ Branch 3 (78→86) taken 103 times.
104 if (!iteratorType.isIterator(node)) {
89 const std::string errMsg =
90 "Can only iterate over arrays or data structures, inheriting from IIterator or IIterable. You provided " +
91
2/4
✓ Branch 0 (79→80) taken 1 times.
✗ Branch 1 (79→264) not taken.
✓ Branch 2 (80→81) taken 1 times.
✗ Branch 3 (80→262) not taken.
1 iteratorType.getName(false);
92
1/2
✓ Branch 0 (82→83) taken 1 times.
✗ Branch 1 (82→266) not taken.
1 softError(node->iteratorAssign, OPERATOR_WRONG_DATA_TYPE, errMsg);
93
1/2
✓ Branch 0 (83→84) taken 1 times.
✗ Branch 1 (83→265) not taken.
1 return nullptr;
94 1 }
95
1/2
✓ Branch 0 (86→87) taken 103 times.
✗ Branch 1 (86→344) not taken.
103 const QualTypeList &iteratorTemplateTypes = iteratorType.getTemplateTypes();
96
2/2
✓ Branch 0 (88→89) taken 1 times.
✓ Branch 1 (88→99) taken 102 times.
103 if (iteratorTemplateTypes.empty())
97
4/8
✓ Branch 0 (91→92) taken 1 times.
✗ Branch 1 (91→271) not taken.
✓ Branch 2 (92→93) taken 1 times.
✗ Branch 3 (92→269) not taken.
✓ Branch 4 (95→96) taken 1 times.
✗ Branch 5 (95→275) not taken.
✓ Branch 6 (96→97) taken 1 times.
✗ Branch 7 (96→275) not taken.
3 SOFT_ERROR_ER(node->iteratorAssign, INVALID_ITERATOR,
98 "Iterator has no generic arguments so that the item type could not be inferred")
99
100 102 const bool hasIdx = node->idxVarDecl;
101
2/2
✓ Branch 0 (99→100) taken 6 times.
✓ Branch 1 (99→120) taken 96 times.
102 if (hasIdx) {
102 // Visit index declaration or assignment
103
2/4
✓ Branch 0 (100→101) taken 6 times.
✗ Branch 1 (100→278) not taken.
✓ Branch 2 (101→102) taken 6 times.
✗ Branch 3 (101→276) not taken.
6 auto indexType = std::any_cast<QualType>(visit(node->idxVarDecl));
104
2/6
✓ Branch 0 (103→104) taken 6 times.
✗ Branch 1 (103→287) not taken.
✗ Branch 2 (104→105) not taken.
✓ Branch 3 (104→107) taken 6 times.
✗ Branch 4 (105→106) not taken.
✗ Branch 5 (105→279) not taken.
6 HANDLE_UNRESOLVED_TYPE_PTR(indexType)
105 // Check if index type is int
106
3/4
✓ Branch 0 (107→108) taken 6 times.
✗ Branch 1 (107→287) not taken.
✓ Branch 2 (108→109) taken 1 times.
✓ Branch 3 (108→118) taken 5 times.
6 if (!indexType.is(TY_LONG))
107
5/10
✓ Branch 0 (109→110) taken 1 times.
✗ Branch 1 (109→284) not taken.
✓ Branch 2 (110→111) taken 1 times.
✗ Branch 3 (110→282) not taken.
✓ Branch 4 (111→112) taken 1 times.
✗ Branch 5 (111→280) not taken.
✓ Branch 6 (114→115) taken 1 times.
✗ Branch 7 (114→286) not taken.
✓ Branch 8 (115→116) taken 1 times.
✗ Branch 9 (115→286) not taken.
1 SOFT_ERROR_ER(node->idxVarDecl, FOREACH_IDX_NOT_LONG,
108 "Index in foreach loop must be of type long. You provided " + indexType.getName(false))
109 }
110
111 // Retrieve .get(), .getIdx(), .isValid() and .next() functions
112
1/2
✓ Branch 0 (120→121) taken 101 times.
✗ Branch 1 (120→344) not taken.
101 Scope *matchScope = iteratorType.getBodyScope();
113 101 QualType iteratorItemType;
114
2/2
✓ Branch 0 (121→122) taken 5 times.
✓ Branch 1 (121→137) taken 96 times.
101 if (hasIdx) {
115
2/4
✓ Branch 0 (126→127) taken 5 times.
✗ Branch 1 (126→290) not taken.
✓ Branch 2 (127→128) taken 5 times.
✗ Branch 3 (127→288) not taken.
15 node->getIdxFct = FunctionManager::match(this, matchScope, "getIdx", iteratorType, {}, {}, false, node);
116
1/2
✗ Branch 0 (132→133) not taken.
✓ Branch 1 (132→134) taken 5 times.
5 assert(node->getIdxFct != nullptr);
117
1/2
✓ Branch 0 (134→135) taken 5 times.
✗ Branch 1 (134→344) not taken.
5 iteratorItemType = node->getIdxFct->returnType.getTemplateTypes().back();
118 } else {
119
2/4
✓ Branch 0 (141→142) taken 96 times.
✗ Branch 1 (141→302) not taken.
✓ Branch 2 (142→143) taken 96 times.
✗ Branch 3 (142→300) not taken.
288 node->getFct = FunctionManager::match(this, matchScope, "get", iteratorType, {}, {}, false, node);
120
1/2
✗ Branch 0 (147→148) not taken.
✓ Branch 1 (147→149) taken 96 times.
96 assert(node->getFct != nullptr);
121 96 iteratorItemType = node->getFct->returnType;
122 }
123
2/4
✓ Branch 0 (154→155) taken 101 times.
✗ Branch 1 (154→314) not taken.
✓ Branch 2 (155→156) taken 101 times.
✗ Branch 3 (155→312) not taken.
303 node->isValidFct = FunctionManager::match(this, matchScope, "isValid", iteratorType, {}, {}, false, node);
124
1/2
✗ Branch 0 (160→161) not taken.
✓ Branch 1 (160→162) taken 101 times.
101 assert(node->isValidFct != nullptr);
125
2/4
✓ Branch 0 (166→167) taken 101 times.
✗ Branch 1 (166→326) not taken.
✓ Branch 2 (167→168) taken 101 times.
✗ Branch 3 (167→324) not taken.
303 node->nextFct = FunctionManager::match(this, matchScope, "next", iteratorType, {}, {}, false, node);
126
1/2
✗ Branch 0 (172→173) not taken.
✓ Branch 1 (172→174) taken 101 times.
101 assert(node->nextFct != nullptr);
127
128 // Retrieve item variable entry
129
1/2
✓ Branch 0 (174→175) taken 101 times.
✗ Branch 1 (174→344) not taken.
101 SymbolTableEntry *itemVarSymbol = currentScope->lookupStrict(node->itemVarDecl->varName);
130
1/2
✗ Branch 0 (177→178) not taken.
✓ Branch 1 (177→179) taken 101 times.
101 assert(itemVarSymbol != nullptr);
131
132 // Check type of the item
133
2/4
✓ Branch 0 (179→180) taken 101 times.
✗ Branch 1 (179→338) not taken.
✓ Branch 2 (180→181) taken 101 times.
✗ Branch 3 (180→336) not taken.
101 auto itemType = std::any_cast<QualType>(visit(node->itemVarDecl));
134
2/6
✓ Branch 0 (182→183) taken 101 times.
✗ Branch 1 (182→344) not taken.
✗ Branch 2 (183→184) not taken.
✓ Branch 3 (183→186) taken 101 times.
✗ Branch 4 (184→185) not taken.
✗ Branch 5 (184→339) not taken.
101 HANDLE_UNRESOLVED_TYPE_PTR(itemType)
135
3/4
✓ Branch 0 (186→187) taken 101 times.
✗ Branch 1 (186→344) not taken.
✓ Branch 2 (187→188) taken 4 times.
✓ Branch 3 (187→190) taken 97 times.
101 if (itemType.is(TY_DYN)) { // Perform type inference
136 // Update evaluated symbol type of the declaration data type
137
1/2
✓ Branch 0 (188→189) taken 4 times.
✗ Branch 1 (188→344) not taken.
4 node->itemVarDecl->dataType->setEvaluatedSymbolType(iteratorItemType, manIdx);
138 // Update item type
139 4 itemType = iteratorItemType;
140 } else {
141 // Check item type
142 97 const ExprResult itemResult = {itemType, itemVarSymbol};
143 97 const ExprResult iteratorItemResult = {iteratorItemType, nullptr /* always a temporary */};
144
2/2
✓ Branch 0 (190→191) taken 96 times.
✓ Branch 1 (190→340) taken 1 times.
97 (void)opRuleManager.getAssignResultType(node->itemVarDecl, itemResult, iteratorItemResult, true, false, ERROR_FOREACH_ITEM);
145 }
146
147 // Update type of item
148
1/2
✓ Branch 0 (192→193) taken 100 times.
✗ Branch 1 (192→344) not taken.
100 itemVarSymbol->updateType(itemType, true);
149
150 // Visit body
151
1/2
✓ Branch 0 (193→194) taken 100 times.
✗ Branch 1 (193→342) not taken.
100 visit(node->body);
152
153
1/2
✓ Branch 0 (195→196) taken 100 times.
✗ Branch 1 (195→343) not taken.
100 return nullptr;
154 104 }
155
156 678 std::any TypeChecker::visitWhileLoop(WhileLoopNode *node) {
157 // Change to while body scope
158
2/4
✓ Branch 0 (2→3) taken 678 times.
✗ Branch 1 (2→33) not taken.
✓ Branch 2 (3→4) taken 678 times.
✗ Branch 3 (3→31) not taken.
678 ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::WHILE_BODY);
159
160 // Visit condition
161
3/4
✓ Branch 0 (5→6) taken 677 times.
✓ Branch 1 (5→37) taken 1 times.
✓ Branch 2 (6→7) taken 677 times.
✗ Branch 3 (6→35) not taken.
678 const QualType conditionType = std::any_cast<ExprResult>(visit(node->condition)).type;
162
2/6
✓ Branch 0 (8→9) taken 677 times.
✗ Branch 1 (8→49) not taken.
✗ Branch 2 (9→10) not taken.
✓ Branch 3 (9→12) taken 677 times.
✗ Branch 4 (10→11) not taken.
✗ Branch 5 (10→39) not taken.
677 HANDLE_UNRESOLVED_TYPE_PTR(conditionType)
163 // Check if condition evaluates to bool
164
3/4
✓ Branch 0 (12→13) taken 677 times.
✗ Branch 1 (12→49) not taken.
✓ Branch 2 (13→14) taken 1 times.
✓ Branch 3 (13→24) taken 676 times.
677 if (!conditionType.is(TY_BOOL))
165
4/8
✓ Branch 0 (16→17) taken 1 times.
✗ Branch 1 (16→42) not taken.
✓ Branch 2 (17→18) taken 1 times.
✗ Branch 3 (17→40) not taken.
✓ Branch 4 (20→21) taken 1 times.
✗ Branch 5 (20→46) not taken.
✓ Branch 6 (21→22) taken 1 times.
✗ Branch 7 (21→46) not taken.
3 SOFT_ERROR_ER(node->condition, CONDITION_MUST_BE_BOOL, "While loop condition must be of type bool")
166
167 // Visit body
168
1/2
✓ Branch 0 (24→25) taken 676 times.
✗ Branch 1 (24→47) not taken.
676 visit(node->body);
169
170
1/2
✓ Branch 0 (26→27) taken 676 times.
✗ Branch 1 (26→48) not taken.
676 return nullptr;
171 678 }
172
173 9 std::any TypeChecker::visitDoWhileLoop(DoWhileLoopNode *node) {
174 // Change to while body scope
175
2/4
✓ Branch 0 (2→3) taken 9 times.
✗ Branch 1 (2→33) not taken.
✓ Branch 2 (3→4) taken 9 times.
✗ Branch 3 (3→31) not taken.
9 ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::WHILE_BODY);
176
177 // Visit body
178
1/2
✓ Branch 0 (5→6) taken 9 times.
✗ Branch 1 (5→35) not taken.
9 visit(node->body);
179
180 // Visit condition
181
2/4
✓ Branch 0 (7→8) taken 9 times.
✗ Branch 1 (7→38) not taken.
✓ Branch 2 (8→9) taken 9 times.
✗ Branch 3 (8→36) not taken.
9 const QualType conditionType = std::any_cast<ExprResult>(visit(node->condition)).type;
182
2/6
✓ Branch 0 (10→11) taken 9 times.
✗ Branch 1 (10→49) not taken.
✗ Branch 2 (11→12) not taken.
✓ Branch 3 (11→14) taken 9 times.
✗ Branch 4 (12→13) not taken.
✗ Branch 5 (12→40) not taken.
9 HANDLE_UNRESOLVED_TYPE_PTR(conditionType)
183 // Check if condition evaluates to bool
184
3/4
✓ Branch 0 (14→15) taken 9 times.
✗ Branch 1 (14→49) not taken.
✓ Branch 2 (15→16) taken 1 times.
✓ Branch 3 (15→26) taken 8 times.
9 if (!conditionType.is(TY_BOOL))
185
4/8
✓ Branch 0 (18→19) taken 1 times.
✗ Branch 1 (18→43) not taken.
✓ Branch 2 (19→20) taken 1 times.
✗ Branch 3 (19→41) not taken.
✓ Branch 4 (22→23) taken 1 times.
✗ Branch 5 (22→47) not taken.
✓ Branch 6 (23→24) taken 1 times.
✗ Branch 7 (23→47) not taken.
3 SOFT_ERROR_ER(node->condition, CONDITION_MUST_BE_BOOL, "Do-While loop condition must be of type bool")
186
187
1/2
✓ Branch 0 (26→27) taken 8 times.
✗ Branch 1 (26→48) not taken.
8 return nullptr;
188 9 }
189
190 3914 std::any TypeChecker::visitIfStmt(IfStmtNode *node) {
191 // Change to then body scope
192
2/4
✓ Branch 0 (2→3) taken 3914 times.
✗ Branch 1 (2→41) not taken.
✓ Branch 2 (3→4) taken 3914 times.
✗ Branch 3 (3→39) not taken.
3914 ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::IF_ELSE_BODY);
193
194 // Visit condition
195
3/4
✓ Branch 0 (5→6) taken 3912 times.
✓ Branch 1 (5→45) taken 2 times.
✓ Branch 2 (6→7) taken 3912 times.
✗ Branch 3 (6→43) not taken.
3914 const QualType conditionType = std::any_cast<ExprResult>(visit(node->condition)).type;
196
4/6
✓ Branch 0 (8→9) taken 3912 times.
✗ Branch 1 (8→59) not taken.
✓ Branch 2 (9→10) taken 1 times.
✓ Branch 3 (9→12) taken 3911 times.
✓ Branch 4 (10→11) taken 1 times.
✗ Branch 5 (10→47) not taken.
3912 HANDLE_UNRESOLVED_TYPE_PTR(conditionType)
197 // Check if condition evaluates to bool
198
3/4
✓ Branch 0 (12→13) taken 3911 times.
✗ Branch 1 (12→59) not taken.
✓ Branch 2 (13→14) taken 2 times.
✓ Branch 3 (13→24) taken 3909 times.
3911 if (!conditionType.is(TY_BOOL))
199
4/8
✓ Branch 0 (16→17) taken 2 times.
✗ Branch 1 (16→50) not taken.
✓ Branch 2 (17→18) taken 2 times.
✗ Branch 3 (17→48) not taken.
✓ Branch 4 (20→21) taken 2 times.
✗ Branch 5 (20→54) not taken.
✓ Branch 6 (21→22) taken 2 times.
✗ Branch 7 (21→54) not taken.
6 SOFT_ERROR_ER(node->condition, CONDITION_MUST_BE_BOOL, "If condition must be of type bool")
200
201 // Warning for bool assignment
202
2/2
✓ Branch 0 (24→25) taken 1 times.
✓ Branch 1 (24→27) taken 3908 times.
3909 if (node->condition->op == AssignExprNode::AssignOp::OP_ASSIGN)
203
1/2
✓ Branch 0 (25→26) taken 1 times.
✗ Branch 1 (25→55) not taken.
1 sourceFile->compilerOutput.warnings.emplace_back(node->condition->codeLoc, BOOL_ASSIGN_AS_CONDITION,
204 "If you want to compare the values, use '=='");
205
206 // Visit body
207
1/2
✓ Branch 0 (27→28) taken 3909 times.
✗ Branch 1 (27→56) not taken.
3909 visit(node->thenBody);
208
209 // Leave then body scope
210
1/2
✓ Branch 0 (29→30) taken 3909 times.
✗ Branch 1 (29→59) not taken.
3909 scopeHandle.leaveScopeEarly();
211
212 // Visit else statement if existing
213
2/2
✓ Branch 0 (30→31) taken 147 times.
✓ Branch 1 (30→34) taken 3762 times.
3909 if (node->elseStmt)
214
1/2
✓ Branch 0 (31→32) taken 147 times.
✗ Branch 1 (31→57) not taken.
147 visit(node->elseStmt);
215
216
1/2
✓ Branch 0 (34→35) taken 3909 times.
✗ Branch 1 (34→58) not taken.
3909 return nullptr;
217 3914 }
218
219 147 std::any TypeChecker::visitElseStmt(ElseStmtNode *node) {
220 // Visit if statement in the case of an else if branch
221
2/2
✓ Branch 0 (2→3) taken 43 times.
✓ Branch 1 (2→7) taken 104 times.
147 if (node->isElseIf) {
222
1/2
✓ Branch 0 (3→4) taken 43 times.
✗ Branch 1 (3→16) not taken.
43 visit(node->ifStmt);
223
1/2
✓ Branch 0 (5→6) taken 43 times.
✗ Branch 1 (5→17) not taken.
43 return nullptr;
224 }
225
226 // Change to else body scope
227
2/4
✓ Branch 0 (7→8) taken 104 times.
✗ Branch 1 (7→20) not taken.
✓ Branch 2 (8→9) taken 104 times.
✗ Branch 3 (8→18) not taken.
104 ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::IF_ELSE_BODY);
228
229 // Visit body
230
1/2
✓ Branch 0 (10→11) taken 104 times.
✗ Branch 1 (10→22) not taken.
104 visit(node->body);
231
232
1/2
✓ Branch 0 (12→13) taken 104 times.
✗ Branch 1 (12→23) not taken.
104 return nullptr;
233 104 }
234
235 12 std::any TypeChecker::visitSwitchStmt(SwitchStmtNode *node) {
236 // Check expression type
237
2/4
✓ Branch 0 (2→3) taken 12 times.
✗ Branch 1 (2→56) not taken.
✓ Branch 2 (3→4) taken 12 times.
✗ Branch 3 (3→54) not taken.
12 const QualType exprType = std::any_cast<ExprResult>(visit(node->assignExpr)).type;
238
2/6
✓ Branch 0 (5→6) taken 12 times.
✗ Branch 1 (5→83) not taken.
✗ Branch 2 (6→7) not taken.
✓ Branch 3 (6→9) taken 12 times.
✗ Branch 4 (7→8) not taken.
✗ Branch 5 (7→58) not taken.
12 HANDLE_UNRESOLVED_TYPE_PTR(exprType)
239
3/4
✓ Branch 0 (9→10) taken 12 times.
✗ Branch 1 (9→59) not taken.
✓ Branch 2 (10→11) taken 1 times.
✓ Branch 3 (10→21) taken 11 times.
12 if (!exprType.isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}))
240
4/8
✓ Branch 0 (13→14) taken 1 times.
✗ Branch 1 (13→62) not taken.
✓ Branch 2 (14→15) taken 1 times.
✗ Branch 3 (14→60) not taken.
✓ Branch 4 (17→18) taken 1 times.
✗ Branch 5 (17→66) not taken.
✓ Branch 6 (18→19) taken 1 times.
✗ Branch 7 (18→66) not taken.
3 SOFT_ERROR_ER(node->assignExpr, SWITCH_EXPR_MUST_BE_PRIMITIVE,
241 "Switch expression must be of int, short, long, byte, char or bool type")
242
243 // Visit children
244
1/2
✓ Branch 0 (21→22) taken 11 times.
✗ Branch 1 (21→67) not taken.
11 visitChildren(node);
245
246 // Check if case constant types match switch expression type
247
2/2
✓ Branch 0 (49→25) taken 53 times.
✓ Branch 1 (49→50) taken 9 times.
62 for (const CaseBranchNode *caseBranchNode : node->caseBranches)
248
2/2
✓ Branch 0 (46→28) taken 70 times.
✓ Branch 1 (46→47) taken 51 times.
121 for (CaseConstantNode *constantNode : caseBranchNode->caseConstants) {
249
2/4
✓ Branch 0 (29→30) taken 70 times.
✗ Branch 1 (29→70) not taken.
✓ Branch 2 (30→31) taken 70 times.
✗ Branch 3 (30→68) not taken.
70 const QualType constantType = std::any_cast<ExprResult>(visit(constantNode)).type;
250
3/4
✓ Branch 0 (32→33) taken 70 times.
✗ Branch 1 (32→79) not taken.
✓ Branch 2 (33→34) taken 2 times.
✓ Branch 3 (33→44) taken 68 times.
70 if (!constantType.matches(exprType, false, true, true))
251
4/8
✓ Branch 0 (36→37) taken 2 times.
✗ Branch 1 (36→74) not taken.
✓ Branch 2 (37→38) taken 2 times.
✗ Branch 3 (37→72) not taken.
✓ Branch 4 (40→41) taken 2 times.
✗ Branch 5 (40→78) not taken.
✓ Branch 6 (41→42) taken 2 times.
✗ Branch 7 (41→78) not taken.
6 SOFT_ERROR_ER(constantNode, SWITCH_CASE_TYPE_MISMATCH, "Case value type does not match the switch expression type")
252 }
253
254
1/2
✓ Branch 0 (50→51) taken 9 times.
✗ Branch 1 (50→82) not taken.
9 return nullptr;
255 }
256
257 53 std::any TypeChecker::visitCaseBranch(CaseBranchNode *node) {
258 // Change to case body scope
259
2/4
✓ Branch 0 (2→3) taken 53 times.
✗ Branch 1 (2→21) not taken.
✓ Branch 2 (3→4) taken 53 times.
✗ Branch 3 (3→19) not taken.
53 ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::CASE_BODY);
260
261 // Visit constant list
262
2/2
✓ Branch 0 (12→7) taken 70 times.
✓ Branch 1 (12→13) taken 53 times.
123 for (CaseConstantNode *constant : node->caseConstants)
263
1/2
✓ Branch 0 (8→9) taken 70 times.
✗ Branch 1 (8→23) not taken.
70 visit(constant);
264
265 // Visit body
266
1/2
✓ Branch 0 (13→14) taken 53 times.
✗ Branch 1 (13→25) not taken.
53 visit(node->body);
267
268
1/2
✓ Branch 0 (15→16) taken 53 times.
✗ Branch 1 (15→26) not taken.
106 return nullptr;
269 53 }
270
271 140 std::any TypeChecker::visitCaseConstant(CaseConstantNode *node) {
272 // If we have a normal constant, we can take the symbol type from there
273
2/2
✓ Branch 0 (2→3) taken 36 times.
✓ Branch 1 (2→4) taken 104 times.
140 if (node->constant)
274 36 return visit(node->constant);
275
276 // Check if a local or global variable can be found by searching for the name
277
2/2
✓ Branch 0 (5→6) taken 30 times.
✓ Branch 1 (5→11) taken 74 times.
104 if (node->identifierFragments.size() == 1)
278 60 node->entry = currentScope->lookup(node->identifierFragments.back());
279
280 // If no local or global was found, search in the name registry
281
2/2
✓ Branch 0 (11→12) taken 37 times.
✓ Branch 1 (11→24) taken 67 times.
104 if (!node->entry) {
282 37 const NameRegistryEntry *registryEntry = sourceFile->getNameRegistryEntry(node->fqIdentifier);
283
1/2
✗ Branch 0 (13→14) not taken.
✓ Branch 1 (13→23) taken 37 times.
37 if (!registryEntry)
284 SOFT_ERROR_ER(node, REFERENCED_UNDEFINED_VARIABLE, "The variable '" + node->fqIdentifier + "' could not be found")
285 37 node->entry = registryEntry->targetEntry;
286 }
287
1/2
✗ Branch 0 (24→25) not taken.
✓ Branch 1 (24→26) taken 104 times.
104 assert(node->entry != nullptr);
288
289 // Check for the correct type
290 104 const QualType &qualType = node->entry->getQualType();
291
3/4
✓ Branch 0 (27→28) taken 104 times.
✗ Branch 1 (27→51) not taken.
✓ Branch 2 (28→29) taken 2 times.
✓ Branch 3 (28→39) taken 102 times.
104 if (!qualType.isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}))
292
4/8
✓ Branch 0 (31→32) taken 2 times.
✗ Branch 1 (31→54) not taken.
✓ Branch 2 (32→33) taken 2 times.
✗ Branch 3 (32→52) not taken.
✓ Branch 4 (35→36) taken 2 times.
✗ Branch 5 (35→58) not taken.
✓ Branch 6 (36→37) taken 2 times.
✗ Branch 7 (36→58) not taken.
6 SOFT_ERROR_ER(node, CASE_CONSTANT_INVALID_TYPE, "Case constants must be of type int, short, long, byte, char, bool or enum")
293
294
2/4
✓ Branch 0 (39→40) taken 102 times.
✗ Branch 1 (39→59) not taken.
✓ Branch 2 (40→41) taken 102 times.
✗ Branch 3 (40→59) not taken.
102 return ExprResult{node->setEvaluatedSymbolType(qualType, manIdx)};
295 }
296
297 6 std::any TypeChecker::visitDefaultBranch(DefaultBranchNode *node) {
298 // Change to default body scope
299
2/4
✓ Branch 0 (2→3) taken 6 times.
✗ Branch 1 (2→13) not taken.
✓ Branch 2 (3→4) taken 6 times.
✗ Branch 3 (3→11) not taken.
6 ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::DEFAULT_BODY);
300
301 // Visit body
302
1/2
✓ Branch 0 (5→6) taken 6 times.
✗ Branch 1 (5→15) not taken.
6 visit(node->body);
303
304
1/2
✓ Branch 0 (7→8) taken 6 times.
✗ Branch 1 (7→16) not taken.
12 return nullptr;
305 6 }
306
307 27 std::any TypeChecker::visitAnonymousBlockStmt(AnonymousBlockStmtNode *node) {
308 // Change to anonymous scope body scope
309
2/4
✓ Branch 0 (2→3) taken 27 times.
✗ Branch 1 (2→13) not taken.
✓ Branch 2 (3→4) taken 27 times.
✗ Branch 3 (3→11) not taken.
27 ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::ANONYMOUS_BLOCK_BODY);
310
311 // Visit body
312
1/2
✓ Branch 0 (5→6) taken 27 times.
✗ Branch 1 (5→15) not taken.
27 visit(node->body);
313
314
1/2
✓ Branch 0 (7→8) taken 27 times.
✗ Branch 1 (7→16) not taken.
54 return nullptr;
315 27 }
316
317 } // namespace spice::compiler
318