GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 96.9% 63 / 0 / 65
Functions: 100.0% 12 / 0 / 12
Branches: 67.9% 53 / 0 / 78

src/typechecker/TypeCheckerTopLevelDefinitions.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "TypeChecker.h"
4
5 #include <ast/ASTNodes.h>
6 #include <global/TypeRegistry.h>
7
8 namespace spice::compiler {
9
10 1086 std::any TypeChecker::visitMainFctDef(MainFctDefNode *node) {
11
2/2
✓ Branch 2 → 3 taken 510 times.
✓ Branch 2 → 4 taken 576 times.
1086 if (typeCheckerMode == TC_MODE_PRE)
12 510 return visitMainFctDefPrepare(node);
13 else
14 576 return visitMainFctDefCheck(node);
15 }
16
17 62627 std::any TypeChecker::visitFctDef(FctDefNode *node) {
18
2/2
✓ Branch 2 → 3 taken 20207 times.
✓ Branch 2 → 4 taken 42420 times.
62627 if (typeCheckerMode == TC_MODE_PRE)
19 20207 return visitFctDefPrepare(node);
20 else
21 42420 return visitFctDefCheck(node);
22 }
23
24 33914 std::any TypeChecker::visitProcDef(ProcDefNode *node) {
25
2/2
✓ Branch 2 → 3 taken 10796 times.
✓ Branch 2 → 4 taken 23118 times.
33914 if (typeCheckerMode == TC_MODE_PRE)
26 10796 return visitProcDefPrepare(node);
27 else
28 23118 return visitProcDefCheck(node);
29 }
30
31 8651 std::any TypeChecker::visitStructDef(StructDefNode *node) {
32
2/2
✓ Branch 2 → 3 taken 2989 times.
✓ Branch 2 → 4 taken 5662 times.
8651 if (typeCheckerMode == TC_MODE_PRE)
33 2989 return visitStructDefPrepare(node);
34 else
35 5662 return visitStructDefCheck(node);
36 }
37
38 807 std::any TypeChecker::visitInterfaceDef(InterfaceDefNode *node) {
39
2/2
✓ Branch 2 → 3 taken 364 times.
✓ Branch 2 → 4 taken 443 times.
807 if (typeCheckerMode == TC_MODE_PRE)
40 364 return visitInterfaceDefPrepare(node);
41
1/2
✓ Branch 4 → 5 taken 443 times.
✗ Branch 4 → 8 not taken.
886 return nullptr;
42 }
43
44 /**
45 * Assign the opaque type to a struct, interface, enum or alias that is referenced before it has been prepared. This
46 * effectively acts as an implicit forward declaration and is what makes circular imports work: two types in mutually
47 * importing files can reference each other, so neither can be prepared strictly before the other. The full prepare pass
48 * (visitStructDefPrepare / visitInterfaceDefPrepare / visitEnumDefPrepare / visitAliasDefPrepare) assigns the identical
49 * interned type later and additionally fills in the body scope and manifestations.
50 *
51 * Only non-generic structs/interfaces can be pre-declared this way, since the opaque type carries no template types.
52 *
53 * @param entry Symbol table entry of the referenced struct, interface, enum or alias (its type must still be invalid)
54 */
55 1023 void TypeChecker::assignDeferredOpaqueType(SymbolTableEntry *entry) {
56
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1023 times.
1023 assert(entry->getQualType().is(TY_INVALID));
57 1023 ASTNode *declNode = entry->declNode;
58
3/4
✓ Branch 6 → 7 taken 1023 times.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 1006 times.
✓ Branch 9 → 18 taken 17 times.
1023 if (const auto *structDef = dynamic_cast<StructDefNode *>(declNode)) {
59
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 1006 times.
1006 if (structDef->hasTemplateTypes)
60 return;
61 1006 const TypeChainElementData data = {.bodyScope = structDef->structScope};
62
1/2
✓ Branch 13 → 14 taken 1006 times.
✗ Branch 13 → 48 not taken.
1006 const Type *type = TypeRegistry::getOrInsert(TY_STRUCT, structDef->structName, structDef->typeId, data, {});
63
2/4
✓ Branch 15 → 16 taken 1006 times.
✗ Branch 15 → 51 not taken.
✓ Branch 16 → 17 taken 1006 times.
✗ Branch 16 → 51 not taken.
1006 entry->updateType(QualType(type, structDef->qualifiers), false);
64
3/4
✓ Branch 18 → 19 taken 17 times.
✗ Branch 18 → 20 not taken.
✓ Branch 21 → 22 taken 15 times.
✓ Branch 21 → 30 taken 2 times.
17 } else if (const auto *interfaceDef = dynamic_cast<InterfaceDefNode *>(declNode)) {
65
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 15 times.
15 if (interfaceDef->hasTemplateTypes)
66 return;
67 15 const TypeChainElementData data = {.bodyScope = interfaceDef->interfaceScope};
68
1/2
✓ Branch 25 → 26 taken 15 times.
✗ Branch 25 → 53 not taken.
15 const Type *type = TypeRegistry::getOrInsert(TY_INTERFACE, interfaceDef->interfaceName, interfaceDef->typeId, data, {});
69
2/4
✓ Branch 27 → 28 taken 15 times.
✗ Branch 27 → 56 not taken.
✓ Branch 28 → 29 taken 15 times.
✗ Branch 28 → 56 not taken.
15 entry->updateType(QualType(type, interfaceDef->qualifiers), false);
70
3/4
✓ Branch 30 → 31 taken 2 times.
✗ Branch 30 → 32 not taken.
✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 40 taken 1 time.
2 } else if (const auto *enumDef = dynamic_cast<EnumDefNode *>(declNode)) {
71 1 const TypeChainElementData data = {.bodyScope = enumDef->enumScope};
72
1/2
✓ Branch 35 → 36 taken 1 time.
✗ Branch 35 → 58 not taken.
1 const Type *type = TypeRegistry::getOrInsert(TY_ENUM, enumDef->enumName, enumDef->typeId, data, {});
73
2/4
✓ Branch 37 → 38 taken 1 time.
✗ Branch 37 → 61 not taken.
✓ Branch 38 → 39 taken 1 time.
✗ Branch 38 → 61 not taken.
1 entry->updateType(QualType(type, enumDef->qualifiers), false);
74
2/4
✓ Branch 40 → 41 taken 1 time.
✗ Branch 40 → 42 not taken.
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 47 not taken.
1 } else if (auto *aliasDef = dynamic_cast<AliasDefNode *>(declNode)) {
75 // An alias additionally needs its aliased type resolved, so prepare it fully on demand. visitAliasDefPrepare is
76 // idempotent: the real prepare pass for the alias's own file skips it once the type is no longer invalid.
77
1/2
✓ Branch 44 → 45 taken 1 time.
✗ Branch 44 → 63 not taken.
1 visitAliasDefPrepare(aliasDef);
78 }
79 }
80
81 1061 std::any TypeChecker::visitEnumDef(EnumDefNode *node) {
82
2/2
✓ Branch 2 → 3 taken 369 times.
✓ Branch 2 → 4 taken 692 times.
1061 if (typeCheckerMode == TC_MODE_PRE)
83 369 return visitEnumDefPrepare(node);
84
1/2
✓ Branch 4 → 5 taken 692 times.
✗ Branch 4 → 8 not taken.
1384 return nullptr;
85 }
86
87 6103 std::any TypeChecker::visitGenericTypeDef(GenericTypeDefNode *node) {
88
2/2
✓ Branch 2 → 3 taken 1941 times.
✓ Branch 2 → 4 taken 4162 times.
6103 if (typeCheckerMode == TC_MODE_PRE)
89 1941 return visitGenericTypeDefPrepare(node);
90
1/2
✓ Branch 4 → 5 taken 4162 times.
✗ Branch 4 → 8 not taken.
8324 return nullptr;
91 }
92
93 958 std::any TypeChecker::visitAliasDef(AliasDefNode *node) {
94
2/2
✓ Branch 2 → 3 taken 341 times.
✓ Branch 2 → 4 taken 617 times.
958 if (typeCheckerMode == TC_MODE_PRE)
95 341 return visitAliasDefPrepare(node);
96
1/2
✓ Branch 4 → 5 taken 617 times.
✗ Branch 4 → 8 not taken.
1234 return nullptr;
97 }
98
99 6014 std::any TypeChecker::visitGlobalVarDef(GlobalVarDefNode *node) {
100
2/2
✓ Branch 2 → 3 taken 2373 times.
✓ Branch 2 → 4 taken 3641 times.
6014 if (typeCheckerMode == TC_MODE_PRE)
101 2373 return visitGlobalVarDefPrepare(node);
102
1/2
✓ Branch 4 → 5 taken 3641 times.
✗ Branch 4 → 8 not taken.
7282 return nullptr;
103 }
104
105 8715 std::any TypeChecker::visitExtDecl(ExtDeclNode *node) {
106
2/2
✓ Branch 2 → 3 taken 2978 times.
✓ Branch 2 → 4 taken 5737 times.
8715 if (typeCheckerMode == TC_MODE_PRE)
107 2978 return visitExtDeclPrepare(node);
108
1/2
✓ Branch 4 → 5 taken 5737 times.
✗ Branch 4 → 8 not taken.
11474 return nullptr;
109 }
110
111 7206 std::any TypeChecker::visitImportDef(ImportDefNode *node) {
112
2/2
✓ Branch 2 → 3 taken 2488 times.
✓ Branch 2 → 4 taken 4718 times.
7206 if (typeCheckerMode == TC_MODE_PRE)
113 2488 return visitImportDefPrepare(node);
114
1/2
✓ Branch 4 → 5 taken 4718 times.
✗ Branch 4 → 8 not taken.
9436 return nullptr;
115 }
116
117 } // namespace spice::compiler
118