diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-12-26 18:17:59 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-12-26 18:17:59 +0000 |
| commit | e0f232e9ad7fbe304e99bb4e880c761f06255791 (patch) | |
| tree | e8b85f8d455430474d4a7f85feef62dd6feab215 /src/main/java | |
| parent | 92431737b02154be7500d5df18a5b4fc883c5fd1 (diff) | |
Support constructed struct type constructors
Diffstat (limited to 'src/main/java')
4 files changed, 92 insertions, 12 deletions
diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedArgsNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedArgsNode.java index 202cb888..177982ea 100644 --- a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedArgsNode.java +++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedArgsNode.java @@ -27,6 +27,13 @@ public record UntypedArgsNode( return new UntypedArgsNode(positional, named, Sources.NULL); } + public Builder addPositionalArg(UntypedExpressionNode arg) { + return new Builder( + this.positional.plus(arg), + this.named + ); + } + public Builder addNamedArg(UntypedNamedArgNode arg) { return new Builder( this.positional, diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedCallNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedCallNode.java index e9624263..73219c47 100644 --- a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedCallNode.java +++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedCallNode.java @@ -47,6 +47,24 @@ public record UntypedCallNode( ); } + public Builder withTypeLevelArgs(List<UntypedTypeLevelExpressionNode> typeLevelArgs) { + return new Builder( + this.receiver, + Optional.of(typeLevelArgs), + this.args, + this.hasEffects + ); + } + + public Builder addPositionalArg(UntypedExpressionNode arg) { + return new Builder( + this.receiver, + this.typeLevelArgs, + this.args.addPositionalArg(arg), + this.hasEffects + ); + } + public Builder addNamedArg(UntypedNamedArgNode arg) { return new Builder( this.receiver, diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java index 2eef55f1..ac3fde79 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java @@ -326,7 +326,28 @@ public class TypeChecker { var typedReceiver = receiverResult.value(); context = receiverResult.context(); - var receiverType = receiverTypeToFunctionType(typedReceiver, context); + var contextForReceiver = context; + var receiverType = untyped.typeLevelArgs() + .map(untypedTypeLevelArgNodes -> { + var typeLevelArgs = untypedTypeLevelArgNodes.stream() + .map(argNode -> typeCheckTypeExpression(argNode, contextForReceiver).value()) + .toList(); + + if ( + typedReceiver.type() instanceof TypeLevelValueType initialReceiverType && + initialReceiverType.value() instanceof TypeConstructor<?> typeConstructor + ) { + // TODO: check args + return receiverTypeToFunctionType( + Types.metaType(Types.constructedType(typeConstructor, typeLevelArgs)), + typedReceiver.source(), + contextForReceiver + ); + } else { + throw new IllegalArgumentException("TODO"); + } + }) + .orElseGet(() -> receiverTypeToFunctionType(typedReceiver, contextForReceiver)); var argsResult = typeCheckArgs(untyped.args(), context, receiverType); var typedArgs = argsResult.value(); @@ -381,20 +402,20 @@ public class TypeChecker { if ( receiverType instanceof TypeLevelValueType typeLevelValueType && - typeLevelValueType.value() instanceof StructType structType + typeLevelValueType.value() instanceof StructType structType ) { var structTypeInfo = context.structTypeInfo(structType, receiverSource); + return receiverStructTypeInfoToFunctionType(structType, structTypeInfo); + } - var namedParams = structTypeInfo.fields().stream() - .map(field -> new NamedParam(field.name(), field.type())) - .toList(); - - return new FunctionType( - List.of(), - namedParams, - Effects.NONE, - structType - ); + if ( + receiverType instanceof TypeLevelValueType typeLevelValueType && + typeLevelValueType.value() instanceof ConstructedType<?> constructedType && + constructedType.genericType() instanceof StructType structType + ) { + // TODO: make specific constructed types to avoid generic casting? + var structTypeInfo = context.structTypeInfo((ConstructedType<StructType>) constructedType, receiverSource); + return receiverStructTypeInfoToFunctionType(constructedType, structTypeInfo); } throw new UnexpectedTypeError( @@ -404,6 +425,22 @@ public class TypeChecker { ); } + private static FunctionType receiverStructTypeInfoToFunctionType( + Type structType, + StructTypeInfo structTypeInfo + ) { + var namedParams = structTypeInfo.fields().stream() + .map(field -> new NamedParam(field.name(), field.type())) + .toList(); + + return new FunctionType( + List.of(), + namedParams, + Effects.NONE, + structType + ); + } + private static TypeCheckerResult<TypedConditionalBranchNode> typeCheckConditionalBranch( UntypedConditionalBranchNode conditionalBranch, TypeCheckerContext context diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java b/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java index d783aafe..dcaa9226 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java @@ -443,6 +443,24 @@ public class TypeCheckerContext { ); } + public StructTypeInfo structTypeInfo(ConstructedType<StructType> type, Source source) { + var typeInfo = this.typeInfos.structTypeInfo(type.genericType()) + .orElseThrow(() -> new MissingStructTypeInfoError(type.genericType(), source)); + + var typeSubstitutionMap = type.typeSubstitutionMap(); + + var fieldsInfoBuilder = FieldsInfo.builder(); + + for (var field : typeInfo.fields()) { + fieldsInfoBuilder = fieldsInfoBuilder.addField( + field.name(), + TypeSubstitution.substitute(field.type(), typeSubstitutionMap) + ); + } + + return new StructTypeInfo(fieldsInfoBuilder.build()); + } + public StructTypeInfo structTypeInfo(StructType type, Source source) { return this.typeInfos.structTypeInfo(type) .orElseThrow(() -> new MissingStructTypeInfoError(type, source)); |
