From 65cb451bbfe923a88100a882709e287b8fe5dbb5 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Fri, 3 Nov 2023 18:47:52 +0000 Subject: Implement subtyping for function types --- .../typechecker/TypeCheckerIsSubTypeTests.java | 100 ++++++++++++++++++++- 1 file changed, 96 insertions(+), 4 deletions(-) (limited to 'src/test/java') diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerIsSubTypeTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerIsSubTypeTests.java index a144b78c..d6bd14be 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerIsSubTypeTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerIsSubTypeTests.java @@ -1,10 +1,7 @@ package org.shedlang.compiler.typechecker; import org.junit.jupiter.api.Test; -import org.shedlang.compiler.types.NamespaceName; -import org.shedlang.compiler.types.StructType; -import org.shedlang.compiler.types.SumTypeInfo; -import org.shedlang.compiler.types.Types; +import org.shedlang.compiler.types.*; import org.shedlang.compiler.util.P; import static org.shedlang.compiler.typechecker.TypeCheckerSubTyping.isSubType; @@ -133,4 +130,99 @@ public class TypeCheckerIsSubTypeTests { assertThat(isSubType(sumType, variantType1, context), equalTo(false)); assertThat(isSubType(sumType, variantType2, context), equalTo(false)); } + + @Test + public void whenFunctionsHaveDifferentPositionalParamCountsThenTheyAreNotSubtypes() { + var functionType1 = FunctionType.builder() + .addPositionalParam(Types.STRING) + .withReturnType(Types.UNIT) + .build(); + var functionType2 = FunctionType.builder() + .addPositionalParam(Types.STRING) + .addPositionalParam(Types.BOOL) + .withReturnType(Types.UNIT) + .build(); + var context = TypeCheckerContext.EMPTY; + + assertThat(isSubType(functionType2, functionType1, context), equalTo(false)); + assertThat(isSubType(functionType1, functionType2, context), equalTo(false)); + } + + @Test + public void functionPositionalParamsAreContravariant() { + var functionType1 = FunctionType.builder() + .addPositionalParam(Types.STRING) + .withReturnType(Types.UNIT) + .build(); + var functionType2 = FunctionType.builder() + .addPositionalParam(Types.TOP) + .withReturnType(Types.UNIT) + .build(); + var context = TypeCheckerContext.EMPTY; + + assertThat(isSubType(functionType2, functionType1, context), equalTo(true)); + assertThat(isSubType(functionType1, functionType2, context), equalTo(false)); + } + + @Test + public void whenFunctionsHaveDifferentNamedParamNamesThenTheyAreNotSubtypes() { + var functionType1 = FunctionType.builder() + .addNamedParam("x", Types.STRING) + .withReturnType(Types.UNIT) + .build(); + var functionType2 = FunctionType.builder() + .addNamedParam("y", Types.STRING) + .withReturnType(Types.UNIT) + .build(); + var context = TypeCheckerContext.EMPTY; + + assertThat(isSubType(functionType2, functionType1, context), equalTo(false)); + assertThat(isSubType(functionType1, functionType2, context), equalTo(false)); + } + + @Test + public void functionNamedParamsAreContravariant() { + var functionType1 = FunctionType.builder() + .addNamedParam("x", Types.STRING) + .withReturnType(Types.UNIT) + .build(); + var functionType2 = FunctionType.builder() + .addNamedParam("x", Types.TOP) + .withReturnType(Types.UNIT) + .build(); + var context = TypeCheckerContext.EMPTY; + + assertThat(isSubType(functionType2, functionType1, context), equalTo(true)); + assertThat(isSubType(functionType1, functionType2, context), equalTo(false)); + } + + @Test + public void functionTypeIsSubtypeOfOtherFunctionTypeWhenItHasSubeffectOfOtherFunction() { + var functionType1 = FunctionType.builder() + .withEffect(Effects.IO) + .withReturnType(Types.UNIT) + .build(); + var functionType2 = FunctionType.builder() + .withEffect(Effects.NONE) + .withReturnType(Types.UNIT) + .build(); + var context = TypeCheckerContext.EMPTY; + + assertThat(isSubType(functionType2, functionType1, context), equalTo(true)); + assertThat(isSubType(functionType1, functionType2, context), equalTo(false)); + } + + @Test + public void functionReturnTypeIsCovariant() { + var functionType1 = FunctionType.builder() + .withReturnType(Types.TOP) + .build(); + var functionType2 = FunctionType.builder() + .withReturnType(Types.STRING) + .build(); + var context = TypeCheckerContext.EMPTY; + + assertThat(isSubType(functionType2, functionType1, context), equalTo(true)); + assertThat(isSubType(functionType1, functionType2, context), equalTo(false)); + } } -- cgit v1.2.3