summaryrefslogtreecommitdiff
path: root/src/main/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/SubtypeIsMissingFieldError.java38
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java50
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java6
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java25
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java8
5 files changed, 112 insertions, 15 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/SubtypeIsMissingFieldError.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/SubtypeIsMissingFieldError.java
new file mode 100644
index 0000000..ce59593
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/SubtypeIsMissingFieldError.java
@@ -0,0 +1,38 @@
+package org.zwobble.hobgoblin.compiler.typechecker;
+
+import org.zwobble.hobgoblin.compiler.errors.SourceError;
+import org.zwobble.hobgoblin.compiler.sources.Source;
+import org.zwobble.hobgoblin.compiler.types.Type;
+
+public class SubtypeIsMissingFieldError extends SourceError {
+ private final Type supertype;
+ private final Type subtype;
+ private final String fieldName;
+
+ public SubtypeIsMissingFieldError(Type supertype, Type subtype, String fieldName, Source source) {
+ super(
+ String.format(
+ "%s is a subtype of %s, but is missing field %s",
+ subtype.describe(),
+ supertype.describe(),
+ fieldName
+ ),
+ source
+ );
+ this.supertype = supertype;
+ this.subtype = subtype;
+ this.fieldName = fieldName;
+ }
+
+ public Type supertype() {
+ return supertype;
+ }
+
+ public Type subtype() {
+ return subtype;
+ }
+
+ public String fieldName() {
+ return fieldName;
+ }
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
index c291aaf..c6f8721 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
@@ -2,6 +2,7 @@ package org.zwobble.hobgoblin.compiler.typechecker;
import org.zwobble.hobgoblin.compiler.ast.typed.*;
import org.zwobble.hobgoblin.compiler.ast.untyped.*;
+import org.zwobble.hobgoblin.compiler.sources.NullSource;
import org.zwobble.hobgoblin.compiler.sources.Source;
import org.zwobble.hobgoblin.compiler.types.*;
@@ -183,6 +184,17 @@ public class TypeChecker {
context.defineStructType(structType, typeCheckedFieldDefinitions.fields());
+ for (var sumType : context.variantOf(structType)) {
+ // TODO: better error if sum type fields aren't defined
+ var sumTypeFields = context.fieldsOf(sumType).orElseThrow();
+ typeCheckVariantType(
+ sumType,
+ sumTypeFields,
+ structType,
+ typeCheckedFieldDefinitions.fields
+ );
+ }
+
return new TypedStructDefinitionNode(
structType,
typeCheckedFieldDefinitions.typedFieldNodes(),
@@ -233,8 +245,7 @@ public class TypeChecker {
var sumType = (SumType) lookupMetaType(untyped.name(), untyped.source(), context);
var typedVariants = new ArrayList<TypedSumVariantDefinitionNode>();
- // TODO: should be StructType?
- var variantTypes = new ArrayList<Type>();
+ var variantTypes = new ArrayList<StructType>();
for (var untypedVariant : untyped.variants()) {
var variantType = typeCheckMetaType(untypedVariant.type(), context);
var typedVariant = new TypedSumVariantDefinitionNode(
@@ -242,12 +253,25 @@ public class TypeChecker {
untyped.source()
);
typedVariants.add(typedVariant);
- variantTypes.add(variantType.value());
+ // TODO: handle not struct type
+ variantTypes.add((StructType) variantType.value());
}
var typeCheckedFieldDefinitions = typeCheckFieldDefinitions(untyped.fields(), context);
- context.defineSumType(sumType, variantTypes);
+ context.defineSumType(sumType, variantTypes, typeCheckedFieldDefinitions.fields);
+
+ for (var variantType : variantTypes) {
+ var variantTypeFields = context.fieldsOf(variantType);
+ if (variantTypeFields.isPresent()) {
+ typeCheckVariantType(
+ sumType,
+ typeCheckedFieldDefinitions.fields,
+ variantType,
+ variantTypeFields.get()
+ );
+ }
+ }
return new TypedSumDefinitionNode(
sumType,
@@ -274,6 +298,24 @@ public class TypeChecker {
}
}
+ private static void typeCheckVariantType(
+ SumType sumType,
+ List<Field> sumTypeFields,
+ StructType variantType,
+ List<Field> variantTypeFields
+ ) {
+ for (var sumTypeField : sumTypeFields) {
+ var variantTypeField = variantTypeFields.stream()
+ .filter(field -> field.name().equals(sumTypeField.name()))
+ .findFirst();
+
+ if (variantTypeField.isEmpty()) {
+ // TODO: set source appropriately.
+ throw new SubtypeIsMissingFieldError(sumType, variantType, sumTypeField.name(), NullSource.INSTANCE);
+ }
+ }
+ }
+
static TypedTypeLevelExpressionNode<? extends TypeLevelValue> typeCheckTypeLevelExpression(
UntypedTypeLevelExpressionNode untyped,
TypeCheckerNamespaceContext context
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java
index 3e7665c..ca2d731 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java
@@ -8,7 +8,7 @@ import java.util.*;
public class TypeCheckerGlobalContext {
private final Map<String, Type> nativeTypes = new HashMap<>();
private final Map<EnumType, List<EnumVariant>> enumVariants = new HashMap<>();
- private final Map<StructType, List<Field>> structFieldsOf = new HashMap<>();
+ private final Map<Type, List<Field>> fieldsOf = new HashMap<>();
private final Map<NamespaceName, Fields> namespaceFieldsOf = new HashMap<>();
private final ManyToMany<SumType, Type> sumVariants = new ManyToMany<>();
@@ -22,7 +22,7 @@ public class TypeCheckerGlobalContext {
public TypesInfo toTypesInfo() {
return new TypesInfo(
this.enumVariants,
- this.structFieldsOf,
+ this.fieldsOf,
this.sumVariants
);
}
@@ -40,7 +40,7 @@ public class TypeCheckerGlobalContext {
namespaceName,
this.nativeTypes,
this.enumVariants,
- this.structFieldsOf,
+ this.fieldsOf,
this.sumVariants
);
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java
index 906cdfa..0df7e16 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java
@@ -13,7 +13,7 @@ public class TypeCheckerNamespaceContext {
NamespaceName namespaceName,
Map<String, Type> nativeTypes,
Map<EnumType, List<EnumVariant>> enumVariants,
- Map<StructType, List<Field>> fieldsOf,
+ Map<Type, List<Field>> fieldsOf,
ManyToMany<SumType, Type> variants
) {
return new TypeCheckerNamespaceContext(
@@ -28,14 +28,14 @@ public class TypeCheckerNamespaceContext {
private final NamespaceName namespaceName;
private final Map<String, Type> variables;
private final Map<EnumType, List<EnumVariant>> enumVariants;
- private final Map<StructType, List<Field>> fieldsOf;
+ private final Map<Type, List<Field>> fieldsOf;
private final ManyToMany<SumType, Type> sumVariants;
private TypeCheckerNamespaceContext(
NamespaceName namespaceName,
Map<String, Type> variables,
Map<EnumType, List<EnumVariant>> enumVariants,
- Map<StructType, List<Field>> fieldsOf,
+ Map<Type, List<Field>> fieldsOf,
ManyToMany<SumType, Type> sumVariants
) {
this.namespaceName = namespaceName;
@@ -66,9 +66,26 @@ public class TypeCheckerNamespaceContext {
this.fieldsOf.put(structType, fields);
}
- public void defineSumType(SumType sumType, List<Type> variantTypes) {
+ public Optional<List<Field>> fieldsOf(StructType type) {
+ return Optional.ofNullable(this.fieldsOf.get(type));
+ }
+
+ public void defineSumType(
+ SumType sumType,
+ List<StructType> variantTypes,
+ List<Field> fields
+ ) {
for (var variantType : variantTypes) {
this.sumVariants.add(sumType, variantType);
}
+ this.fieldsOf.put(sumType, fields);
+ }
+
+ public List<SumType> variantOf(StructType variantType) {
+ return this.sumVariants.rightToLeft(variantType);
+ }
+
+ public Optional<List<Field>> fieldsOf(SumType type) {
+ return Optional.ofNullable(this.fieldsOf.get(type));
}
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java
index 0fb4f81..63d21b6 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java
@@ -9,16 +9,16 @@ import java.util.Optional;
public class TypesInfo {
private final Map<EnumType, List<EnumVariant>> enumVariants;
- private final Map<StructType, List<Field>> structFieldsOf;
+ private final Map<Type, List<Field>> fieldsOf;
private final ManyToMany<SumType, Type> sumVariants;
public TypesInfo(
Map<EnumType, List<EnumVariant>> enumVariants,
- Map<StructType, List<Field>> structFieldsOf,
+ Map<Type, List<Field>> fieldsOf,
ManyToMany<SumType, Type> sumVariants
) {
this.enumVariants = enumVariants;
- this.structFieldsOf = structFieldsOf;
+ this.fieldsOf = fieldsOf;
this.sumVariants = sumVariants;
}
@@ -28,7 +28,7 @@ public class TypesInfo {
public List<Field> fieldsOf(StructType structType) {
// TODO: handle error better
- return Optional.ofNullable(this.structFieldsOf.get(structType)).orElseThrow();
+ return Optional.ofNullable(this.fieldsOf.get(structType)).orElseThrow();
}
public List<SumType> variantOf(StructType variantType) {