aboutsummaryrefslogtreecommitdiff
path: root/src/test/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-12-23 16:49:29 +0000
committerMichael Williamson <mike@zwobble.org>2023-12-23 16:49:29 +0000
commit6ea1e107ed1358e809e24681bc22284d4aa7e630 (patch)
treeb19f448bf5fbdda2062b9a30a4a8cf29cb56ad72 /src/test/java
parent1886fc2b214bb2c5bfc4cb1ca3d49975c76da0d6 (diff)
Create type constructor for structs with type params
Diffstat (limited to 'src/test/java')
-rw-r--r--src/test/java/org/shedlang/compiler/ast/typed/TypedStructDefinitionNodeMatcher.java16
-rw-r--r--src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java4
-rw-r--r--src/test/java/org/shedlang/compiler/typechecker/TypeCheckerConstructedTypeTests.java74
-rw-r--r--src/test/java/org/shedlang/compiler/typechecker/TypeCheckerStructDefinitionTests.java45
-rw-r--r--src/test/java/org/shedlang/compiler/types/TypeMatchers.java27
5 files changed, 163 insertions, 3 deletions
diff --git a/src/test/java/org/shedlang/compiler/ast/typed/TypedStructDefinitionNodeMatcher.java b/src/test/java/org/shedlang/compiler/ast/typed/TypedStructDefinitionNodeMatcher.java
index 46f0438f..6dd41fe8 100644
--- a/src/test/java/org/shedlang/compiler/ast/typed/TypedStructDefinitionNodeMatcher.java
+++ b/src/test/java/org/shedlang/compiler/ast/typed/TypedStructDefinitionNodeMatcher.java
@@ -3,11 +3,13 @@ package org.shedlang.compiler.ast.typed;
import org.pcollections.PVector;
import org.shedlang.compiler.testing.MatcherBuilder;
import org.shedlang.compiler.types.StructType;
-import org.shedlang.compiler.types.UserDefinedEffect;
+import org.shedlang.compiler.types.TypeConstructor;
+import org.shedlang.compiler.types.TypeOrConstructor;
import org.shedlang.compiler.util.P;
import org.zwobble.precisely.Matcher;
import static org.zwobble.precisely.Matchers.has;
+import static org.zwobble.precisely.Matchers.instanceOf;
public class TypedStructDefinitionNodeMatcher extends MatcherBuilder<
TypedNamespaceStatementNode,
@@ -33,7 +35,17 @@ public class TypedStructDefinitionNodeMatcher extends MatcherBuilder<
}
public TypedStructDefinitionNodeMatcher withType(Matcher<? super StructType> type) {
- return with(has("type", x -> x.type(), type));
+ return with(has("typeOrConstructor", x -> x.typeOrConstructor(), instanceOf(
+ TypeOrConstructor.Type.class,
+ has("value", x -> x.value(), instanceOf(StructType.class, type))
+ )));
+ }
+
+ public TypedStructDefinitionNodeMatcher withTypeConstructor(Matcher<TypeConstructor<?>> type) {
+ return with(has("typeOrConstructor", x -> x.typeOrConstructor(), instanceOf(
+ TypeOrConstructor.Constructor.class,
+ has("value", x -> (TypeConstructor<StructType>) x.value(), type)
+ )));
}
public TypedStructDefinitionNodeMatcher withFields(
diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java
index 8d105dd9..559ca461 100644
--- a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java
+++ b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java
@@ -224,6 +224,10 @@ public class Untyped {
return new UntypedTupleTypeNode(elements, Sources.NULL);
}
+ public static UntypedTypeLevelParamNode typeLevelParam(String name) {
+ return new UntypedTypeLevelParamNode(name, Sources.NULL);
+ }
+
public static UntypedTypeLevelReferenceNode typeLevelReference(String name) {
return new UntypedTypeLevelReferenceNode(name, Sources.NULL);
}
diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerConstructedTypeTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerConstructedTypeTests.java
new file mode 100644
index 00000000..a3c78120
--- /dev/null
+++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerConstructedTypeTests.java
@@ -0,0 +1,74 @@
+package org.shedlang.compiler.typechecker;
+
+import org.junit.jupiter.api.Test;
+import org.shedlang.compiler.ast.untyped.Untyped;
+import org.shedlang.compiler.typechecker.errors.UnexpectedTypeError;
+import org.shedlang.compiler.typechecker.errors.UnknownVariableError;
+import org.shedlang.compiler.typechecker.typesets.TypeSets;
+import org.shedlang.compiler.types.Effects;
+import org.shedlang.compiler.types.Types;
+import org.shedlang.compiler.util.P;
+
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.isTypedTypeLevelReferenceNode;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.equalTo;
+
+public class TypeCheckerConstructedTypeTests {
+ @Test
+ public void whenNameIsBoundInEnvironmentThenTypeIsUsedFromEnvironment() {
+ var untyped = Untyped.typeLevelReference("String");
+ var context = TypeCheckerContext.EMPTY
+ .enterGlobal(P.map(Map.entry("String", Types.metaType(Types.STRING))));
+
+ var typed = TypeChecker.typeCheckTypeLevelExpression(TypeSets.META_TYPE, untyped, context);
+
+ assertThat(typed, isTypedTypeLevelReferenceNode("String", Types.STRING));
+ }
+
+ @Test
+ public void whenNameRefersToNonTypeLevelValueThenErrorIsThrown() {
+ var untyped = Untyped.typeLevelReference("String");
+ var context = TypeCheckerContext.EMPTY
+ .enterGlobal(P.map(Map.entry("String", Types.STRING)));
+
+ var error = assertThrows(
+ UnexpectedTypeError.class,
+ () -> TypeChecker.typeCheckTypeLevelExpression(TypeSets.META_TYPE, untyped, context)
+ );
+
+ assertThat(error.expected(), equalTo(TypeSets.META_TYPE));
+ assertThat(error.actual(), equalTo(Types.STRING));
+ }
+
+ @Test
+ public void whenNameRefersToValueOfWrongTypeThenErrorIsThrown() {
+ var untyped = Untyped.typeLevelReference("Io");
+ var context = TypeCheckerContext.EMPTY
+ .enterGlobal(P.map(Map.entry("Io", Types.effectType(Effects.IO))));
+
+ var error = assertThrows(
+ UnexpectedTypeError.class,
+ () -> TypeChecker.typeCheckTypeLevelExpression(TypeSets.META_TYPE, untyped, context)
+ );
+
+ assertThat(error.expected(), equalTo(TypeSets.META_TYPE));
+ assertThat(error.actual(), equalTo(Types.effectType(Effects.IO)));
+ }
+
+ @Test
+ public void whenNameIsNotBoundInEnvironmentThenErrorIsThrown() {
+ var untyped = Untyped.typeLevelReference("String");
+ var context = TypeCheckerContext.EMPTY
+ .enterGlobal(P.map(Map.entry("Int", Types.metaType(Types.INT))));
+
+ var error = assertThrows(
+ UnknownVariableError.class,
+ () -> TypeChecker.typeCheckTypeLevelExpression(TypeSets.META_TYPE, untyped, context)
+ );
+
+ assertThat(error.variableName(), equalTo("String"));
+ }
+}
diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerStructDefinitionTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerStructDefinitionTests.java
index 1f8af21d..230fd811 100644
--- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerStructDefinitionTests.java
+++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerStructDefinitionTests.java
@@ -9,12 +9,13 @@ import org.shedlang.compiler.types.NamespaceName;
import org.shedlang.compiler.types.Types;
import org.shedlang.compiler.util.P;
+import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.*;
import static org.shedlang.compiler.typechecker.TypeCheckerTesting.typeCheckNamespaceStatement;
-import static org.shedlang.compiler.types.TypeMatchers.isStructType;
+import static org.shedlang.compiler.types.TypeMatchers.*;
import static org.zwobble.precisely.AssertThat.assertThat;
import static org.zwobble.precisely.Matchers.*;
@@ -35,6 +36,48 @@ public class TypeCheckerStructDefinitionTests {
}
@Test
+ public void whenDefinitionHasNoTypeLevelParamsThenTypedNodeHasType() {
+ var untyped = UntypedStructDefinitionNode.builder()
+ .withName("ExampleStruct")
+ .build();
+ var context = TypeCheckerContext.EMPTY;
+
+ var typed = typeCheckNamespaceStatement(untyped, context);
+
+ assertThat(
+ typed.value(),
+ isTypedStructDefinitionNode()
+ .withType(isStructType(NAMESPACE_NAME, "ExampleStruct"))
+ );
+ }
+
+ @Test
+ public void whenDefinitionHasTypeLevelParamsThenTypedNodeHasTypeConstructor() {
+ var untyped = UntypedStructDefinitionNode.builder()
+ .withName("ExampleStruct")
+ .withTypeLevelParams(List.of(
+ Untyped.typeLevelParam("T1"),
+ Untyped.typeLevelParam("T2")
+ ))
+ .build();
+ var context = TypeCheckerContext.EMPTY;
+
+ var typed = typeCheckNamespaceStatement(untyped, context);
+
+ assertThat(
+ typed.value(),
+ isTypedStructDefinitionNode()
+ .withTypeConstructor(isTypeConstructor(
+ isSequence(
+ isStructTypeLevelParam(NAMESPACE_NAME, "ExampleStruct", "T1"),
+ isStructTypeLevelParam(NAMESPACE_NAME, "ExampleStruct", "T2")
+ ),
+ isStructType(NAMESPACE_NAME, "ExampleStruct")
+ ))
+ );
+ }
+
+ @Test
public void typeIsAddedToEnvironment() {
var untyped = UntypedStructDefinitionNode.builder()
.withName("ExampleStruct")
diff --git a/src/test/java/org/shedlang/compiler/types/TypeMatchers.java b/src/test/java/org/shedlang/compiler/types/TypeMatchers.java
index 429caec7..cc47bad4 100644
--- a/src/test/java/org/shedlang/compiler/types/TypeMatchers.java
+++ b/src/test/java/org/shedlang/compiler/types/TypeMatchers.java
@@ -2,6 +2,8 @@ package org.shedlang.compiler.types;
import org.zwobble.precisely.Matcher;
+import java.util.List;
+
import static org.zwobble.precisely.Matchers.*;
public class TypeMatchers {
@@ -15,4 +17,29 @@ public class TypeMatchers {
has("name", x -> x.name(), equalTo(name))
);
}
+
+ public static Matcher<TypeConstructor<?>> isTypeConstructor(
+ Matcher<? super Iterable<? extends TypeParam>> params,
+ Matcher<? super Type> genericType
+ ) {
+ return instanceOf(
+ TypeConstructor.class,
+ has("params", x -> (List<TypeParam>) x.params(), params),
+ has("genericType", x -> x.genericType(), genericType)
+ );
+ }
+
+ public static Matcher<TypeParam> isStructTypeLevelParam(
+ NamespaceName namespaceName,
+ String structName,
+ String paramName
+ ) {
+ return allOf(
+ has("scope", x -> x.scope(), instanceOf(
+ Scope.Struct.class,
+ has("type", x -> x.type(), isStructType(namespaceName, structName))
+ )),
+ has("name", x -> x.name(), equalTo(paramName))
+ );
+ }
}