diff options
Diffstat (limited to 'src')
4 files changed, 41 insertions, 4 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNode.java index 9742068..29cb885 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNode.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNode.java @@ -60,5 +60,12 @@ public record UntypedStructDefinitionNode( } // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode body + public boolean isGeneric() { + return this.typeParams.isPresent(); + } + + public boolean isSingleton() { + return this.fields.isEmpty(); + } // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode body } 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 63fc357..95ce840 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java @@ -227,6 +227,10 @@ public class TypeChecker { UntypedStructDefinitionNode untyped, TypeCheckerNamespaceContext context ) { + if (untyped.isSingleton() && untyped.isGeneric()) { + throw new SingletonStructCannotHaveTypeParamsError(untyped.source()); + } + var metaType = lookupTypeLevelValue(untyped.name(), untyped.source(), context); var typeOrConstructor = switch (metaType) { case SimpleStructType type -> diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/SingletonStructCannotHaveTypeParamsError.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/SingletonStructCannotHaveTypeParamsError.java new file mode 100644 index 0000000..a630646 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/SingletonStructCannotHaveTypeParamsError.java @@ -0,0 +1,10 @@ +package org.zwobble.hobgoblin.compiler.typechecker.errors; + +import org.zwobble.hobgoblin.compiler.errors.SourceError; +import org.zwobble.hobgoblin.compiler.sources.Source; + +public class SingletonStructCannotHaveTypeParamsError extends SourceError { + public SingletonStructCannotHaveTypeParamsError(Source source) { + super("singleton struct cannot have type params", source); + } +} diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerStructDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerStructDefinitionTests.java index 1de6cbf..fa913fa 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerStructDefinitionTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerStructDefinitionTests.java @@ -6,11 +6,13 @@ import org.zwobble.hobgoblin.compiler.ast.typed.TypedStructDefinitionNode; import org.zwobble.hobgoblin.compiler.ast.typed.TypedStructFieldDefinitionNode; import org.zwobble.hobgoblin.compiler.ast.typed.TypedTypeLevelExpressionNode; import org.zwobble.hobgoblin.compiler.ast.untyped.*; +import org.zwobble.hobgoblin.compiler.typechecker.errors.SingletonStructCannotHaveTypeParamsError; import org.zwobble.hobgoblin.compiler.types.*; import java.util.List; import java.util.Optional; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.zwobble.hobgoblin.compiler.typechecker.TypeCheckerTesting.typeCheckNamespaceStatement; import static org.zwobble.hobgoblin.compiler.types.TypeMatchers.isField; import static org.zwobble.precisely.AssertThat.assertThat; @@ -48,6 +50,7 @@ public class TypeCheckerStructDefinitionTests { UntypedTypeParamNode.arbitrary().withName("A").build(), UntypedTypeParamNode.arbitrary().withName("B").build() ))) + .withFields(List.of()) .build(); var context = TypeCheckerContextArb.namespaceContext(NamespaceName.of("a", "b")); @@ -130,15 +133,11 @@ public class TypeCheckerStructDefinitionTests { @Test public void singletonStructHasNoFields() { - var int32Type = SimpleNativeType.builtin("Int32"); - var int64Type = SimpleNativeType.builtin("Int64"); var untyped = UntypedStructDefinitionNode.arbitrary() .withName("X") .withFields(Optional.empty()) .build(); var globalContext = TypeCheckerGlobalContext.initial(); - globalContext.addNativeType(int32Type); - globalContext.addNativeType(int64Type); var namespaceName = NamespaceName.of("a", "b"); var namespaceContext = globalContext.enterNamespace(namespaceName); @@ -160,6 +159,23 @@ public class TypeCheckerStructDefinitionTests { } @Test + public void singletonStructCannotHaveTypeParams() { + var untyped = UntypedStructDefinitionNode.arbitrary() + .withName("X") + .withTypeParams(List.of(UntypedTypeParamNode.arbitrary().build())) + .withFields(Optional.empty()) + .build(); + var globalContext = TypeCheckerGlobalContext.initial(); + var namespaceName = NamespaceName.of("a", "b"); + var namespaceContext = globalContext.enterNamespace(namespaceName); + + assertThrows( + SingletonStructCannotHaveTypeParamsError.class, + () -> typeCheckNamespaceStatement(untyped, namespaceContext) + ); + } + + @Test public void whenStructDefinitionHasTypeParamsThenTypeParamsAreBoundWithinStructDefinition() { var untyped = UntypedStructDefinitionNode.arbitrary() .withName("X") |
