aboutsummaryrefslogtreecommitdiff
path: root/src/test/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-07-19 14:44:13 +0100
committerMichael Williamson <mike@zwobble.org>2023-07-19 14:44:13 +0100
commit813d4b15f404ace15684a474404ae88563d27579 (patch)
treead9b22af77fe7f96f2e2a5b3bd9b65026a7e7700 /src/test/java
parentb2aab81fd37cc37ca96ec17d6bf2a92e77f35819 (diff)
Bodge together proper checks for dependencies between statements
Diffstat (limited to 'src/test/java')
-rw-r--r--src/test/java/org/shedlang/compiler/typechecker/TypeCheckerNamespaceTests.java173
1 files changed, 169 insertions, 4 deletions
diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerNamespaceTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerNamespaceTests.java
index 03db0b54..e9e5aba5 100644
--- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerNamespaceTests.java
+++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerNamespaceTests.java
@@ -3,17 +3,17 @@ package org.shedlang.compiler.typechecker;
import org.junit.jupiter.api.Test;
import org.shedlang.compiler.ast.untyped.Untyped;
import org.shedlang.compiler.ast.untyped.UntypedFunctionDefinitionNode;
+import org.shedlang.compiler.typechecker.errors.ReferenceBeforeDefinitionError;
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.isTypedFunctionDefinitionNode;
-import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.isTypedNamespaceNode;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.*;
import static org.zwobble.precisely.AssertThat.assertThat;
-import static org.zwobble.precisely.Matchers.equalTo;
-import static org.zwobble.precisely.Matchers.isSequence;
+import static org.zwobble.precisely.Matchers.*;
public class TypeCheckerNamespaceTests {
@Test
@@ -119,6 +119,171 @@ public class TypeCheckerNamespaceTests {
}
@Test
+ public void functionCanReferenceValDefinedEarlier() {
+ var untyped = Untyped.namespace(List.of(
+ Untyped.val(Untyped.targetVariable("x"), Untyped.boolLiteral(true)),
+ UntypedFunctionDefinitionNode.builder()
+ .withName("f")
+ .withReturnType(Untyped.typeLevelReference("Unit"))
+ .addStatement(Untyped.expressionStatement(Untyped.reference("x")))
+ .build()
+ ));
+ var context = TypeCheckerContext.EMPTY
+ .enterNamespaceWithDefinedVariables(P.map(Map.entry("Unit", Types.metaType(Types.UNIT))));
+
+ var result = TypeChecker.typeCheckNamespace(untyped, context);
+
+ assertThat(
+ result.value(),
+ isTypedNamespaceNode()
+ .withBody(isSequence(
+ isTypedValNode(isTypedTargetVariable("x"), isTypedBoolLiteralNode(true)),
+ isTypedFunctionDefinitionNode().withName("f")
+ )
+ )
+ );
+ }
+
+ @Test
+ public void functionCannotReferenceValDefinedLater() {
+ var untyped = Untyped.namespace(List.of(
+ UntypedFunctionDefinitionNode.builder()
+ .withName("f")
+ .withReturnType(Untyped.typeLevelReference("Unit"))
+ .addStatement(Untyped.expressionStatement(Untyped.reference("x")))
+ .build(),
+ Untyped.val(Untyped.targetVariable("x"), Untyped.boolLiteral(true))
+ ));
+ var context = TypeCheckerContext.EMPTY
+ .enterNamespaceWithDefinedVariables(P.map(Map.entry("Unit", Types.metaType(Types.UNIT))));
+
+ var error = assertThrows(
+ ReferenceBeforeDefinitionError.class,
+ () -> TypeChecker.typeCheckNamespace(untyped, context)
+ );
+
+ assertThat(error.variableName(), equalTo("x"));
+ }
+
+ @Test
+ public void valCanReferenceFunctionDefinedEarlier() {
+ var untyped = Untyped.namespace(List.of(
+ UntypedFunctionDefinitionNode.builder()
+ .withName("f")
+ .withReturnType(Untyped.typeLevelReference("Unit"))
+ .build(),
+ Untyped.val(Untyped.targetVariable("x"), Untyped.call(Untyped.reference("f"), List.of()))
+ ));
+ var context = TypeCheckerContext.EMPTY
+ .enterNamespaceWithDefinedVariables(P.map(Map.entry("Unit", Types.metaType(Types.UNIT))));
+
+ var result = TypeChecker.typeCheckNamespace(untyped, context);
+
+ assertThat(
+ result.value(),
+ isTypedNamespaceNode()
+ .withBody(isSequence(
+ isTypedFunctionDefinitionNode().withName("f"),
+ isTypedValNode(isTypedTargetVariable("x"), anything())
+ ))
+ );
+ }
+
+ @Test
+ public void valCanReferenceFunctionDefinedLater() {
+ var untyped = Untyped.namespace(List.of(
+ Untyped.val(Untyped.targetVariable("x"), Untyped.call(Untyped.reference("f"), List.of())),
+ UntypedFunctionDefinitionNode.builder()
+ .withName("f")
+ .withReturnType(Untyped.typeLevelReference("Unit"))
+ .build()
+ ));
+ var context = TypeCheckerContext.EMPTY
+ .enterNamespaceWithDefinedVariables(P.map(Map.entry("Unit", Types.metaType(Types.UNIT))));
+
+ var result = TypeChecker.typeCheckNamespace(untyped, context);
+
+ assertThat(
+ result.value(),
+ isTypedNamespaceNode()
+ .withBody(isSequence(
+ isTypedValNode(isTypedTargetVariable("x"), anything()),
+ isTypedFunctionDefinitionNode().withName("f")
+ ))
+ );
+ }
+
+ @Test
+ public void valCanReferenceFunctionThatUsesValDefinedEarlier() {
+ var untyped = Untyped.namespace(List.of(
+ Untyped.val(Untyped.targetVariable("x"), Untyped.boolLiteral(true)),
+ Untyped.val(Untyped.targetVariable("y"), Untyped.call(Untyped.reference("f"), List.of())),
+ UntypedFunctionDefinitionNode.builder()
+ .withName("f")
+ .withReturnType(Untyped.typeLevelReference("Unit"))
+ .addStatement(Untyped.expressionStatement(Untyped.reference("x")))
+ .build()
+ ));
+ var context = TypeCheckerContext.EMPTY
+ .enterNamespaceWithDefinedVariables(P.map(Map.entry("Unit", Types.metaType(Types.UNIT))));
+
+ var result = TypeChecker.typeCheckNamespace(untyped, context);
+
+ assertThat(
+ result.value(),
+ isTypedNamespaceNode()
+ .withBody(isSequence(
+ isTypedValNode(isTypedTargetVariable("x"), anything()),
+ isTypedValNode(isTypedTargetVariable("y"), anything()),
+ isTypedFunctionDefinitionNode().withName("f")
+ ))
+ );
+ }
+
+ @Test
+ public void valCannotReferenceFunctionThatUsesThatVal() {
+ var untyped = Untyped.namespace(List.of(
+ Untyped.val(Untyped.targetVariable("x"), Untyped.call(Untyped.reference("f"), List.of())),
+ UntypedFunctionDefinitionNode.builder()
+ .withName("f")
+ .withReturnType(Untyped.typeLevelReference("Unit"))
+ .addStatement(Untyped.expressionStatement(Untyped.reference("x")))
+ .build()
+ ));
+ var context = TypeCheckerContext.EMPTY
+ .enterNamespaceWithDefinedVariables(P.map(Map.entry("Unit", Types.metaType(Types.UNIT))));
+
+ var error = assertThrows(
+ ReferenceBeforeDefinitionError.class,
+ () -> TypeChecker.typeCheckNamespace(untyped, context)
+ );
+
+ assertThat(error.variableName(), equalTo("x"));
+ }
+
+ @Test
+ public void valCannotReferenceFunctionThatUsesValDefinedLater() {
+ var untyped = Untyped.namespace(List.of(
+ Untyped.val(Untyped.targetVariable("x"), Untyped.call(Untyped.reference("f"), List.of())),
+ Untyped.val(Untyped.targetVariable("y"), Untyped.boolLiteral(true)),
+ UntypedFunctionDefinitionNode.builder()
+ .withName("f")
+ .withReturnType(Untyped.typeLevelReference("Unit"))
+ .addStatement(Untyped.expressionStatement(Untyped.reference("y")))
+ .build()
+ ));
+ var context = TypeCheckerContext.EMPTY
+ .enterNamespaceWithDefinedVariables(P.map(Map.entry("Unit", Types.metaType(Types.UNIT))));
+
+ var error = assertThrows(
+ ReferenceBeforeDefinitionError.class,
+ () -> TypeChecker.typeCheckNamespace(untyped, context)
+ );
+
+ assertThat(error.variableName(), equalTo("y"));
+ }
+
+ @Test
public void typesOfFieldsAreStored() {
var namespaceName = NamespaceName.of("Example");
var untyped = Untyped.namespace(