Skip to content

Commit 3c164cb

Browse files
committed
WIP: TASK combine EnumMemberType into EnumInstanceType
this modeling is imo correct, as this will allow this in the future ``` Enum.A.value ``` `Enum.A` is an EnumInstanceType (which knows that its name is "A") while Enum is just an EnumStaticType if an enum is referenced like `enum: Enum` an unspecific instance (without known MemberName) will be used
1 parent 42224b5 commit 3c164cb

File tree

9 files changed

+120
-264
lines changed

9 files changed

+120
-264
lines changed

src/TypeSystem/Resolver/Access/AccessTypeResolver.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
use PackageFactory\ComponentEngine\Parser\Ast\AccessNode;
2727
use PackageFactory\ComponentEngine\TypeSystem\Resolver\Expression\ExpressionTypeResolver;
2828
use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface;
29-
use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumMemberType;
29+
use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumInstanceType;
3030
use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumStaticType;
3131
use PackageFactory\ComponentEngine\TypeSystem\Type\StructType\StructType;
3232
use PackageFactory\ComponentEngine\TypeSystem\TypeInterface;
@@ -45,13 +45,13 @@ public function resolveTypeOf(AccessNode $accessNode): TypeInterface
4545
$rootType = $expressionResolver->resolveTypeOf($accessNode->root);
4646

4747
return match ($rootType::class) {
48-
EnumStaticType::class => $this->createEnumMemberType($accessNode, $rootType),
48+
EnumStaticType::class => $this->createEnumInstanceMemberType($accessNode, $rootType),
4949
StructType::class => throw new \Exception('@TODO: StructType Access is not implemented'),
5050
default => throw new \Exception('@TODO Error: Cannot access on type ' . $rootType::class)
5151
};
5252
}
5353

