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 | 2501 | std::any TypeChecker::visitMainFctDef(MainFctDefNode *node) { | |
| 11 |
2/2✓ Branch 2 → 3 taken 1172 times.
✓ Branch 2 → 4 taken 1329 times.
|
2501 | if (typeCheckerMode == TC_MODE_PRE) |
| 12 | 1172 | return visitMainFctDefPrepare(node); | |
| 13 | else | ||
| 14 | 1329 | return visitMainFctDefCheck(node); | |
| 15 | } | ||
| 16 | |||
| 17 | 154472 | std::any TypeChecker::visitFctDef(FctDefNode *node) { | |
| 18 |
2/2✓ Branch 2 → 3 taken 48724 times.
✓ Branch 2 → 4 taken 105748 times.
|
154472 | if (typeCheckerMode == TC_MODE_PRE) |
| 19 | 48724 | return visitFctDefPrepare(node); | |
| 20 | else | ||
| 21 | 105748 | return visitFctDefCheck(node); | |
| 22 | } | ||
| 23 | |||
| 24 | 94899 | std::any TypeChecker::visitProcDef(ProcDefNode *node) { | |
| 25 |
2/2✓ Branch 2 → 3 taken 29248 times.
✓ Branch 2 → 4 taken 65651 times.
|
94899 | if (typeCheckerMode == TC_MODE_PRE) |
| 26 | 29248 | return visitProcDefPrepare(node); | |
| 27 | else | ||
| 28 | 65651 | return visitProcDefCheck(node); | |
| 29 | } | ||
| 30 | |||
| 31 | 22231 | std::any TypeChecker::visitStructDef(StructDefNode *node) { | |
| 32 |
2/2✓ Branch 2 → 3 taken 7457 times.
✓ Branch 2 → 4 taken 14774 times.
|
22231 | if (typeCheckerMode == TC_MODE_PRE) |
| 33 | 7457 | return visitStructDefPrepare(node); | |
| 34 | else | ||
| 35 | 14774 | return visitStructDefCheck(node); | |
| 36 | } | ||
| 37 | |||
| 38 | 1773 | std::any TypeChecker::visitInterfaceDef(InterfaceDefNode *node) { | |
| 39 |
2/2✓ Branch 2 → 3 taken 801 times.
✓ Branch 2 → 4 taken 972 times.
|
1773 | if (typeCheckerMode == TC_MODE_PRE) |
| 40 | 801 | return visitInterfaceDefPrepare(node); | |
| 41 |
1/2✓ Branch 4 → 5 taken 972 times.
✗ Branch 4 → 8 not taken.
|
1944 | return nullptr; |
| 42 | } | ||
| 43 | |||
| 44 | 154 | std::any TypeChecker::visitUnionDef(UnionDefNode *node) { | |
| 45 |
2/2✓ Branch 2 → 3 taken 64 times.
✓ Branch 2 → 4 taken 90 times.
|
154 | if (typeCheckerMode == TC_MODE_PRE) |
| 46 | 64 | return visitUnionDefPrepare(node); | |
| 47 | else | ||
| 48 | 90 | 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 | 2046 | void TypeChecker::assignDeferredOpaqueType(SymbolTableEntry *entry) { | |
| 63 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2046 times.
|
2046 | assert(entry->getQualType().is(TY_INVALID)); |
| 64 | 2046 | ASTNode *declNode = entry->declNode; | |
| 65 |
3/4✓ Branch 6 → 7 taken 2046 times.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 2012 times.
✓ Branch 9 → 18 taken 34 times.
|
2046 | if (const auto *structDef = dynamic_cast<StructDefNode *>(declNode)) { |
| 66 |
1/2✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 2012 times.
|
2012 | if (structDef->hasTemplateTypes) |
| 67 | ✗ | return; | |
| 68 | 2012 | const TypeChainElementData data = {.bodyScope = structDef->structScope}; | |
| 69 |
1/2✓ Branch 13 → 14 taken 2012 times.
✗ Branch 13 → 60 not taken.
|
2012 | const Type *type = TypeRegistry::getOrInsert(TY_STRUCT, structDef->structName, structDef->typeId, data, {}); |
| 70 |
2/4✓ Branch 15 → 16 taken 2012 times.
✗ Branch 15 → 63 not taken.
✓ Branch 16 → 17 taken 2012 times.
✗ Branch 16 → 63 not taken.
|
2012 | entry->updateType(QualType(type, structDef->qualifiers), false); |
| 71 |
3/4✓ Branch 18 → 19 taken 34 times.
✗ Branch 18 → 20 not taken.
✓ Branch 21 → 22 taken 30 times.
✓ Branch 21 → 30 taken 4 times.
|
34 | } else if (const auto *interfaceDef = dynamic_cast<InterfaceDefNode *>(declNode)) { |
| 72 |
1/2✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 30 times.
|
30 | if (interfaceDef->hasTemplateTypes) |
| 73 | ✗ | return; | |
| 74 | 30 | const TypeChainElementData data = {.bodyScope = interfaceDef->interfaceScope}; | |
| 75 |
1/2✓ Branch 25 → 26 taken 30 times.
✗ Branch 25 → 65 not taken.
|
30 | const Type *type = TypeRegistry::getOrInsert(TY_INTERFACE, interfaceDef->interfaceName, interfaceDef->typeId, data, {}); |
| 76 |
2/4✓ Branch 27 → 28 taken 30 times.
✗ Branch 27 → 68 not taken.
✓ Branch 28 → 29 taken 30 times.
✗ Branch 28 → 68 not taken.
|
30 | entry->updateType(QualType(type, interfaceDef->qualifiers), false); |
| 77 |
2/4✓ Branch 30 → 31 taken 4 times.
✗ Branch 30 → 32 not taken.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 42 taken 4 times.
|
4 | } 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 4 times.
✗ Branch 42 → 44 not taken.
✓ Branch 45 → 46 taken 2 times.
✓ Branch 45 → 52 taken 2 times.
|
4 | } else if (const auto *enumDef = dynamic_cast<EnumDefNode *>(declNode)) { |
| 84 | 2 | const TypeChainElementData data = {.bodyScope = enumDef->enumScope}; | |
| 85 |
1/2✓ Branch 47 → 48 taken 2 times.
✗ Branch 47 → 75 not taken.
|
2 | const Type *type = TypeRegistry::getOrInsert(TY_ENUM, enumDef->enumName, enumDef->typeId, data, {}); |
| 86 |
2/4✓ Branch 49 → 50 taken 2 times.
✗ Branch 49 → 78 not taken.
✓ Branch 50 → 51 taken 2 times.
✗ Branch 50 → 78 not taken.
|
2 | 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 | 3575 | std::any TypeChecker::visitEnumDef(EnumDefNode *node) { | |
| 95 |
2/2✓ Branch 2 → 3 taken 1226 times.
✓ Branch 2 → 4 taken 2349 times.
|
3575 | if (typeCheckerMode == TC_MODE_PRE) |
| 96 | 1226 | return visitEnumDefPrepare(node); | |
| 97 |
1/2✓ Branch 4 → 5 taken 2349 times.
✗ Branch 4 → 8 not taken.
|
4698 | return nullptr; |
| 98 | } | ||
| 99 | |||
| 100 | 14349 | std::any TypeChecker::visitGenericTypeDef(GenericTypeDefNode *node) { | |
| 101 |
2/2✓ Branch 2 → 3 taken 4495 times.
✓ Branch 2 → 4 taken 9854 times.
|
14349 | if (typeCheckerMode == TC_MODE_PRE) |
| 102 | 4495 | return visitGenericTypeDefPrepare(node); | |
| 103 |
1/2✓ Branch 4 → 5 taken 9854 times.
✗ Branch 4 → 8 not taken.
|
19708 | return nullptr; |
| 104 | } | ||
| 105 | |||
| 106 | 1985 | std::any TypeChecker::visitAliasDef(AliasDefNode *node) { | |
| 107 |
2/2✓ Branch 2 → 3 taken 703 times.
✓ Branch 2 → 4 taken 1282 times.
|
1985 | if (typeCheckerMode == TC_MODE_PRE) |
| 108 | 703 | return visitAliasDefPrepare(node); | |
| 109 |
1/2✓ Branch 4 → 5 taken 1282 times.
✗ Branch 4 → 8 not taken.
|
2564 | return nullptr; |
| 110 | } | ||
| 111 | |||
| 112 | 15857 | std::any TypeChecker::visitGlobalVarDef(GlobalVarDefNode *node) { | |
| 113 |
2/2✓ Branch 2 → 3 taken 5935 times.
✓ Branch 2 → 4 taken 9922 times.
|
15857 | if (typeCheckerMode == TC_MODE_PRE) |
| 114 | 5935 | return visitGlobalVarDefPrepare(node); | |
| 115 |
1/2✓ Branch 4 → 5 taken 9922 times.
✗ Branch 4 → 8 not taken.
|
19844 | return nullptr; |
| 116 | } | ||
| 117 | |||
| 118 | 28504 | std::any TypeChecker::visitExtDecl(ExtDeclNode *node) { | |
| 119 |
2/2✓ Branch 2 → 3 taken 8883 times.
✓ Branch 2 → 4 taken 19621 times.
|
28504 | if (typeCheckerMode == TC_MODE_PRE) |
| 120 | 8883 | return visitExtDeclPrepare(node); | |
| 121 |
1/2✓ Branch 4 → 5 taken 19621 times.
✗ Branch 4 → 8 not taken.
|
39242 | return nullptr; |
| 122 | } | ||
| 123 | |||
| 124 | 17221 | std::any TypeChecker::visitImportDef(ImportDefNode *node) { | |
| 125 |
2/2✓ Branch 2 → 3 taken 5892 times.
✓ Branch 2 → 4 taken 11329 times.
|
17221 | if (typeCheckerMode == TC_MODE_PRE) |
| 126 | 5892 | return visitImportDefPrepare(node); | |
| 127 |
1/2✓ Branch 4 → 5 taken 11329 times.
✗ Branch 4 → 8 not taken.
|
22658 | return nullptr; |
| 128 | } | ||
| 129 | |||
| 130 | } // namespace spice::compiler | ||
| 131 |