diff options
| author | Michael Williamson <mike@zwobble.org> | 2024-01-14 10:48:53 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2024-01-14 10:48:53 +0000 |
| commit | c8b1f9139439ca6096e82f4b98a9baccba5807fe (patch) | |
| tree | ca9435281473e7d3c9a1692f6085e7158c18cee9 /src/main/java | |
| parent | 6920b525a9a7e37f0e5436612d1fc7517b8212d0 (diff) | |
Support inferring type args in when cases
Diffstat (limited to 'src/main/java')
| -rw-r--r-- | src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java | 41 |
1 files changed, 37 insertions, 4 deletions
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.<String>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<Type>(); for (var typedCase : typedCases) { @@ -2149,15 +2151,46 @@ public class TypeChecker { private static TypeCheckerResult<TypedWhenCaseNode> typeCheckWhenCase( UntypedWhenCaseNode untyped, Optional<String> variableName, + OrderedPSet<StructType> 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); |
