From e0f232e9ad7fbe304e99bb4e880c761f06255791 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Tue, 26 Dec 2023 18:17:59 +0000 Subject: Support constructed struct type constructors --- .../compiler/ast/untyped/UntypedArgsNode.java | 7 +++ .../compiler/ast/untyped/UntypedCallNode.java | 18 +++++++ .../shedlang/compiler/typechecker/TypeChecker.java | 61 +++++++++++++++++----- .../compiler/typechecker/TypeCheckerContext.java | 18 +++++++ 4 files changed, 92 insertions(+), 12 deletions(-) (limited to 'src/main/java') 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 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) 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 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 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)); -- cgit v1.2.3