aboutsummaryrefslogtreecommitdiff
path: root/src/test/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-11-07 18:57:50 +0000
committerMichael Williamson <mike@zwobble.org>2023-11-07 18:57:50 +0000
commit73915b6f89e4551575b349d5fda6bacf2b578288 (patch)
tree47756b68048695d5fa38c8a35d186a5a3679e19f /src/test/java
parentb02598aa7b8d02e2f1177177d6e0cd7b2d805198 (diff)
Handle handler method signature properly
Diffstat (limited to 'src/test/java')
-rw-r--r--src/test/java/org/shedlang/compiler/typechecker/TypeCheckerTryTests.java82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerTryTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerTryTests.java
index 2a335d20..4469979e 100644
--- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerTryTests.java
+++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerTryTests.java
@@ -314,6 +314,88 @@ public class TypeCheckerTryTests {
}
@Test
+ public void whenHandlerMethodTypeHasWrongReturnTypeThenErrorIsThrown() {
+ var handledEffect = Effects.userDefined(NAMESPACE_NAME, "HandledEffect");
+ var untyped = UntypedTryNode.builder()
+ .withHandledEffect(Untyped.typeLevelReference(handledEffect.name()))
+ .addHandlerMethod(
+ UntypedFunctionDefinitionNode.builder()
+ .addStatement(Untyped.resume())
+ .withReturnType(Untyped.typeLevelReference("String"))
+ .withName("mark")
+ .build()
+ )
+ .build();
+ var context = TypeCheckerContext.EMPTY
+ .addUserDefinedEffectInfo(
+ handledEffect,
+ UserDefinedEffectInfo.builder()
+ .addField("mark", FunctionType.builder().withReturnType(Types.UNIT).build())
+ .build()
+ )
+ .enterFunction(
+ P.map(
+ Map.entry("String", Variable.defined(Types.metaType(Types.STRING), VariableType.CONSTANT)),
+ Map.entry(handledEffect.name(), Variable.defined(Types.effectType(handledEffect), VariableType.CONSTANT))
+ ),
+ Effects.NONE,
+ Optional.empty()
+ );
+
+ var error = assertThrows(
+ UnexpectedTypeError.class,
+ () -> typeCheckExpression(untyped, context)
+ );
+
+ assertThat(error.expected(), equalTo(TypeSets.type(Types.UNIT)));
+ assertThat(error.actual(), equalTo(Types.STRING));
+ }
+
+ @Test
+ public void whenHandlerMethodTypeHasEffectThenEffectOfExpressionScopeIsIgnored() {
+ var handledEffect = Effects.userDefined(NAMESPACE_NAME, "HandledEffect");
+ var untyped = UntypedTryNode.builder()
+ .withHandledEffect(Untyped.typeLevelReference(handledEffect.name()))
+ .addHandlerMethod(
+ UntypedFunctionDefinitionNode.builder()
+ .withName("effectField")
+ .withEffect(Untyped.typeLevelReference("Pure"))
+ .addStatement(Untyped.resume(
+ UntypedCallNode.builder()
+ .withReceiver(Untyped.reference("f"))
+ .withHasEffects(true)
+ .build()
+ ))
+ .build()
+ )
+ .build();
+ var context = TypeCheckerContext.EMPTY
+ .enterFunction(
+ P.map(
+ Map.entry(handledEffect.name(), Variable.defined(Types.effectType(handledEffect), VariableType.CONSTANT)),
+ Map.entry("Pure", Variable.defined(Types.effectType(Effects.NONE), VariableType.CONSTANT)),
+ Map.entry("f", Variable.defined(FunctionType.builder().withEffect(Effects.IO).build(), VariableType.VAL))
+ ),
+ Effects.IO,
+ Optional.empty()
+ )
+ .addUserDefinedEffectInfo(
+ handledEffect,
+ UserDefinedEffectInfo.builder()
+ .addField("effectField", FunctionType.builder().withReturnType(Types.UNIT).build())
+ .build()
+ );
+
+ var error = assertThrows(
+ UnexpectedEffectError.class,
+ () -> typeCheckExpression(untyped, context)
+ );
+
+ assertThat(error.allowed(), equalTo(Effects.NONE));
+ assertThat(error.actual(), equalTo(Effects.IO));
+ }
+
+ @Test
public void whenEffectIsNotAllowedInExpressionScopeAndIsNotHandledEffectThenEffectIsNotAllowedInHandlerScope() {
var handledEffect = Effects.userDefined(NAMESPACE_NAME, "HandledEffect");
var unexpectedEffect = Effects.userDefined(NAMESPACE_NAME, "UnexpectedEffect");