diff options
| author | Michael Williamson <mike@zwobble.org> | 2026-08-02 14:19:23 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2026-08-02 14:19:23 +0100 |
| commit | ff49a4cd2231787867b4aafc95bd5705057bfcc3 (patch) | |
| tree | 13ca6588de1f5f5dae010e537c54af3ad8b1c06d | |
| parent | f8b54eca1cedff1fcccb099b3cd1dbea81a1410b (diff) | |
Introduce NativeTypeConstructor for greater safety
7 files changed, 44 insertions, 21 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/builtins/NativeTypes.java b/src/main/java/org/zwobble/hobgoblin/compiler/builtins/NativeTypes.java index 485df8c..f4e499e 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/builtins/NativeTypes.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/builtins/NativeTypes.java @@ -13,7 +13,7 @@ public class NativeTypes { public static final SimpleNativeType BOX_INNER = SimpleNativeType.builtin("Box"); - public static TypeConstructor<SimpleNativeType> BOX = new TypeConstructor<>( + public static TypeConstructor<SimpleNativeType> BOX = Types.constructor( List.of(new TypeParam("T")), BOX_INNER ); @@ -24,7 +24,7 @@ public class NativeTypes { public static final SimpleNativeType LIST_INNER = SimpleNativeType.builtin("List"); - public static TypeConstructor<SimpleNativeType> LIST = new TypeConstructor<>( + public static TypeConstructor<SimpleNativeType> LIST = Types.constructor( List.of(new TypeParam("T")), LIST_INNER ); @@ -35,7 +35,7 @@ public class NativeTypes { public static final SimpleNativeType OPTION_INNER = SimpleNativeType.builtin("Option"); - public static TypeConstructor<SimpleNativeType> OPTION = new TypeConstructor<>( + public static TypeConstructor<SimpleNativeType> OPTION = Types.constructor( List.of(new TypeParam("T")), OPTION_INNER ); @@ -46,7 +46,7 @@ public class NativeTypes { public static final SimpleNativeType SHARED_INNER = SimpleNativeType.builtin("Shared"); - public static TypeConstructor<SimpleNativeType> SHARED = new TypeConstructor<>( + public static TypeConstructor<SimpleNativeType> SHARED = Types.constructor( List.of(new TypeParam("T")), SHARED_INNER ); 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 4b02f60..9429313 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java @@ -408,12 +408,9 @@ public class TypeChecker { .map(untypedArg -> typeCheckMetaType(untypedArg, context).value()) .toList(); - var constructedType = switch (receiver.genericType()) { - case SimpleNativeType _ -> { - @SuppressWarnings("unchecked") - var narrowReceiver = (TypeConstructor<SimpleNativeType>) receiver; - yield new ConstructedNativeType(narrowReceiver, args); - } + var constructedType = switch (receiver) { + case NativeTypeConstructor nativeTypeConstructor -> + new ConstructedNativeType(nativeTypeConstructor, args); }; return new TypedConstructedTypeNode( diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/NativeTypeConstructor.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/NativeTypeConstructor.java new file mode 100644 index 0000000..43e0cfc --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/NativeTypeConstructor.java @@ -0,0 +1,9 @@ +package org.zwobble.hobgoblin.compiler.types; + +import java.util.List; + +public record NativeTypeConstructor( + List<TypeParam> params, + SimpleNativeType genericType +) implements TypeConstructor<SimpleNativeType> { +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeConstructor.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeConstructor.java index 1e412d7..e2726fb 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeConstructor.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeConstructor.java @@ -2,12 +2,11 @@ package org.zwobble.hobgoblin.compiler.types; import java.util.List; -public record TypeConstructor<T extends ConstructibleType>( - List<TypeParam> params, - T genericType -) implements TypeLevelValue { - @Override - public String describe() { - return genericType.describe(); +public sealed interface TypeConstructor<T extends ConstructibleType> extends TypeLevelValue permits NativeTypeConstructor { + List<TypeParam> params(); + T genericType(); + + default String describe() { + return genericType().describe(); } } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java new file mode 100644 index 0000000..6d8fcbb --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java @@ -0,0 +1,18 @@ +package org.zwobble.hobgoblin.compiler.types; + +import java.util.List; + +public class Types { + private Types() {} + + @SuppressWarnings("unchecked") + public static <T extends ConstructibleType> TypeConstructor<T> constructor( + List<TypeParam> params, + T genericType + ) { + return (TypeConstructor<T>) switch (genericType) { + case SimpleNativeType simpleNativeType -> + new NativeTypeConstructor(params, simpleNativeType); + }; + } +} diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerConstructedTypeTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerConstructedTypeTests.java index 09c0f8c..c0a7f93 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerConstructedTypeTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerConstructedTypeTests.java @@ -22,7 +22,7 @@ public class TypeCheckerConstructedTypeTests { ); var context = TypeCheckerContextArb.namespaceContext(); var listType = SimpleNativeType.builtin("List"); - var listTypeConstructor = new TypeConstructor<>(List.of(new TypeParam("T")), listType); + var listTypeConstructor = Types.constructor(List.of(new TypeParam("T")), listType); context.declare("List", new TypeLevelValueType(listTypeConstructor), NullSource.INSTANCE); var int32Type = SimpleNativeType.builtin("Int32"); context.declare("Int32", new TypeLevelValueType(int32Type), NullSource.INSTANCE); @@ -42,7 +42,7 @@ public class TypeCheckerConstructedTypeTests { ); var context = TypeCheckerContextArb.namespaceContext(); var listType = SimpleNativeType.builtin("List"); - var listTypeConstructor = new TypeConstructor<>(List.of(new TypeParam("T")), listType); + var listTypeConstructor = Types.constructor(List.of(new TypeParam("T")), listType); context.declare("List", new TypeLevelValueType(listTypeConstructor), NullSource.INSTANCE); var error = assertThrows( @@ -65,7 +65,7 @@ public class TypeCheckerConstructedTypeTests { ); var context = TypeCheckerContextArb.namespaceContext(); var listType = SimpleNativeType.builtin("List"); - var listTypeConstructor = new TypeConstructor<>(List.of(new TypeParam("T")), listType); + var listTypeConstructor = Types.constructor(List.of(new TypeParam("T")), listType); context.declare("List", new TypeLevelValueType(listTypeConstructor), NullSource.INSTANCE); var error = assertThrows( diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerMetaTypeTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerMetaTypeTests.java index c1b308c..4566b9b 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerMetaTypeTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerMetaTypeTests.java @@ -35,7 +35,7 @@ public class TypeCheckerMetaTypeTests { public void whenVariableIsTypeLevelValueButNotMetaTypeThenErrorIsThrown() { var untyped = UntypedArb.typeLevelReference("List"); var context = TypeCheckerContextArb.namespaceContext(); - var typeConstructor = new TypeConstructor<>(List.of(new TypeParam("T")), SimpleNativeType.builtin("List")); + var typeConstructor = Types.constructor(List.of(new TypeParam("T")), SimpleNativeType.builtin("List")); context.declare("List", new TypeLevelValueType(typeConstructor), NullSource.INSTANCE); var error = assertThrows( |
