From 09f15965cf8fb86077e06bcf6c4f34af4ad7b0e7 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 3 Jan 2024 21:23:18 +0000 Subject: Introduce specific subtypes for constructed types --- .../shedlang/compiler/typechecker/TypeChecker.java | 25 +++++--------- .../compiler/typechecker/TypeCheckerSubTyping.java | 11 +++--- .../shedlang/compiler/typechecker/TypeInfos.java | 2 +- .../compiler/types/ConstructedStructType.java | 9 +++++ .../compiler/types/ConstructedSumType.java | 9 +++++ .../shedlang/compiler/types/ConstructedType.java | 26 +++++++-------- .../org/shedlang/compiler/types/SumVariant.java | 4 +-- .../shedlang/compiler/types/TypeSubstitution.java | 39 +++++++++++++++++++--- .../java/org/shedlang/compiler/types/Types.java | 26 +++++++++++++-- 9 files changed, 105 insertions(+), 46 deletions(-) create mode 100644 src/main/java/org/shedlang/compiler/types/ConstructedStructType.java create mode 100644 src/main/java/org/shedlang/compiler/types/ConstructedSumType.java (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java index 854fdbfe..8ac346a3 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java @@ -435,11 +435,9 @@ public class TypeChecker { if ( receiverType instanceof TypeLevelValueType typeLevelValueType && - typeLevelValueType.value() instanceof ConstructedType constructedType && - constructedType.genericType() instanceof StructType + typeLevelValueType.value() instanceof ConstructedStructType constructedType ) { - // TODO: make specific constructed types to avoid generic casting? - var structTypeInfo = context.structTypeInfo((ConstructedType) constructedType, receiverSource); + var structTypeInfo = context.structTypeInfo(constructedType, receiverSource); return receiverStructTypeInfoToFunctionType( constructedType, structTypeInfo @@ -1664,13 +1662,8 @@ public class TypeChecker { if (variantType instanceof StructType variantStructType) { return SumVariant.struct(variantStructType); - } else if ( - variantType instanceof ConstructedType variantConstructedType && - variantConstructedType.genericType() instanceof StructType - ) { - return SumVariant.constructedStruct( - (ConstructedType) variantConstructedType - ); + } else if (variantType instanceof ConstructedStructType variantConstructedType) { + return SumVariant.constructedStruct(variantConstructedType); } else { throw new VariantTypeIsNotStructError( variantType, @@ -1723,7 +1716,7 @@ public class TypeChecker { var args = constructedTypeNode.args().stream() .map(arg -> typeCheckTypeExpression(arg, context).value()) .toList(); - var constructedType = new ConstructedType<>(constructor, args); + var constructedType = Types.constructedType(constructor, args); // TODO: tidy this (and other similar checks in this function) up if (valueType.valueClass().equals(Type.class)) { @@ -2102,8 +2095,8 @@ public class TypeChecker { context = typedExpressionResult.context(); var expressionTypeInfo = switch (typedExpression.type()) { - case ConstructedType constructedType when constructedType.genericType() instanceof SumType -> - context.sumTypeInfo((ConstructedType) constructedType, untyped.source()); + case ConstructedSumType constructedType -> + context.sumTypeInfo(constructedType, untyped.source()); case SumType expressionType -> context.sumTypeInfo(expressionType, untyped.source()); @@ -2176,8 +2169,8 @@ public class TypeChecker { ); var variant = switch (typedCaseType.value()) { - case ConstructedType constructedType when constructedType.genericType() instanceof StructType -> - SumVariant.constructedStruct((ConstructedType) constructedType); + case ConstructedStructType constructedStructType -> + SumVariant.constructedStruct(constructedStructType); case StructType structType -> SumVariant.struct(structType); diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerSubTyping.java b/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerSubTyping.java index 898cacf9..1ffd9ee2 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerSubTyping.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerSubTyping.java @@ -125,13 +125,10 @@ public class TypeCheckerSubTyping { return tryAddVariantSubtypeConstraint(subtype, superTypeInfo, constraints); } - if ( - supertype instanceof ConstructedType supertypeConstructedType && - supertypeConstructedType.genericType() instanceof SumType - ) { - var superTypeInfo = constraints.typeInfos.sumTypeInfo( - (ConstructedType) supertypeConstructedType - ).orElseThrow(); + if (supertype instanceof ConstructedSumType supertypeConstructedType) { + var superTypeInfo = constraints.typeInfos + .sumTypeInfo(supertypeConstructedType) + .orElseThrow(); return tryAddVariantSubtypeConstraint(subtype, superTypeInfo, constraints); } diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeInfos.java b/src/main/java/org/shedlang/compiler/typechecker/TypeInfos.java index 99947094..1e00a354 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeInfos.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeInfos.java @@ -103,7 +103,7 @@ public class TypeInfos { var variants = typeInfo.variants().stream() .map(variant -> switch (variant) { case SumVariant.ConstructedStruct constructedStruct -> - SumVariant.constructedStruct(TypeSubstitution.substituteConstructedType( + SumVariant.constructedStruct(TypeSubstitution.substituteConstructedStructType( constructedStruct.type(), typeSubstitutionMap )); diff --git a/src/main/java/org/shedlang/compiler/types/ConstructedStructType.java b/src/main/java/org/shedlang/compiler/types/ConstructedStructType.java new file mode 100644 index 00000000..df454e5d --- /dev/null +++ b/src/main/java/org/shedlang/compiler/types/ConstructedStructType.java @@ -0,0 +1,9 @@ +package org.shedlang.compiler.types; + +import java.util.List; + +public record ConstructedStructType( + TypeConstructor constructor, + List args +) implements ConstructedType { +} diff --git a/src/main/java/org/shedlang/compiler/types/ConstructedSumType.java b/src/main/java/org/shedlang/compiler/types/ConstructedSumType.java new file mode 100644 index 00000000..ee3c6f80 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/types/ConstructedSumType.java @@ -0,0 +1,9 @@ +package org.shedlang.compiler.types; + +import java.util.List; + +public record ConstructedSumType( + TypeConstructor constructor, + List args +) implements ConstructedType { +} diff --git a/src/main/java/org/shedlang/compiler/types/ConstructedType.java b/src/main/java/org/shedlang/compiler/types/ConstructedType.java index d4f688dc..daf7bcb4 100644 --- a/src/main/java/org/shedlang/compiler/types/ConstructedType.java +++ b/src/main/java/org/shedlang/compiler/types/ConstructedType.java @@ -4,28 +4,28 @@ import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; -public record ConstructedType( - TypeConstructor constructor, - List args -) implements Type { +public sealed interface ConstructedType extends Type permits ConstructedStructType, ConstructedSumType { + TypeConstructor constructor(); + List args(); + @Override - public String describe() { - var argsString = args.stream() + default String describe() { + var argsString = args().stream() .map(arg -> arg.describe()) .collect(Collectors.joining(", ")); - return constructor.describe() + "[" + argsString + "]"; + return constructor().describe() + "[" + argsString + "]"; } - public T genericType() { - return constructor.genericType(); + default T genericType() { + return constructor().genericType(); } - public TypeSubstitutionMap typeSubstitutionMap() { + default TypeSubstitutionMap typeSubstitutionMap() { var map = new HashMap(); - for (var argIndex = 0; argIndex < args.size(); argIndex++) { - var param = constructor.params().get(argIndex); - var arg = args.get(argIndex); + for (var argIndex = 0; argIndex < args().size(); argIndex++) { + var param = constructor().params().get(argIndex); + var arg = args().get(argIndex); map.put(param, arg); } diff --git a/src/main/java/org/shedlang/compiler/types/SumVariant.java b/src/main/java/org/shedlang/compiler/types/SumVariant.java index 74ff287b..5c04d77b 100644 --- a/src/main/java/org/shedlang/compiler/types/SumVariant.java +++ b/src/main/java/org/shedlang/compiler/types/SumVariant.java @@ -1,7 +1,7 @@ package org.shedlang.compiler.types; public sealed interface SumVariant { - static SumVariant constructedStruct(ConstructedType type) { + static SumVariant constructedStruct(ConstructedStructType type) { return new ConstructedStruct(type); } @@ -14,7 +14,7 @@ public sealed interface SumVariant { Type type(); StructType rawType(); - record ConstructedStruct(ConstructedType type) implements SumVariant { + record ConstructedStruct(ConstructedStructType type) implements SumVariant { @Override public String describe() { return type.describe(); diff --git a/src/main/java/org/shedlang/compiler/types/TypeSubstitution.java b/src/main/java/org/shedlang/compiler/types/TypeSubstitution.java index 60edfdfb..db6d554f 100644 --- a/src/main/java/org/shedlang/compiler/types/TypeSubstitution.java +++ b/src/main/java/org/shedlang/compiler/types/TypeSubstitution.java @@ -1,6 +1,8 @@ package org.shedlang.compiler.types; +import java.util.List; import java.util.Optional; +import java.util.function.BiFunction; public class TypeSubstitution { private TypeSubstitution() {} @@ -13,8 +15,11 @@ public class TypeSubstitution { case BottomType bottomType -> type; - case ConstructedType constructedType -> - substituteConstructedType(constructedType, map); + case ConstructedStructType constructedType -> + substituteConstructedStructType(constructedType, map); + + case ConstructedSumType constructedType -> + substituteConstructedSumType(constructedType, map); case FunctionType functionType -> new FunctionType( Optional.empty(), @@ -66,11 +71,37 @@ public class TypeSubstitution { }; } - public static ConstructedType substituteConstructedType( + public static ConstructedStructType substituteConstructedStructType( + ConstructedStructType constructedType, + TypeSubstitutionMap map + ) { + return substituteConstructedType( + ConstructedStructType::new, + constructedType, + map + ); + } + + private static ConstructedSumType substituteConstructedSumType( + ConstructedSumType constructedType, + TypeSubstitutionMap map + ) { + return substituteConstructedType( + ConstructedSumType::new, + constructedType, + map + ); + } + + private static < + T extends StructuredType, + TConstructedType extends ConstructedType + > TConstructedType substituteConstructedType( + BiFunction, List, TConstructedType> createConstructedType, ConstructedType constructedType, TypeSubstitutionMap map ) { - return new ConstructedType<>( + return createConstructedType.apply( constructedType.constructor(), constructedType.args().stream() .map(arg -> substituteType(arg, map)) diff --git a/src/main/java/org/shedlang/compiler/types/Types.java b/src/main/java/org/shedlang/compiler/types/Types.java index d05f4665..dbf5b441 100644 --- a/src/main/java/org/shedlang/compiler/types/Types.java +++ b/src/main/java/org/shedlang/compiler/types/Types.java @@ -49,11 +49,31 @@ public class Types { return new TypeConstructor<>(params, genericType); } - public static ConstructedType constructedType( - TypeConstructor constructor, + @SuppressWarnings("unchecked") + public static ConstructedType constructedType( + TypeConstructor constructor, List args ) { - return new ConstructedType<>(constructor, args); + return switch (constructor.genericType()) { + case StructType structType -> + constructedStructType((TypeConstructor) constructor, args); + case SumType sumType -> + constructedSumType((TypeConstructor) constructor, args); + }; + } + + public static ConstructedStructType constructedStructType( + TypeConstructor constructor, + List args + ) { + return new ConstructedStructType(constructor, args); + } + + public static ConstructedSumType constructedSumType( + TypeConstructor constructor, + List args + ) { + return new ConstructedSumType(constructor, args); } public static Type commonSupertype(List subtypes) { -- cgit v1.2.3