diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-07-16 17:57:35 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-07-16 17:57:35 +0100 |
| commit | 1fe69b87b1c409c3a4b7a27a165a8e0b71c62fa7 (patch) | |
| tree | fb030eb472dfb51b7a456c913cd9dd1eb5e922e7 /src/test/java | |
| parent | 4b88193205d2b681cb77b136ec3b858b58b42ede (diff) | |
Require variables to be declared before definition
Diffstat (limited to 'src/test/java')
3 files changed, 74 insertions, 22 deletions
diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerContextTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerContextTests.java index 650f23d5..f8529083 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerContextTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerContextTests.java @@ -2,11 +2,13 @@ package org.shedlang.compiler.typechecker; import org.junit.jupiter.api.Test; import org.shedlang.compiler.sources.Sources; +import org.shedlang.compiler.typechecker.errors.UnknownVariableError; 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.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.equalTo; import static org.zwobble.precisely.Matchers.isOptionalOf; @@ -25,4 +27,19 @@ public class TypeCheckerContextTests { assertThat(result.value(), isOptionalOf(equalTo(TypeCheckerContext.defined(Types.STRING)))); } + + @Test + public void givenVariableIsUnknownWhenVariableIsDefinedThenErrorIsThrown() { + var context = TypeCheckerContext.EMPTY + .enterNamespace(P.map( + Map.entry("y", TypeCheckerContext.undefined()) + )); + + var error = assertThrows( + UnknownVariableError.class, + () -> context.define("x", Types.STRING, Sources.NULL) + ); + + assertThat(error.variableName(), equalTo("x")); + } } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerFunctionDefinitionTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerFunctionDefinitionTests.java index a39ec685..ee88b457 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerFunctionDefinitionTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerFunctionDefinitionTests.java @@ -1,6 +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.UntypedCallNode; import org.shedlang.compiler.ast.untyped.UntypedFunctionDefinitionNode; @@ -30,7 +31,7 @@ public class TypeCheckerFunctionDefinitionTests { var context = TypeCheckerContext.EMPTY .enterNamespaceWithDefinedVariables(P.map(Map.entry("Unit", Types.metaType(Types.UNIT)))); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, context); + var typed = typeCheckNamespaceStatement(untyped, context); assertThat( typed.value(), @@ -58,7 +59,7 @@ public class TypeCheckerFunctionDefinitionTests { Map.entry("Unit", Types.metaType(Types.UNIT)) )); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, context); + var typed = typeCheckNamespaceStatement(untyped, context); assertThat( typed.value(), @@ -90,7 +91,7 @@ public class TypeCheckerFunctionDefinitionTests { Map.entry("Unit", Types.metaType(Types.UNIT)) )); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, context); + var typed = typeCheckNamespaceStatement(untyped, context); assertThat( typed.value(), @@ -108,7 +109,7 @@ public class TypeCheckerFunctionDefinitionTests { var context = TypeCheckerContext.EMPTY .enterNamespaceWithDefinedVariables(P.map(Map.entry("Unit", Types.metaType(Types.UNIT)))); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, context); + var typed = typeCheckNamespaceStatement(untyped, context); assertThat( typed.value(), @@ -132,7 +133,7 @@ public class TypeCheckerFunctionDefinitionTests { Map.entry("Unit", Types.metaType(Types.UNIT)) )); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, context); + var typed = typeCheckNamespaceStatement(untyped, context); assertThat( typed.value(), @@ -156,7 +157,7 @@ public class TypeCheckerFunctionDefinitionTests { Map.entry("Unit", Types.metaType(Types.UNIT)) )); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, context); + var typed = typeCheckNamespaceStatement(untyped, context); assertThat( typed.value(), @@ -170,6 +171,7 @@ public class TypeCheckerFunctionDefinitionTests { @Test public void bodyHasEffectAsDefinedInSignature() { var untyped = UntypedFunctionDefinitionNode.builder() + .withName("g") .withEffect(Untyped.typeLevelReference("Io")) .withReturnType(Untyped.typeLevelReference("Unit")) .addStatement(Untyped.expressionStatement( @@ -190,7 +192,7 @@ public class TypeCheckerFunctionDefinitionTests { Map.entry("Unit", Types.metaType(Types.UNIT)) )); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, context); + var typed = typeCheckNamespaceStatement(untyped, context); assertThat( typed.value(), @@ -214,7 +216,7 @@ public class TypeCheckerFunctionDefinitionTests { var error = assertThrows( UnexpectedTypeError.class, - () -> TypeChecker.typeCheckNamespaceStatement(untyped, context) + () -> typeCheckNamespaceStatement(untyped, context) ); assertThat(error.expected(), equalTo(TypeSets.type(Types.STRING))); @@ -231,7 +233,7 @@ public class TypeCheckerFunctionDefinitionTests { Map.entry("Unit", Types.metaType(Types.UNIT)) )); - TypeChecker.typeCheckNamespaceStatement(untyped, context); + typeCheckNamespaceStatement(untyped, context); } @Test @@ -246,7 +248,7 @@ public class TypeCheckerFunctionDefinitionTests { var error = assertThrows( UnexpectedTypeError.class, - () -> TypeChecker.typeCheckNamespaceStatement(untyped, context) + () -> typeCheckNamespaceStatement(untyped, context) ); assertThat(error.expected(), equalTo(TypeSets.type(Types.STRING))); @@ -264,7 +266,7 @@ public class TypeCheckerFunctionDefinitionTests { Map.entry("String", Types.metaType(Types.STRING)) )); - TypeChecker.typeCheckNamespaceStatement(untyped, context); + typeCheckNamespaceStatement(untyped, context); } @Test @@ -280,7 +282,7 @@ public class TypeCheckerFunctionDefinitionTests { Map.entry("y", Types.STRING) )); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, context); + var typed = typeCheckNamespaceStatement(untyped, context); assertThat( typed.value(), @@ -304,7 +306,7 @@ public class TypeCheckerFunctionDefinitionTests { Map.entry("Unit", Types.metaType(Types.UNIT)) )); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, context); + var typed = typeCheckNamespaceStatement(untyped, context); assertThat( typed.value(), @@ -312,4 +314,15 @@ public class TypeCheckerFunctionDefinitionTests { .withFreeVariables(containsExactly()) ); } + + private static TypeCheckerResult<? extends TypedNamespaceStatementNode> typeCheckNamespaceStatement( + UntypedFunctionDefinitionNode untyped, + TypeCheckerContext context + ) { + var environment = TypeChecker.declareVariables(untyped, EnvironmentBuilder.EMPTY); + + context = context.enterNamespace(environment.build()); + + return TypeChecker.typeCheckNamespaceStatement(untyped, context); + } } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerValTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerValTests.java index 11a66f12..44abec8b 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerValTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerValTests.java @@ -1,9 +1,9 @@ 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.ast.untyped.UntypedNamespaceNode; +import org.shedlang.compiler.ast.typed.TypedFunctionStatementNode; +import org.shedlang.compiler.ast.typed.TypedNamespaceStatementNode; +import org.shedlang.compiler.ast.untyped.*; import org.shedlang.compiler.typechecker.errors.DuplicateVariableName; import org.shedlang.compiler.typechecker.errors.ReferenceBeforeDefinitionError; import org.shedlang.compiler.types.Types; @@ -21,7 +21,7 @@ public class TypeCheckerValTests { public void canTypeCheckAsFunctionStatement() { var untyped = Untyped.val(Untyped.targetVariable("x"), Untyped.stringLiteral("hello")); - var typed = TypeChecker.typeCheckFunctionStatement(untyped, TypeCheckerContext.EMPTY); + var typed = typeCheckFunctionStatement(untyped, TypeCheckerContext.EMPTY); assertThat(typed.value(), isTypedValNode( isTypedTargetVariable("x"), @@ -33,7 +33,7 @@ public class TypeCheckerValTests { public void canTypeCheckAsNamespaceStatement() { var untyped = Untyped.val(Untyped.targetVariable("x"), Untyped.stringLiteral("hello")); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, TypeCheckerContext.EMPTY); + var typed = typeCheckNamespaceStatement(untyped, TypeCheckerContext.EMPTY); assertThat(typed.value(), isTypedValNode( isTypedTargetVariable("x"), @@ -52,7 +52,7 @@ public class TypeCheckerValTests { Map.entry("Unit", Types.metaType(Types.UNIT)) )); - var typed = TypeChecker.typeCheckNamespaceStatement(untyped, context); + var typed = typeCheckNamespaceStatement(untyped, context); assertThat( typed.value(), @@ -100,7 +100,7 @@ public class TypeCheckerValTests { var error = assertThrows( ReferenceBeforeDefinitionError.class, - () -> TypeChecker.typeCheckNamespaceStatement(untyped, context) + () -> typeCheckNamespaceStatement(untyped, context) ); assertThat(error.variableName(), equalTo("x")); @@ -120,7 +120,7 @@ public class TypeCheckerValTests { var error = assertThrows( ReferenceBeforeDefinitionError.class, - () -> TypeChecker.typeCheckNamespaceStatement(untyped, context) + () -> typeCheckNamespaceStatement(untyped, context) ); assertThat(error.variableName(), equalTo("x")); @@ -139,9 +139,31 @@ public class TypeCheckerValTests { var error = assertThrows( DuplicateVariableName.class, - () -> TypeChecker.typeCheckNamespaceStatement(untyped, context) + () -> typeCheckNamespaceStatement(untyped, context) ); assertThat(error.variableName(), equalTo("x")); } + + private static TypeCheckerResult<? extends TypedFunctionStatementNode> typeCheckFunctionStatement( + UntypedFunctionStatementNode untyped, + TypeCheckerContext context + ) { + var environment = TypeChecker.declareVariables(untyped, EnvironmentBuilder.EMPTY); + + context = context.enterNamespace(environment.build()); + + return TypeChecker.typeCheckFunctionStatement(untyped, context); + } + + private static TypeCheckerResult<? extends TypedNamespaceStatementNode> typeCheckNamespaceStatement( + UntypedNamespaceStatementNode untyped, + TypeCheckerContext context + ) { + var environment = TypeChecker.declareVariables(untyped, EnvironmentBuilder.EMPTY); + + context = context.enterNamespace(environment.build()); + + return TypeChecker.typeCheckNamespaceStatement(untyped, context); + } } |
