From c8b1f9139439ca6096e82f4b98a9baccba5807fe Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sun, 14 Jan 2024 10:48:53 +0000 Subject: Support inferring type args in when cases --- .../shedlang/compiler/typechecker/TypeChecker.java | 41 +++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) (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 08600f43..187442a8 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java @@ -2101,18 +2101,20 @@ public class TypeChecker { ? Optional.of(expressionReference.name()) : Optional.empty(); + var variantTypes = expressionTypeInfo.variants(); + var typedCasesResult = context.mapWithContext( untyped.cases(), (untypedWhenCase, whenCaseContext) -> typeCheckWhenCase( untypedWhenCase, variableName, + variantTypes, whenCaseContext ) ); var typedCases = typedCasesResult.value(); context = typedCasesResult.context(); - var variantTypes = expressionTypeInfo.variants(); var handledVariantTypes = new HashSet(); for (var typedCase : typedCases) { @@ -2149,15 +2151,46 @@ public class TypeChecker { private static TypeCheckerResult typeCheckWhenCase( UntypedWhenCaseNode untyped, Optional variableName, + OrderedPSet variantTypes, TypeCheckerContext context ) { var typedCaseType = typeCheckTypeLevelExpression( - TypeSets.STRUCT_META_TYPE, untyped.caseType(), context ); - var variant = typedCaseType.value(); + var variant = switch (typedCaseType.value()) { + case StructType variantStructType -> + variantStructType; + + case TypeConstructor variantTypeConstructor when + variantTypeConstructor.genericType() instanceof StructType genericStructType -> { + + var matchingVariantTypes = variantTypes.stream() + .filter( + variantType -> variantType instanceof ConstructedType variantTypeConstructed && + variantTypeConstructed.genericType().equals(genericStructType) + ) + .toList(); + + if (matchingVariantTypes.size() == 1) { + yield matchingVariantTypes.get(0); + } else { + throw new UnexpectedTypeError( + TypeSets.STRUCT_META_TYPE, + Types.typeLevelValueType(typedCaseType.value()), + typedCaseType.source() + ); + } + } + + default -> + throw new UnexpectedTypeError( + TypeSets.STRUCT_META_TYPE, + Types.typeLevelValueType(typedCaseType.value()), + typedCaseType.source() + ); + }; var declaredVariables = DeclaredVariables.forFunctionStatements( untyped.body().statements(), @@ -2168,7 +2201,7 @@ public class TypeChecker { context = context.enterBlock(bodyEnvironment.build()); if (variableName.isPresent()) { - context = context.updateType(variableName.get(), typedCaseType.value(), untyped.source()); + context = context.updateType(variableName.get(), variant, untyped.source()); } var typedBodyResult = typeCheckBlock(untyped.body(), bodyEnvironment.toBoundVariables(), context); -- cgit v1.2.3