diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-10-01 19:37:52 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-10-01 19:37:52 +0100 |
| commit | 0f40994a60b060bddba5f08f5f43e4c49099c015 (patch) | |
| tree | 41d67d5d4adb3a112127f89780c783d8267668ae /src/test/java | |
| parent | 1dc8b36afbdb164029212d199d225c728c1fa5d9 (diff) | |
Add basic type checking for when expressions
Diffstat (limited to 'src/test/java')
9 files changed, 118 insertions, 88 deletions
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 1f64f631..c5281090 100644 --- a/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java +++ b/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java @@ -348,6 +348,27 @@ public class TypedNodeMatchers { ); } + public static Matcher<TypedExpressionNode> isTypedWhenNode( + Matcher<TypedExpressionNode> expression, + Matcher<Iterable<? extends TypedWhenCaseNode>> cases + ) { + return instanceOf( + TypedWhenNode.class, + has("expression", x -> x.expression(), expression), + has("cases", x -> x.cases(), cases) + ); + } + + public static Matcher<TypedWhenCaseNode> isTypedWhenCaseNode( + Matcher<TypedTypeLevelExpressionNode<?>> caseType, + Matcher<TypedBlockNode> body + ) { + return allOf( + has("caseType", x -> x.caseType(), caseType), + has("body", x -> x.body(), body) + ); + } + public static Matcher<TypedFunctionStatementNode> isTypedWhileNode( Matcher<? super TypedExpressionNode> condition, Matcher<? super TypedBlockNode> body 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 21335011..09067087 100644 --- a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java +++ b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java @@ -207,6 +207,20 @@ public class Untyped { return new UntypedAssignNode(targetVal(targetName), expression, Sources.NULL); } + public static UntypedWhenNode when( + UntypedExpressionNode expression, + List<UntypedWhenCaseNode> cases + ) { + return new UntypedWhenNode(expression, cases, Sources.NULL); + } + + public static UntypedWhenCaseNode whenCase( + UntypedTypeLevelExpressionNode caseType, + UntypedBlockNode body + ) { + return new UntypedWhenCaseNode(caseType, body, Sources.NULL); + } + public static UntypedWhileNode while_( UntypedExpressionNode condition, UntypedBlockNode body diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java index cc161b56..ff2e3f1d 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java @@ -2,10 +2,8 @@ package org.shedlang.compiler.typechecker; import org.junit.jupiter.api.Test; import org.shedlang.compiler.ast.typed.TypedFunctionStatementNode; -import org.shedlang.compiler.ast.typed.TypedNamespaceStatementNode; import org.shedlang.compiler.ast.untyped.Untyped; import org.shedlang.compiler.ast.untyped.UntypedFunctionStatementNode; -import org.shedlang.compiler.ast.untyped.UntypedNamespaceStatementNode; import org.shedlang.compiler.typechecker.errors.CanOnlyAssignToVarError; import org.shedlang.compiler.typechecker.errors.TargetTupleHasWrongElementCount; import org.shedlang.compiler.typechecker.errors.UnexpectedTypeError; @@ -177,16 +175,4 @@ public class TypeCheckerAssignTests { return TypeChecker.typeCheckFunctionStatement(untyped, context); } - - private static TypeCheckerResult<? extends TypedNamespaceStatementNode> typeCheckNamespaceStatement( - UntypedNamespaceStatementNode untyped, - TypeCheckerContext context - ) { - var declaredVariables = DeclaredVariables.forNamespaceStatement(untyped, P.vector()); - var environment = EnvironmentBuilder.EMPTY.addUndefined(declaredVariables); - - context = context.enterNamespace(NamespaceName.of("Example"), environment.build()); - - return TypeChecker.typeCheckNamespaceStatement(untyped).typeCheckAllPhases(context); - } } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerFunctionDefinitionTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerFunctionDefinitionTests.java index d6a600bc..78b89e90 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerFunctionDefinitionTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerFunctionDefinitionTests.java @@ -1,13 +1,15 @@ package org.shedlang.compiler.typechecker; import org.junit.jupiter.api.Test; -import org.shedlang.compiler.ast.typed.TypedNamespaceStatementNode; import org.shedlang.compiler.ast.untyped.Untyped; import org.shedlang.compiler.ast.untyped.UntypedCallNode; import org.shedlang.compiler.ast.untyped.UntypedFunctionDefinitionNode; import org.shedlang.compiler.typechecker.errors.UnexpectedTypeError; import org.shedlang.compiler.typechecker.typesets.TypeSets; -import org.shedlang.compiler.types.*; +import org.shedlang.compiler.types.Effects; +import org.shedlang.compiler.types.FunctionType; +import org.shedlang.compiler.types.NamedParam; +import org.shedlang.compiler.types.Types; import org.shedlang.compiler.util.P; import java.util.List; @@ -15,6 +17,7 @@ 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.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.*; @@ -383,16 +386,4 @@ public class TypeCheckerFunctionDefinitionTests { ))) ); } - - private static TypeCheckerResult<? extends TypedNamespaceStatementNode> typeCheckNamespaceStatement( - UntypedFunctionDefinitionNode untyped, - TypeCheckerContext context - ) { - var declaredVariables = DeclaredVariables.forNamespaceStatement(untyped, P.vector()); - var environment = EnvironmentBuilder.EMPTY.addUndefined(declaredVariables); - - context = context.enterNamespace(NamespaceName.of("Example"), environment.build()); - - return TypeChecker.typeCheckNamespaceStatement(untyped).typeCheckAllPhases(context); - } } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerStructDefinitionTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerStructDefinitionTests.java index 53c5d5e8..344cfa66 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerStructDefinitionTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerStructDefinitionTests.java @@ -1,9 +1,7 @@ package org.shedlang.compiler.typechecker; import org.junit.jupiter.api.Test; -import org.shedlang.compiler.ast.typed.TypedNamespaceStatementNode; import org.shedlang.compiler.ast.untyped.Untyped; -import org.shedlang.compiler.ast.untyped.UntypedNamespaceStatementNode; import org.shedlang.compiler.ast.untyped.UntypedStructDefinitionNode; import org.shedlang.compiler.typechecker.errors.CannotDefineStructOutsideOfNamespace; import org.shedlang.compiler.types.NamespaceName; @@ -14,6 +12,7 @@ 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.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.*; @@ -30,7 +29,7 @@ public class TypeCheckerStructDefinitionTests { assertThrows( CannotDefineStructOutsideOfNamespace.class, - () -> TypeChecker.typeCheckNamespaceStatement(untyped).typeCheckAllPhases(context) + () -> TypeChecker.typeCheckStepsNamespaceStatement(untyped).typeCheckAllPhases(context) ); } @@ -126,17 +125,4 @@ public class TypeCheckerStructDefinitionTests { )) ); } - - private static TypeCheckerResult<? extends TypedNamespaceStatementNode> typeCheckNamespaceStatement( - UntypedNamespaceStatementNode untyped, - TypeCheckerContext context - ) { - // TODO: remove duplication of this method - var declaredVariables = DeclaredVariables.forNamespaceStatement(untyped, P.vector()); - var environment = EnvironmentBuilder.EMPTY.addUndefined(declaredVariables); - - context = context.enterNamespace(NAMESPACE_NAME, environment.build()); - - return TypeChecker.typeCheckNamespaceStatement(untyped).typeCheckAllPhases(context); - } } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerSumTypeDefinitionTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerSumTypeDefinitionTests.java index d70d3660..f93cea14 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerSumTypeDefinitionTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerSumTypeDefinitionTests.java @@ -1,9 +1,7 @@ package org.shedlang.compiler.typechecker; import org.junit.jupiter.api.Test; -import org.shedlang.compiler.ast.typed.TypedNamespaceStatementNode; import org.shedlang.compiler.ast.untyped.Untyped; -import org.shedlang.compiler.ast.untyped.UntypedNamespaceStatementNode; import org.shedlang.compiler.ast.untyped.UntypedSumTypeDefinitionNode; import org.shedlang.compiler.typechecker.errors.CannotDefineSumTypeOutsideOfNamespace; import org.shedlang.compiler.types.NamespaceName; @@ -14,6 +12,7 @@ import java.util.Map; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.isTypedSumTypeDefinitionNode; +import static org.shedlang.compiler.typechecker.TypeCheckerTesting.typeCheckNamespaceStatement; import static org.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.*; @@ -29,7 +28,7 @@ public class TypeCheckerSumTypeDefinitionTests { assertThrows( CannotDefineSumTypeOutsideOfNamespace.class, - () -> TypeChecker.typeCheckNamespaceStatement(untyped).typeCheckAllPhases(context) + () -> TypeChecker.typeCheckStepsNamespaceStatement(untyped).typeCheckAllPhases(context) ); } @@ -82,17 +81,4 @@ public class TypeCheckerSumTypeDefinitionTests { )) ); } - - private static TypeCheckerResult<? extends TypedNamespaceStatementNode> typeCheckNamespaceStatement( - UntypedNamespaceStatementNode untyped, - TypeCheckerContext context - ) { - // TODO: remove duplication of this method - var declaredVariables = DeclaredVariables.forNamespaceStatement(untyped, P.vector()); - var environment = EnvironmentBuilder.EMPTY.addUndefined(declaredVariables); - - context = context.enterNamespace(NAMESPACE_NAME, environment.build()); - - return TypeChecker.typeCheckNamespaceStatement(untyped).typeCheckAllPhases(context); - } } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerValTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerValTests.java index 9fd948ba..2688a4c1 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerValTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerValTests.java @@ -2,8 +2,10 @@ package org.shedlang.compiler.typechecker; import org.junit.jupiter.api.Test; import org.shedlang.compiler.ast.typed.TypedFunctionStatementNode; -import org.shedlang.compiler.ast.typed.TypedNamespaceStatementNode; -import org.shedlang.compiler.ast.untyped.*; +import org.shedlang.compiler.ast.untyped.Untyped; +import org.shedlang.compiler.ast.untyped.UntypedFunctionDefinitionNode; +import org.shedlang.compiler.ast.untyped.UntypedFunctionStatementNode; +import org.shedlang.compiler.ast.untyped.UntypedNamespaceNode; import org.shedlang.compiler.typechecker.errors.DuplicateVariableName; import org.shedlang.compiler.typechecker.errors.ReferenceBeforeDefinitionError; import org.shedlang.compiler.types.NamespaceName; @@ -14,6 +16,7 @@ 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.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.*; @@ -157,16 +160,4 @@ public class TypeCheckerValTests { return TypeChecker.typeCheckFunctionStatement(untyped, context); } - - private static TypeCheckerResult<? extends TypedNamespaceStatementNode> typeCheckNamespaceStatement( - UntypedNamespaceStatementNode untyped, - TypeCheckerContext context - ) { - var declaredVariables = DeclaredVariables.forNamespaceStatement(untyped, P.vector()); - var environment = EnvironmentBuilder.EMPTY.addUndefined(declaredVariables); - - context = context.enterNamespace(NamespaceName.of("Example"), environment.build()); - - return TypeChecker.typeCheckNamespaceStatement(untyped).typeCheckAllPhases(context); - } } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerVarTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerVarTests.java index 466ab16c..53e2e65f 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerVarTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerVarTests.java @@ -2,11 +2,9 @@ package org.shedlang.compiler.typechecker; import org.junit.jupiter.api.Test; import org.shedlang.compiler.ast.typed.TypedFunctionStatementNode; -import org.shedlang.compiler.ast.typed.TypedNamespaceStatementNode; import org.shedlang.compiler.ast.untyped.Untyped; import org.shedlang.compiler.ast.untyped.UntypedFunctionDefinitionNode; import org.shedlang.compiler.ast.untyped.UntypedFunctionStatementNode; -import org.shedlang.compiler.ast.untyped.UntypedNamespaceStatementNode; import org.shedlang.compiler.types.NamespaceName; import org.shedlang.compiler.types.Types; import org.shedlang.compiler.util.P; @@ -14,6 +12,7 @@ import org.shedlang.compiler.util.P; import java.util.Map; import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.*; +import static org.shedlang.compiler.typechecker.TypeCheckerTesting.typeCheckNamespaceStatement; import static org.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.anything; import static org.zwobble.precisely.Matchers.isSequence; @@ -65,16 +64,4 @@ public class TypeCheckerVarTests { return TypeChecker.typeCheckFunctionStatement(untyped, context); } - - private static TypeCheckerResult<? extends TypedNamespaceStatementNode> typeCheckNamespaceStatement( - UntypedNamespaceStatementNode untyped, - TypeCheckerContext context - ) { - var declaredVariables = DeclaredVariables.forNamespaceStatement(untyped, P.vector()); - var environment = EnvironmentBuilder.EMPTY.addUndefined(declaredVariables); - - context = context.enterNamespace(NamespaceName.of("Example"), environment.build()); - - return TypeChecker.typeCheckNamespaceStatement(untyped).typeCheckAllPhases(context); - } } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerWhenTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerWhenTests.java new file mode 100644 index 00000000..4fdaf950 --- /dev/null +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerWhenTests.java @@ -0,0 +1,68 @@ +package org.shedlang.compiler.typechecker; + +import org.junit.jupiter.api.Test; +import org.shedlang.compiler.ast.untyped.Untyped; +import org.shedlang.compiler.types.*; +import org.shedlang.compiler.util.P; + +import java.util.List; +import java.util.Map; + +import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.*; +import static org.zwobble.precisely.AssertThat.assertThat; +import static org.zwobble.precisely.Matchers.isSequence; + +public class TypeCheckerWhenTests { + private static final NamespaceName NAMESPACE_NAME = NamespaceName.of("Example", "Project"); + private static final SumType SUM_TYPE = Types.sum(NAMESPACE_NAME, "SumType"); + private static final StructType VARIANT_TYPE_1 = Types.struct(NAMESPACE_NAME, "Variant1"); + private static final StructType VARIANT_TYPE_2 = Types.struct(NAMESPACE_NAME, "Variant2"); + + @Test + public void whenAllCasesAreHandledThenExpressionTypeChecks() { + var untyped = Untyped.when( + Untyped.reference("x"), + List.of( + Untyped.whenCase( + Untyped.typeLevelReference(VARIANT_TYPE_1.name()), + Untyped.block(List.of( + Untyped.blockReturn(Untyped.stringLiteral("a")) + )) + ), + Untyped.whenCase( + Untyped.typeLevelReference(VARIANT_TYPE_2.name()), + Untyped.block(List.of( + Untyped.blockReturn(Untyped.stringLiteral("b")) + )) + ) + ) + ); + var context = TypeCheckerContext.EMPTY + .addSumTypeInfo(SUM_TYPE, new SumTypeInfo(P.orderedSet(VARIANT_TYPE_1, VARIANT_TYPE_2))) + .enterGlobal(P.map( + Map.entry("x", SUM_TYPE), + Map.entry(VARIANT_TYPE_1.name(), Types.metaType(VARIANT_TYPE_1)), + Map.entry(VARIANT_TYPE_2.name(), Types.metaType(VARIANT_TYPE_2)) + )); + + var result = TypeChecker.typeCheckExpression(untyped, context); + + assertThat(result.value(), isTypedWhenNode( + isTypedReferenceNode("x", SUM_TYPE), + isSequence( + isTypedWhenCaseNode( + isTypedTypeLevelReferenceNode("Variant1", VARIANT_TYPE_1), + isTypedBlockNode(isSequence( + isTypedBlockReturnNode(isTypedStringLiteralNode("a")) + )) + ), + isTypedWhenCaseNode( + isTypedTypeLevelReferenceNode("Variant2", VARIANT_TYPE_2), + isTypedBlockNode(isSequence( + isTypedBlockReturnNode(isTypedStringLiteralNode("b")) + )) + ) + ) + )); + } +} |
