diff options
| author | Michael Williamson <mike@zwobble.org> | 2026-04-28 23:43:29 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2026-04-28 23:43:29 +0100 |
| commit | e49744ff95e24ad4282c29634fa58a4241c66c82 (patch) | |
| tree | 4f5969e73ddd6c9871a525bb62fdee9e574852eb | |
| parent | 0df2137ae4f03069398f6417d46d9a6d5bea1ce2 (diff) | |
Type check sum definitions
| -rw-r--r-- | src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java | 22 | ||||
| -rw-r--r-- | src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java | 77 |
2 files changed, 97 insertions, 2 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java index 84cb6aa..c713c70 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java @@ -97,14 +97,32 @@ public class TypeChecker { UntypedSumDefinitionNode untyped, TypeCheckerNamespaceContext context ) { - throw new UnsupportedOperationException("TODO"); + var sumType = new SumType(context.namespaceName(), untyped.name()); + // TODO: tidy up declare vs define + context.declare(untyped.name()); + context.define(untyped.name(), new TypeLevelValueType(sumType)); } private static TypedNamespaceStatementNode defineSumDefinition( UntypedSumDefinitionNode untyped, TypeCheckerNamespaceContext context ) { - throw new UnsupportedOperationException("TODO"); + var sumType = (SumType) lookupMetaType(untyped.name(), untyped.source(), context); + + var typedVariants = new ArrayList<TypedSumVariantDefinitionNode>(); + for (var untypedVariant : untyped.variants()) { + var typedVariant = new TypedSumVariantDefinitionNode( + typeCheckMetaType(untypedVariant.type(), context), + untyped.source() + ); + typedVariants.add(typedVariant); + } + + return new TypedSumDefinitionNode( + sumType, + typedVariants, + untyped.source() + ); } private static TypedTypeLevelExpressionNode<Type> typeCheckMetaType( diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java new file mode 100644 index 0000000..18d718e --- /dev/null +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java @@ -0,0 +1,77 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.junit.jupiter.api.Test; +import org.zwobble.hobgoblin.compiler.ast.typed.*; +import org.zwobble.hobgoblin.compiler.ast.untyped.*; +import org.zwobble.hobgoblin.compiler.sources.NullSource; +import org.zwobble.hobgoblin.compiler.types.*; + +import java.util.List; + +import static org.zwobble.hobgoblin.compiler.typechecker.TypeCheckerTesting.typeCheckNamespaceStatement; +import static org.zwobble.precisely.AssertThat.assertThat; +import static org.zwobble.precisely.Matchers.*; + +public class TypeCheckerSumDefinitionTests { + @Test + public void sumHasNamespaceFromContext() { + var untyped = new UntypedSumDefinitionNode( + "X", + List.of(), + NullSource.INSTANCE + ); + var context = TypeCheckerContextArb.namespaceContext(NamespaceName.of("a", "b")); + + var typed = typeCheckNamespaceStatement(untyped, context); + + assertThat(typed, instanceOf( + TypedSumDefinitionNode.class, + has( + "type", + TypedSumDefinitionNode::type, + equalTo(new SumType(NamespaceName.of("a", "b"), "X")) + ) + )); + } + + @Test + public void variantsAreTypeChecked() { + var rectangleType = new StructType(NamespaceName.of("a", "b"), "Rectangle"); + var triangleType = new StructType(NamespaceName.of("a", "b"), "Triangle"); + var untyped = new UntypedSumDefinitionNode( + "X", + List.of( + new UntypedSumVariantDefinitionNode(UntypedArb.typeLevelReference("Rectangle"), NullSource.INSTANCE), + new UntypedSumVariantDefinitionNode(UntypedArb.typeLevelReference("Triangle"), NullSource.INSTANCE) + ), + NullSource.INSTANCE + ); + var context = TypeCheckerContextArb.namespaceContext(NamespaceName.of("a", "b")); + context.declare(rectangleType.name()); + context.define(rectangleType.name(), new TypeLevelValueType(rectangleType)); + context.declare(triangleType.name()); + context.define(triangleType.name(), new TypeLevelValueType(triangleType)); + + var typed = typeCheckNamespaceStatement(untyped, context); + + assertThat(typed, instanceOf( + TypedSumDefinitionNode.class, + has( + "fields", + TypedSumDefinitionNode::variants, + isSequence( + has("type", TypedSumVariantDefinitionNode::type, has( + "value", + TypedTypeLevelExpressionNode::value, + equalTo(rectangleType) + )), + has("type", TypedSumVariantDefinitionNode::type, has( + "value", + TypedTypeLevelExpressionNode::value, + equalTo(triangleType) + )) + ) + ) + )); + } +} |
