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 | 2613 | std::any TypeChecker::visitMainFctDef(MainFctDefNode *node) { | |
| 11 |
2/2✓ Branch 2 → 3 taken 1225 times.
✓ Branch 2 → 4 taken 1388 times.
|
2613 | if (typeCheckerMode == TC_MODE_PRE) |
| 12 | 1225 | return visitMainFctDefPrepare(node); | |
| 13 | else | ||
| 14 | 1388 | return visitMainFctDefCheck(node); | |
| 15 | } | ||
| 16 | |||
| 17 | 204124 | std::any TypeChecker::visitFctDef(FctDefNode *node) { | |
| 18 |
2/2✓ Branch 2 → 3 taken 65722 times.
✓ Branch 2 → 4 taken 138402 times.
|
204124 | if (typeCheckerMode == TC_MODE_PRE) |
| 19 | 65722 | return visitFctDefPrepare(node); | |
| 20 | else | ||
| 21 | 138402 | return visitFctDefCheck(node); | |
| 22 | } | ||
| 23 | |||
| 24 | 114221 | std::any TypeChecker::visitProcDef(ProcDefNode *node) { | |
| 25 |
2/2✓ Branch 2 → 3 taken 35747 times.
✓ Branch 2 → 4 taken 78474 times.
|
114221 | if (typeCheckerMode == TC_MODE_PRE) |
| 26 | 35747 | return visitProcDefPrepare(node); | |
| 27 | else | ||
| 28 | 78474 | return visitProcDefCheck(node); | |
| 29 | } | ||
| 30 | |||
| 31 | 28575 | std::any TypeChecker::visitStructDef(StructDefNode *node) { | |
| 32 |
2/2✓ Branch 2 → 3 taken 9653 times.
✓ Branch 2 → 4 taken 18922 times.
|
28575 | if (typeCheckerMode == TC_MODE_PRE) |
| 33 | 9653 | return visitStructDefPrepare(node); | |
| 34 | else | ||
| 35 | 18922 | return visitStructDefCheck(node); | |
| 36 | } | ||
| 37 | |||
| 38 | 2351 | std::any TypeChecker::visitInterfaceDef(InterfaceDefNode *node) { | |
| 39 |
2/2✓ Branch 2 → 3 taken 1015 times.
✓ Branch 2 → 4 taken 1336 times.
|
2351 | if (typeCheckerMode == TC_MODE_PRE) |
| 40 | 1015 | return visitInterfaceDefPrepare(node); | |
| 41 |
1/2✓ Branch 4 → 5 taken 1336 times.
✗ Branch 4 → 8 not taken.
|
2672 | return nullptr; |
| 42 | } | ||
| 43 | |||
| 44 | 184 | std::any TypeChecker::visitUnionDef(UnionDefNode *node) { | |
| 45 |
2/2✓ Branch 2 → 3 taken 74 times.
✓ Branch 2 → 4 taken 110 times.
|
184 | if (typeCheckerMode == TC_MODE_PRE) |
| 46 | 74 | return visitUnionDefPrepare(node); | |
| 47 | else | ||
| 48 | 110 | return visitUnionDefCheck(node); | |
| 49 | } | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Assign the opaque type to a struct, interface, enum or alias that is referenced before it has been prepared. This | ||
| 53 | * effectively acts as an implicit forward declaration and is what makes circular imports work: two types in mutually | ||
| 54 | * importing files can reference each other, so neither can be prepared strictly before the other. The full prepare pass | ||
| 55 | * (visitStructDefPrepare / visitInterfaceDefPrepare / visitEnumDefPrepare / visitAliasDefPrepare) assigns the identical | ||
| 56 | * interned type later and additionally fills in the body scope and manifestations. | ||
| 57 | * | ||
| 58 | * Only non-generic structs/interfaces can be pre-declared this way, since the opaque type carries no template types. | ||
| 59 | * | ||
| 60 | * @param entry Symbol table entry of the referenced struct, interface, enum or alias (its type must still be invalid) | ||
| 61 | */ | ||
| 62 | 2708 | void TypeChecker::assignDeferredOpaqueType(SymbolTableEntry *entry) { | |
| 63 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2708 times.
|
2708 | assert(entry->getQualType().is(TY_INVALID)); |
| 64 | 2708 | ASTNode *declNode = entry->declNode; | |
| 65 |
3/4✓ Branch 6 → 7 taken 2708 times.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 2548 times.
✓ Branch 9 → 18 taken 160 times.
|
2708 | if (const auto *structDef = dynamic_cast<StructDefNode *>(declNode)) { |
| 66 |
1/2✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 2548 times.
|
2548 | if (structDef->hasTemplateTypes) |
| 67 | ✗ | return; | |
| 68 | 2548 | const TypeChainElementData data = {.bodyScope = structDef->structScope}; | |
| 69 |
1/2✓ Branch 13 → 14 taken 2548 times.
✗ Branch 13 → 60 not taken.
|
2548 | const Type *type = TypeRegistry::getOrInsert(TY_STRUCT, structDef->structName, structDef->typeId, data, {}); |
| 70 |
2/4✓ Branch 15 → 16 taken 2548 times.
✗ Branch 15 → 63 not taken.
✓ Branch 16 → 17 taken 2548 times.
✗ Branch 16 → 63 not taken.
|
2548 | entry->updateType(QualType(type, structDef->qualifiers), false); |
| 71 |
3/4✓ Branch 18 → 19 taken 160 times.
✗ Branch 18 → 20 not taken.
✓ Branch 21 → 22 taken 152 times.
✓ Branch 21 → 30 taken 8 times.
|
160 | } else if (const auto *interfaceDef = dynamic_cast<InterfaceDefNode *>(declNode)) { |
| 72 |
1/2✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 152 times.
|
152 | if (interfaceDef->hasTemplateTypes) |
| 73 | ✗ | return; | |
| 74 | 152 | const TypeChainElementData data = {.bodyScope = interfaceDef->interfaceScope}; | |
| 75 |
1/2✓ Branch 25 → 26 taken 152 times.
✗ Branch 25 → 65 not taken.
|
152 | const Type *type = TypeRegistry::getOrInsert(TY_INTERFACE, interfaceDef->interfaceName, interfaceDef->typeId, data, {}); |
| 76 |
2/4✓ Branch 27 → 28 taken 152 times.
✗ Branch 27 → 68 not taken.
✓ Branch 28 → 29 taken 152 times.
✗ Branch 28 → 68 not taken.
|
152 | entry->updateType(QualType(type, interfaceDef->qualifiers), false); |
| 77 |
2/4✓ Branch 30 → 31 taken 8 times.
✗ Branch 30 → 32 not taken.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 42 taken 8 times.
|
8 | } else if (const auto *unionDef = dynamic_cast<UnionDefNode *>(declNode)) { |
| 78 | ✗ | if (unionDef->hasTemplateTypes) | |
| 79 | ✗ | return; | |
| 80 | ✗ | const TypeChainElementData data = {.bodyScope = unionDef->unionScope}; | |
| 81 | ✗ | const Type *type = TypeRegistry::getOrInsert(TY_UNION, unionDef->unionName, unionDef->typeId, data, {}); | |
| 82 | ✗ | entry->updateType(QualType(type, unionDef->qualifiers), false); | |
| 83 |
3/4✓ Branch 42 → 43 taken 8 times.
✗ Branch 42 → 44 not taken.
✓ Branch 45 → 46 taken 6 times.
✓ Branch 45 → 52 taken 2 times.
|
8 | } else if (const auto *enumDef = dynamic_cast<EnumDefNode *>(declNode)) { |
| 84 | 6 | const TypeChainElementData data = {.bodyScope = enumDef->enumScope}; | |
| 85 |
1/2✓ Branch 47 → 48 taken 6 times.
✗ Branch 47 → 75 not taken.
|
6 | const Type *type = TypeRegistry::getOrInsert(TY_ENUM, enumDef->enumName, enumDef->typeId, data, {}); |
| 86 |
2/4✓ Branch 49 → 50 taken 6 times.
✗ Branch 49 → 78 not taken.
✓ Branch 50 → 51 taken 6 times.
✗ Branch 50 → 78 not taken.
|
6 | entry->updateType(QualType(type, enumDef->qualifiers), false); |
| 87 |
2/4✓ Branch 52 → 53 taken 2 times.
✗ Branch 52 → 54 not taken.
✓ Branch 55 → 56 taken 2 times.
✗ Branch 55 → 59 not taken.
|
2 | } else if (auto *aliasDef = dynamic_cast<AliasDefNode *>(declNode)) { |
| 88 | // An alias additionally needs its aliased type resolved, so prepare it fully on demand. visitAliasDefPrepare is | ||
| 89 | // idempotent: the real prepare pass for the alias's own file skips it once the type is no longer invalid. | ||
| 90 |
1/2✓ Branch 56 → 57 taken 2 times.
✗ Branch 56 → 80 not taken.
|
2 | visitAliasDefPrepare(aliasDef); |
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | 5673 | std::any TypeChecker::visitEnumDef(EnumDefNode *node) { | |
| 95 |
2/2✓ Branch 2 → 3 taken 1964 times.
✓ Branch 2 → 4 taken 3709 times.
|
5673 | if (typeCheckerMode == TC_MODE_PRE) |
| 96 | 1964 | return visitEnumDefPrepare(node); | |
| 97 |
1/2✓ Branch 4 → 5 taken 3709 times.
✗ Branch 4 → 8 not taken.
|
7418 | return nullptr; |
| 98 | } | ||
| 99 | |||
| 100 | 16223 | std::any TypeChecker::visitGenericTypeDef(GenericTypeDefNode *node) { | |
| 101 |
2/2✓ Branch 2 → 3 taken 5137 times.
✓ Branch 2 → 4 taken 11086 times.
|
16223 | if (typeCheckerMode == TC_MODE_PRE) |
| 102 | 5137 | return visitGenericTypeDefPrepare(node); | |
| 103 |
1/2✓ Branch 4 → 5 taken 11086 times.
✗ Branch 4 → 8 not taken.
|
22172 | return nullptr; |
| 104 | } | ||
| 105 | |||
| 106 | 3377 | std::any TypeChecker::visitAliasDef(AliasDefNode *node) { | |
| 107 |
2/2✓ Branch 2 → 3 taken 1185 times.
✓ Branch 2 → 4 taken 2192 times.
|
3377 | if (typeCheckerMode == TC_MODE_PRE) |
| 108 | 1185 | return visitAliasDefPrepare(node); | |
| 109 |
1/2✓ Branch 4 → 5 taken 2192 times.
✗ Branch 4 → 8 not taken.
|
4384 | return nullptr; |
| 110 | } | ||
| 111 | |||
| 112 | 25863 | std::any TypeChecker::visitGlobalVarDef(GlobalVarDefNode *node) { | |
| 113 |
2/2✓ Branch 2 → 3 taken 10241 times.
✓ Branch 2 → 4 taken 15622 times.
|
25863 | if (typeCheckerMode == TC_MODE_PRE) |
| 114 | 10241 | return visitGlobalVarDefPrepare(node); | |
| 115 |
1/2✓ Branch 4 → 5 taken 15622 times.
✗ Branch 4 → 8 not taken.
|
31244 | return nullptr; |
| 116 | } | ||
| 117 | |||
| 118 | 38580 | std::any TypeChecker::visitExtDecl(ExtDeclNode *node) { | |
| 119 |
2/2✓ Branch 2 → 3 taken 12363 times.
✓ Branch 2 → 4 taken 26217 times.
|
38580 | if (typeCheckerMode == TC_MODE_PRE) |
| 120 | 12363 | return visitExtDeclPrepare(node); | |
| 121 |
1/2✓ Branch 4 → 5 taken 26217 times.
✗ Branch 4 → 8 not taken.
|
52434 | return nullptr; |
| 122 | } | ||
| 123 | |||
| 124 | 27357 | std::any TypeChecker::visitImportDef(ImportDefNode *node) { | |
| 125 |
2/2✓ Branch 2 → 3 taken 9466 times.
✓ Branch 2 → 4 taken 17891 times.
|
27357 | if (typeCheckerMode == TC_MODE_PRE) |
| 126 | 9466 | return visitImportDefPrepare(node); | |
| 127 |
1/2✓ Branch 4 → 5 taken 17891 times.
✗ Branch 4 → 8 not taken.
|
35782 | return nullptr; |
| 128 | } | ||
| 129 | |||
| 130 | } // namespace spice::compiler | ||
| 131 |