summaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-08-09 22:06:17 +0100
committerMichael Williamson <mike@zwobble.org>2026-08-09 22:06:17 +0100
commit1e2d86b9d7f2f659f4c53f8543f7931ea81c5781 (patch)
tree53658f9c95fadabf8169b730c0de3d2dd54cd63c /src/main/java
parent4722db99dcc14457e505ee988c0622c65d4039cc (diff)
Type check generic struct definition
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java49
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/TypeOrConstructor.java11
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java8
3 files changed, 55 insertions, 13 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 e61cb7a..97008b6 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
@@ -208,7 +208,17 @@ public class TypeChecker {
TypeCheckerNamespaceContext context
) {
var structType = new SimpleStructType(context.namespaceName(), untyped.name());
- var metaType = new TypeLevelValueType(structType);
+
+ var structTypeOrConstructor = untyped.typeParams().isEmpty()
+ ? new TypeOrConstructor.Type<>(structType)
+ : new TypeOrConstructor.Constructor<>(new StructTypeConstructor(
+ untyped.typeParams().get().stream()
+ .map(typeParam -> new TypeParam(structType, typeParam.name()))
+ .toList(),
+ structType
+ ));
+ var metaType = new TypeLevelValueType(structTypeOrConstructor.value());
+
context.declare(untyped.name(), metaType, untyped.source());
return metaType;
}
@@ -217,7 +227,17 @@ public class TypeChecker {
UntypedStructDefinitionNode untyped,
TypeCheckerNamespaceContext context
) {
- var structType = (SimpleStructType) lookupMetaType(untyped.name(), untyped.source(), context);
+ var metaType = lookupTypeLevelValue(untyped.name(), untyped.source(), context);
+ var typeOrConstructor = switch (metaType) {
+ case SimpleStructType type ->
+ new TypeOrConstructor.Type<>(type);
+
+ case StructTypeConstructor typeConstructor ->
+ new TypeOrConstructor.Constructor<>(typeConstructor);
+
+ default ->
+ throw new UnsupportedOperationException("TODO");
+ };
var typeCheckedFieldDefinitions = untyped.fields().isPresent()
? Optional.of(typeCheckFieldDefinitions(untyped.fields().get(), context))
@@ -225,21 +245,24 @@ public class TypeChecker {
var typedFields = typeCheckedFieldDefinitions.map(TypeCheckFieldDefinitionsResult::fields);
var typedFieldNodes = typeCheckedFieldDefinitions.map(TypeCheckFieldDefinitionsResult::typedFieldNodes);
- context.defineStructType(structType, typedFields);
+ context.defineStructType(typeOrConstructor.unboundType(), typedFields);
- for (var sumType : context.variantOf(structType)) {
- var sumTypeFields = context.fieldsOf(sumType);
- typeCheckVariantType(
- sumType,
- sumTypeFields,
- structType,
- typedFields,
- context.toTypesInfo()
- );
+ // TODO: handle sums with generic structs
+ if (typeOrConstructor instanceof TypeOrConstructor.Type<SimpleStructType> type) {
+ for (var sumType : context.variantOf(type.value())) {
+ var sumTypeFields = context.fieldsOf(sumType);
+ typeCheckVariantType(
+ sumType,
+ sumTypeFields,
+ type.value(),
+ typedFields,
+ context.toTypesInfo()
+ );
+ }
}
return new TypedStructDefinitionNode(
- TypeOrConstructor.type(structType),
+ typeOrConstructor,
typedFieldNodes,
untyped.docComment(),
untyped.source()
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeOrConstructor.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeOrConstructor.java
index 3cffbc6..7904d29 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeOrConstructor.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeOrConstructor.java
@@ -14,6 +14,11 @@ public sealed interface TypeOrConstructor<T extends ConstructibleType> {
public String name() {
return this.value.name();
}
+
+ @Override
+ public T unboundType() {
+ return value;
+ }
}
record Constructor<T extends ConstructibleType>(TypeConstructor<T> value) implements TypeOrConstructor<T> {
@@ -21,8 +26,14 @@ public sealed interface TypeOrConstructor<T extends ConstructibleType> {
public String name() {
return this.value.name();
}
+
+ @Override
+ public T unboundType() {
+ return this.value.genericType();
+ }
}
String name();
TypeLevelValue value();
+ T unboundType();
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java
index 094a419..cfbb5ba 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java
@@ -18,4 +18,12 @@ public class Types {
new StructTypeConstructor(params, simpleStructType);
};
}
+
+ public static Type metaType(Type type) {
+ return new TypeLevelValueType(type);
+ }
+
+ public static Type metaType(TypeConstructor<?> constructor) {
+ return new TypeLevelValueType(constructor);
+ }
}