54-
private function createEnumMemberType(AccessNode $accessNode, EnumStaticType $enumType): EnumMemberType
54+
private function createEnumInstanceMemberType(AccessNode $accessNode, EnumStaticType $enumType): EnumInstanceType
5555
{
5656
if (!(
5757
count($accessNode->chain->items) === 1

src/TypeSystem/Resolver/Match/MatchTypeResolver.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
use PackageFactory\ComponentEngine\TypeSystem\Resolver\Expression\ExpressionTypeResolver;
2828
use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface;
2929
use PackageFactory\ComponentEngine\TypeSystem\Type\BooleanType\BooleanType;
30-
use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumMemberType;
3130
use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumInstanceType;
3231
use PackageFactory\ComponentEngine\TypeSystem\Type\UnionType\UnionType;
3332
use PackageFactory\ComponentEngine\TypeSystem\TypeInterface;
@@ -106,12 +105,12 @@ private function resolveTypeOfEnumMatch(MatchNode $matchNode, EnumInstanceType $
106105
} else {
107106
foreach ($matchArmNode->left->items as $expressionNode) {
108107
$enumMemberType = $expressionTypeResolver->resolveTypeOf($expressionNode);
109-
if (!$enumMemberType instanceof EnumMemberType) {
108+
if (!$enumMemberType instanceof EnumInstanceType) {
110109
throw new \Error('@TODO Error: Cannot match enum with type of ' . $enumMemberType::class);
111110
}
112111

113-
if (!$enumMemberType->enumType->is($subjectEnumType)) {
114-
throw new \Error('@TODO Error: incompatible enum match: got ' . $enumMemberType->enumType->enumName . ' expected ' . $subjectEnumType->enumName);
112+
if (!$enumMemberType->enumStaticType->is($subjectEnumType->enumStaticType)) {
113+
throw new \Error('@TODO Error: incompatible enum match: got ' . $enumMemberType->enumStaticType->enumName . ' expected ' . $subjectEnumType->enumStaticType->enumName);
115114
}
116115

117116
if (isset($referencedEnumMembers[$enumMemberType->memberName])) {
@@ -128,7 +127,7 @@ private function resolveTypeOfEnumMatch(MatchNode $matchNode, EnumInstanceType $
128127
}
129128

130129
if (!$defaultArmPresent) {
131-
foreach ($subjectEnumType->getMemberNames() as $member) {
130+
foreach ($subjectEnumType->enumStaticType->getMemberNames() as $member) {
132131
if (!isset($referencedEnumMembers[$member])) {
133132
throw new \Error('@TODO Error: member ' . $member . ' not checked');
134133
}

src/TypeSystem/Type/EnumType/EnumInstanceType.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,33 @@
2626

2727
final class EnumInstanceType implements TypeInterface
2828
{
29-
use EnumTrait;
29+
private function __construct(
30+
public readonly EnumStaticType $enumStaticType,
31+
public readonly ?string $memberName
32+
) {
33+
if ($memberName !== null && !$enumStaticType->hasMember($memberName)) {
34+
throw new \Exception('@TODO cannot access member ' . $memberName . ' of enum ' . $this->enumStaticType->enumName);
35+
}
36+
}
37+
38+
public static function fromStaticEnumCreateUnspecificInstance(EnumStaticType $enumStaticType): self
39+
{
40+
return new self(
41+
enumStaticType: $enumStaticType,
42+
memberName: null
43+
);
44+
}
45+
46+
public static function fromStaticEnumAndMemberName(EnumStaticType $enumStaticType, string $enumMemberName): self
47+
{
48+
return new self(
49+
enumStaticType: $enumStaticType,
50+
memberName: $enumMemberName
51+
);
52+
}
53+
54+
public function is(TypeInterface $other): bool
55+
{
56+
return false;
57+
}
3058
}

src/TypeSystem/Type/EnumType/EnumMemberType.php

Lines changed: 0 additions & 39 deletions
This file was deleted.

src/TypeSystem/Type/EnumType/EnumStaticType.php

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,65 @@
2222

2323
namespace PackageFactory\ComponentEngine\TypeSystem\Type\EnumType;
2424

25+
use PackageFactory\ComponentEngine\Module\ModuleId;
26+
use PackageFactory\ComponentEngine\Parser\Ast\EnumDeclarationNode;
2527
use PackageFactory\ComponentEngine\TypeSystem\TypeInterface;
2628

2729
final class EnumStaticType implements TypeInterface
2830
{
29-
use EnumTrait;
30-
31+
public function __construct(
32+
public readonly string $enumName,
33+
private readonly ModuleId $moduleId,
34+
private readonly array $memberNameHashMap,
35+
) {
36+
}
37+
38+
public static function fromModuleIdAndDeclaration(ModuleId $moduleId, EnumDeclarationNode $enumDeclarationNode): self
39+
{
40+
$memberNameHashMap = [];
41+
foreach ($enumDeclarationNode->memberDeclarations->items as $memberDeclarationNode) {
42+
$memberNameHashMap[$memberDeclarationNode->name] = true;
43+
}
44+
45+
return new self(
46+
enumName: $enumDeclarationNode->enumName,
47+
moduleId: $moduleId,
48+
memberNameHashMap: $memberNameHashMap
49+
);
50+
}
51+
52+
public function getMemberNames(): array
53+
{
54+
return array_keys($this->memberNameHashMap);
55+
}
56+
57+
public function hasMember(string $memberName): bool
58+
{
59+
return array_key_exists($memberName, $this->memberNameHashMap);
60+
}
61+
62+
public function getMemberType(string $memberName): EnumInstanceType
63+
{
64+
return EnumInstanceType::fromStaticEnumAndMemberName(
65+
$this,
66+
$memberName
67+
);
68+
}
69+
70+
public function is(TypeInterface $other): bool
71+
{
72+
if ($other === $this) {
73+
return true;
74+
}
75+
if ($other instanceof EnumStaticType) {
76+
return $this->moduleId === $other->moduleId
77+
&& $this->enumName === $other->enumName;
78+
}
79+
return false;
80+
}
81+
3182
public function toEnumInstanceType(): EnumInstanceType
3283
{
33-
return new EnumInstanceType($this->moduleId, $this->enumName, $this->memberNameHashMap);
84+
return EnumInstanceType::fromStaticEnumCreateUnspecificInstance($this);
3485
}
3586
}

src/TypeSystem/Type/EnumType/EnumTrait.php

Lines changed: 0 additions & 77 deletions
This file was deleted.

test/Unit/TypeSystem/Resolver/Access/AccessTypeResolverTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
use PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Scope\Fixtures\DummyScope;
3030
use PackageFactory\ComponentEngine\TypeSystem\Resolver\Access\AccessTypeResolver;
3131
use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface;
32-
use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumMemberType;
32+
use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumInstanceType;
3333
use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumStaticType;
3434
use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType;
3535
use PackageFactory\ComponentEngine\TypeSystem\TypeInterface;
@@ -68,7 +68,7 @@ private function resolveAccessType(string $accessAsString, ScopeInterface $scope
6868
/**
6969
* @test
7070
*/
71-
public function access(): void
71+
public function enumMemberAccessOnStaticEnum(): void
7272
{
7373
$someEnum = EnumStaticType::fromModuleIdAndDeclaration(
7474
ModuleId::fromString("module-a"),
@@ -86,9 +86,9 @@ public function access(): void
8686
$scope
8787
);
8888

89-
$this->assertInstanceOf(EnumMemberType::class, $accessType);
89+
$this->assertInstanceOf(EnumInstanceType::class, $accessType);
9090

91-
$this->assertTrue($accessType->enumType->is($someEnum));
91+
$this->assertTrue($accessType->enumStaticType->is($someEnum));
9292

9393
$this->assertEquals("A", $accessType->memberName);
9494
}

0 commit comments

Comments
 (0)