summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-08-02 13:54:53 +0100
committerMichael Williamson <mike@zwobble.org>2026-08-02 13:54:53 +0100
commit4c2db9bb403c8ffc04eadb6ab262d5137f216000 (patch)
treef990ed4fbf61b53757ee79e92b22b67e3d8d5f4c
parent75ccf6f44905cbc94b866821f34f340370430292 (diff)
Check that sum variant is struct
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java8
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/SumVariantMustBeStructError.java18
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java25
3 files changed, 49 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 a40bd92..c2eae29 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
@@ -286,8 +286,12 @@ public class TypeChecker {
} else {
variantValueType = variantType.value();
}
- // TODO: handle not struct type
- var variant = new SumVariant(variants.size(), variantType.value(), (StructType) variantValueType);
+
+ if (!(variantValueType instanceof StructType variantValueStructType)) {
+ throw new SumVariantMustBeStructError(variantValueType, untypedVariant.source());
+ }
+
+ var variant = new SumVariant(variants.size(), variantType.value(), variantValueStructType);
variants.add(variant);
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/SumVariantMustBeStructError.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/SumVariantMustBeStructError.java
new file mode 100644
index 0000000..78235ae
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/SumVariantMustBeStructError.java
@@ -0,0 +1,18 @@
+package org.zwobble.hobgoblin.compiler.typechecker.errors;
+
+import org.zwobble.hobgoblin.compiler.errors.SourceError;
+import org.zwobble.hobgoblin.compiler.sources.Source;
+import org.zwobble.hobgoblin.compiler.types.Type;
+
+public class SumVariantMustBeStructError extends SourceError {
+ private final Type variantType;
+
+ public SumVariantMustBeStructError(Type variantType, Source source) {
+ super("sum variants must be structs, but was " + variantType.describe(), source);
+ this.variantType = variantType;
+ }
+
+ public Type variantType() {
+ return variantType;
+ }
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java
index ef67cb5..1120bbe 100644
--- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java
@@ -9,6 +9,7 @@ import org.zwobble.hobgoblin.compiler.ast.untyped.*;
import org.zwobble.hobgoblin.compiler.builtins.NativeTypes;
import org.zwobble.hobgoblin.compiler.sources.NullSource;
import org.zwobble.hobgoblin.compiler.typechecker.errors.SubtypeIsMissingFieldError;
+import org.zwobble.hobgoblin.compiler.typechecker.errors.SumVariantMustBeStructError;
import org.zwobble.hobgoblin.compiler.typechecker.errors.UnexpectedTypeError;
import org.zwobble.hobgoblin.compiler.types.*;
@@ -149,6 +150,30 @@ public class TypeCheckerSumDefinitionTests {
}
@Test
+ public void variantMustBeStructType() {
+ var untyped = UntypedSumDefinitionNode.arbitrary()
+ .withName("X")
+ .withVariants(List.of(
+ UntypedSumVariantDefinitionNode.arbitrary()
+ .withType(UntypedArb.typeLevelReference("Int32"))
+ .build()
+ ))
+ .build();
+ var globalContext = TypeCheckerGlobalContext.initial();
+ globalContext.addNativeType(NativeTypes.INT_32);
+ globalContext.addNativeTypeConstructor(NativeTypes.BOX);
+ var namespaceContext = globalContext
+ .enterNamespace(NamespaceName.of("a", "b"));
+
+ var error = assertThrows(
+ SumVariantMustBeStructError.class,
+ () -> typeCheckNamespaceStatement(untyped, namespaceContext)
+ );
+
+ assertThat(error.variantType(), equalTo(NativeTypes.INT_32));
+ }
+
+ @Test
public void fieldsAreTypeChecked() {
var int32Type = SimpleNativeType.builtin("Int32");
var int64Type = SimpleNativeType.builtin("Int64");