summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNode.java7
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java4
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/SingletonStructCannotHaveTypeParamsError.java10
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerStructDefinitionTests.java24
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")