aboutsummaryrefslogtreecommitdiff
path: root/src/test/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-12-03 00:21:36 +0000
committerMichael Williamson <mike@zwobble.org>2023-12-03 00:21:36 +0000
commit86f4db9a9daf5207e047284fef93bceec3b5e0c9 (patch)
treeacb6a871763a1a3998ef865f43cecda7d8e70d3e /src/test/java
parent2dbc90aacf38c68fe06209b998bb2c7b2ef9f560 (diff)
Use break statements to determine type of try expression
Diffstat (limited to 'src/test/java')
-rw-r--r--src/test/java/org/shedlang/compiler/ast/typed/TypedTryNodeMatcher.java7
-rw-r--r--src/test/java/org/shedlang/compiler/typechecker/TypeCheckerTryTests.java70
2 files changed, 77 insertions, 0 deletions
diff --git a/src/test/java/org/shedlang/compiler/ast/typed/TypedTryNodeMatcher.java b/src/test/java/org/shedlang/compiler/ast/typed/TypedTryNodeMatcher.java
index 9bc549d3..5efbc24d 100644
--- a/src/test/java/org/shedlang/compiler/ast/typed/TypedTryNodeMatcher.java
+++ b/src/test/java/org/shedlang/compiler/ast/typed/TypedTryNodeMatcher.java
@@ -2,6 +2,7 @@ package org.shedlang.compiler.ast.typed;
import org.pcollections.PVector;
import org.shedlang.compiler.testing.MatcherBuilder;
+import org.shedlang.compiler.types.Type;
import org.shedlang.compiler.util.P;
import org.zwobble.precisely.Matcher;
@@ -38,6 +39,12 @@ public class TypedTryNodeMatcher extends MatcherBuilder<
return with(has("body", x -> x.body(), body));
}
+ public TypedTryNodeMatcher withType(
+ Matcher<Type> type
+ ) {
+ return with(has("type", x -> x.type(), type));
+ }
+
public TypedTryNodeMatcher withHandlerMethods(
Matcher<? super Iterable<TypedTryHandlerMethodNode>> handlerMethods
) {
diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerTryTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerTryTests.java
index 2d60446b..23be48ef 100644
--- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerTryTests.java
+++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerTryTests.java
@@ -8,6 +8,7 @@ import org.shedlang.compiler.typechecker.typesets.TypeSets;
import org.shedlang.compiler.types.*;
import org.shedlang.compiler.util.P;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -46,6 +47,75 @@ public class TypeCheckerTryTests {
}
@Test
+ public void typeIsCommonSupertypeOfBodyTypeAndBreaksInHandlerMethods() {
+ var untyped = UntypedTryNode.builder()
+ .addBodyStatement(Untyped.blockReturn(Untyped.intLiteral(42)))
+ .withHandledEffect(Untyped.typeLevelReference("Effect"))
+ .addHandlerMethod(
+ UntypedTryHandlerMethodNode.builder()
+ .withName("a")
+ .addStatement(Untyped.break_(Untyped.stringLiteral("")))
+ .build()
+ )
+ .build();
+ var effect = Effects.userDefined(NAMESPACE_NAME, "Effect");
+ var effectInfo = UserDefinedEffectInfo.builder()
+ .addMethod("a", FunctionType.builder().withReturnType(Types.UNIT).build())
+ .build();
+ var context = TypeCheckerContext.EMPTY
+ .enterGlobal(P.map(
+ Map.entry("Effect", Types.effectType(effect))
+ ))
+ .addUserDefinedEffectInfo(effect, effectInfo);
+
+ var result = typeCheckExpression(untyped, context);
+
+ assertThat(
+ result.value(),
+ isTypedTryNode()
+ .withType(equalTo(Types.commonSupertype(List.of(Types.INT, Types.STRING))))
+ );
+ }
+
+ @Test
+ public void resumeStatementsAreIgnoredWhenDeterminingTypeOfTry() {
+ var untyped = UntypedTryNode.builder()
+ .addBodyStatement(Untyped.blockReturn(Untyped.intLiteral(42)))
+ .withHandledEffect(Untyped.typeLevelReference("Effect"))
+ .addHandlerMethod(
+ UntypedTryHandlerMethodNode.builder()
+ .withName("a")
+ .addStatement(Untyped.resume())
+ .build()
+ )
+ .addHandlerMethod(
+ UntypedTryHandlerMethodNode.builder()
+ .withName("b")
+ .addStatement(Untyped.break_(Untyped.intLiteral(0)))
+ .build()
+ )
+ .build();
+ var effect = Effects.userDefined(NAMESPACE_NAME, "Effect");
+ var effectInfo = UserDefinedEffectInfo.builder()
+ .addMethod("a", FunctionType.builder().withReturnType(Types.UNIT).build())
+ .addMethod("b", FunctionType.builder().withReturnType(Types.UNIT).build())
+ .build();
+ var context = TypeCheckerContext.EMPTY
+ .enterGlobal(P.map(
+ Map.entry("Effect", Types.effectType(effect))
+ ))
+ .addUserDefinedEffectInfo(effect, effectInfo);
+
+ var result = typeCheckExpression(untyped, context);
+
+ assertThat(
+ result.value(),
+ isTypedTryNode()
+ .withType(equalTo(Types.INT))
+ );
+ }
+
+ @Test
public void whenEffectIsNotAllowedInExpressionScopeAndIsNotHandledEffectThenEffectIsNotAllowedInBodyScope() {
var handledEffect = Effects.userDefined(NAMESPACE_NAME, "HandledEffect");
var unexpectedEffect = Effects.userDefined(NAMESPACE_NAME, "UnexpectedEffect");