From c4498af1d2fb1f9456d16a39daba9e841d3537b9 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 23 Dec 2023 23:12:57 +0000 Subject: Add basic type checking for constructed types --- .../compiler/ast/typed/TypedNodeMatchers.java | 9 +++ .../org/shedlang/compiler/ast/untyped/Untyped.java | 7 ++ .../TypeCheckerConstructedTypeTests.java | 87 ++++++++-------------- .../org/shedlang/compiler/types/TypeMatchers.java | 10 +++ 4 files changed, 58 insertions(+), 55 deletions(-) (limited to 'src/test/java') diff --git a/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java b/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java index 4a5bf1c5..65f5f24b 100644 --- a/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java +++ b/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java @@ -93,6 +93,15 @@ public class TypedNodeMatchers { ); } + public static Matcher> isTypedConstructedTypeNode( + Matcher> value + ) { + return instanceOf( + TypedConstructedTypeNode.class, + has("value", x -> x.value(), value) + ); + } + public static TypedEffectDefinitionNodeMatcher isTypedEffectDefinitionNode() { return TypedEffectDefinitionNodeMatcher.empty(); } 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 559ca461..41c52802 100644 --- a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java +++ b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java @@ -78,6 +78,13 @@ public class Untyped { return new UntypedConditionalBranchNode(condition, body, Sources.NULL); } + public static UntypedConstructedTypeNode constructedType( + UntypedTypeLevelExpressionNode receiver, + List args + ) { + return new UntypedConstructedTypeNode(receiver, args, Sources.NULL); + } + public static UntypedBinaryOperationNode equals( UntypedExpressionNode left, UntypedExpressionNode right diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerConstructedTypeTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerConstructedTypeTests.java index a3c78120..80c7e82d 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerConstructedTypeTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerConstructedTypeTests.java @@ -2,73 +2,50 @@ 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.NamespaceName; +import org.shedlang.compiler.types.TypeParam; 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.isTypedTypeLevelReferenceNode; +import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.isTypedConstructedTypeNode; +import static org.shedlang.compiler.types.TypeMatchers.isConstructedType; import static org.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.equalTo; +import static org.zwobble.precisely.Matchers.isSequence; 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) + public void typedNodeHasConstructedType() { + var untyped = Untyped.constructedType( + Untyped.typeLevelReference("Map"), + List.of( + Untyped.typeLevelReference("Int"), + Untyped.typeLevelReference("Bool") + ) ); - - 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) + var structType = Types.struct(NamespaceName.of("Example", "Project"), "Map"); + var typeConstructor = Types.typeConstructor( + List.of( + TypeParam.forStructType(structType, "K"), + TypeParam.forStructType(structType, "V") + ), + structType ); - - 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")); + .enterGlobal(P.map( + Map.entry("Map", Types.typeConstructorType(typeConstructor)), + Map.entry("Int", Types.metaType(Types.INT)), + Map.entry("Bool", Types.metaType(Types.BOOL)) + )); + + var typed = TypeChecker.typeCheckTypeExpression(untyped, context); + + assertThat(typed, isTypedConstructedTypeNode(isConstructedType( + equalTo(typeConstructor), + isSequence(equalTo(Types.INT), equalTo(Types.BOOL)) + ))); } } diff --git a/src/test/java/org/shedlang/compiler/types/TypeMatchers.java b/src/test/java/org/shedlang/compiler/types/TypeMatchers.java index b52bbdff..9b6f0d54 100644 --- a/src/test/java/org/shedlang/compiler/types/TypeMatchers.java +++ b/src/test/java/org/shedlang/compiler/types/TypeMatchers.java @@ -44,6 +44,16 @@ public class TypeMatchers { ); } + public static Matcher> isConstructedType( + Matcher> constructor, + Matcher> args + ) { + return allOf( + has("constructor", x -> x.constructor(), constructor), + has("args", x -> x.args(), args) + ); + } + public static Matcher isTypeLevelValueType(Matcher value) { return instanceOf(TypeLevelValueType.class, has("value", x -> x.value(), value)); } -- cgit v1.2.3