aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-12-26 18:17:59 +0000
committerMichael Williamson <mike@zwobble.org>2023-12-26 18:17:59 +0000
commite0f232e9ad7fbe304e99bb4e880c761f06255791 (patch)
treee8b85f8d455430474d4a7f85feef62dd6feab215 /src/main/java
parent92431737b02154be7500d5df18a5b4fc883c5fd1 (diff)
Support constructed struct type constructors
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/shedlang/compiler/ast/untyped/UntypedArgsNode.java7
-rw-r--r--src/main/java/org/shedlang/compiler/ast/untyped/UntypedCallNode.java18
-rw-r--r--src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java61
-rw-r--r--src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java18
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));