diff options
| author | Michael Williamson <mike@zwobble.org> | 2026-06-26 16:25:34 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2026-06-26 16:25:34 +0100 |
| commit | 9c2421d317068021c64a42be9f785e5ec73afd43 (patch) | |
| tree | e5284a4ffa6a65117c3c84458fe1560ec0a713f5 | |
| parent | 7e632842ecdc2a3b72b3e5f0b575166c6c5e8b4b (diff) | |
Treat variant as subtype of sum
6 files changed, 80 insertions, 12 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 34c05cb..8b930aa 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java @@ -189,7 +189,8 @@ public class TypeChecker { sumType, sumTypeFields, structType, - typeCheckedFieldDefinitions.fields + typeCheckedFieldDefinitions.fields, + context.toTypesInfo() ); } @@ -265,7 +266,8 @@ public class TypeChecker { sumType, typeCheckedFieldDefinitions.fields, variantType, - context.fieldsOf(variantType) + context.fieldsOf(variantType), + context.toTypesInfo() ); } } @@ -299,7 +301,8 @@ public class TypeChecker { SumType sumType, List<Field> sumTypeFields, StructType variantType, - List<Field> variantTypeFields + List<Field> variantTypeFields, + TypesInfo typesInfo ) { for (var sumTypeField : sumTypeFields) { var variantTypeField = variantTypeFields.stream() @@ -310,7 +313,12 @@ public class TypeChecker { throw new SubtypeIsMissingFieldError(sumType, variantType, sumTypeField.name(), sumTypeField.source()); } - checkIsSubtype(variantTypeField.get().type(), sumTypeField.type(), variantTypeField.get().source()); + checkIsSubtype( + variantTypeField.get().type(), + sumTypeField.type(), + variantTypeField.get().source(), + typesInfo + ); } } @@ -384,8 +392,13 @@ public class TypeChecker { return value; } - private static void checkIsSubtype(Type subtype, Type supertype, Source source) { - if (!isSubtype(subtype, supertype)) { + private static void checkIsSubtype( + Type subtype, + Type supertype, + Source source, + TypesInfo typesInfo + ) { + if (!isSubtype(subtype, supertype, typesInfo)) { throw new UnexpectedTypeError( new TypeSet.SingleType(supertype), subtype, diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java index cf61a22..c66c999 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java @@ -1,9 +1,11 @@ package org.zwobble.hobgoblin.compiler.typechecker; import org.zwobble.hobgoblin.compiler.types.*; -import org.zwobble.hobgoblin.compiler.util.ManyToMany; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; public class TypeCheckerGlobalContext { private final Map<String, Type> nativeTypes = new HashMap<>(); diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java index 0ffbe66..82c8273 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java @@ -34,6 +34,11 @@ public class TypeCheckerNamespaceContext { this.typesInfo = typesInfo; } + public TypesInfo toTypesInfo() { + return this.typesInfo; + } + + public NamespaceName namespaceName() { return this.namespaceName; } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSubtyping.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSubtyping.java index 673d931..335fa8d 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSubtyping.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSubtyping.java @@ -1,12 +1,22 @@ package org.zwobble.hobgoblin.compiler.typechecker; +import org.zwobble.hobgoblin.compiler.types.SumType; import org.zwobble.hobgoblin.compiler.types.Type; class TypeCheckerSubtyping { private TypeCheckerSubtyping() { } - static boolean isSubtype(Type subtype, Type supertype) { - return subtype.equals(supertype); + static boolean isSubtype(Type subtype, Type supertype, TypesInfo typesInfo) { + if (subtype.equals(supertype)) { + return true; + } + + if (supertype instanceof SumType supertypeSum) { + return typesInfo.sumVariants(supertypeSum).stream() + .anyMatch(variantType -> isSubtype(variantType, subtype, typesInfo)); + } + + return false; } } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java index 4e896dd..814466c 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java @@ -5,6 +5,8 @@ import org.zwobble.hobgoblin.compiler.types.*; import java.util.List; public interface TypesInfo { + TypesInfo EMPTY = TypesInfoInMemory.empty(); + boolean isDefined(StructType type); List<Field> fieldsOf(StructType structType); diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSubtypingTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSubtypingTests.java index 35779fe..e2b43d0 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSubtypingTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSubtypingTests.java @@ -1,7 +1,12 @@ package org.zwobble.hobgoblin.compiler.typechecker; import org.junit.jupiter.api.Test; +import org.zwobble.hobgoblin.compiler.types.NamespaceName; import org.zwobble.hobgoblin.compiler.types.SimpleNativeType; +import org.zwobble.hobgoblin.compiler.types.StructType; +import org.zwobble.hobgoblin.compiler.types.SumType; + +import java.util.List; import static org.zwobble.hobgoblin.compiler.typechecker.TypeCheckerSubtyping.isSubtype; import static org.zwobble.precisely.AssertThat.assertThat; @@ -13,7 +18,7 @@ public class TypeCheckerSubtypingTests { var nativeType1 = SimpleNativeType.builtin("Int32"); var nativeType2 = SimpleNativeType.builtin("Int32"); - var isSubtype = isSubtype(nativeType1, nativeType2); + var isSubtype = isSubtype(nativeType1, nativeType2, TypesInfo.EMPTY); assertThat(isSubtype, equalTo(true)); } @@ -23,7 +28,38 @@ public class TypeCheckerSubtypingTests { var nativeType1 = SimpleNativeType.builtin("Int32"); var nativeType2 = SimpleNativeType.builtin("Int64"); - var isSubtype = isSubtype(nativeType1, nativeType2); + var isSubtype = isSubtype(nativeType1, nativeType2, TypesInfo.EMPTY); + + assertThat(isSubtype, equalTo(false)); + } + + @Test + public void variantIsSubtypeOfSumType() { + var variantType1 = new StructType(NamespaceName.of(), "Rectangle"); + var variantType2 = new StructType(NamespaceName.of(), "Circle"); + var sumType = new SumType(NamespaceName.of(), "Shape"); + var typesInfo = TypesInfoInMemory.empty(); + typesInfo.defineSumType(sumType, List.of(variantType1, variantType2), List.of()); + + var isSubtype = isSubtype(variantType1, sumType, typesInfo); + + assertThat(isSubtype, equalTo(true)); + } + + @Test + public void variantIsNotSubtypeOfUnrelatedSumType() { + var typesInfo = TypesInfoInMemory.empty(); + + var variantType1 = new StructType(NamespaceName.of(), "Rectangle"); + var variantType2 = new StructType(NamespaceName.of(), "Circle"); + var sumType = new SumType(NamespaceName.of(), "Shape"); + typesInfo.defineSumType(sumType, List.of(variantType1, variantType2), List.of()); + + var otherSumType = new SumType(NamespaceName.of(), "Shape3D"); + var otherVariantType = new StructType(NamespaceName.of(), "Cube"); + typesInfo.defineSumType(sumType, List.of(otherVariantType), List.of()); + + var isSubtype = isSubtype(variantType1, otherSumType, typesInfo); assertThat(isSubtype, equalTo(false)); } |
