summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java8
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UnknownNamespaceFieldError.java24
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/Fields.java7
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceTests.java26
4 files changed, 59 insertions, 6 deletions
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 e9e7e74..78bdc97 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
@@ -31,7 +31,13 @@ public class TypeChecker {
var importedNamespaceFields = context.namespaceFields(importedNamespace);
for (var importedName : untypedImport.importedNames()) {
- namespaceContext.declare(importedName, importedNamespaceFields.get(importedName));
+ var fieldType = importedNamespaceFields.fieldType(importedName)
+ .orElseThrow(() -> new UnknownNamespaceFieldError(
+ importedName,
+ importedNamespace,
+ untypedImport.source()
+ ));
+ namespaceContext.declare(importedName, fieldType);
}
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UnknownNamespaceFieldError.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UnknownNamespaceFieldError.java
new file mode 100644
index 0000000..52f8b0a
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UnknownNamespaceFieldError.java
@@ -0,0 +1,24 @@
+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.NamespaceName;
+
+public class UnknownNamespaceFieldError extends SourceError {
+ private final String fieldName;
+ private final NamespaceName namespaceName;
+
+ public UnknownNamespaceFieldError(String fieldName, NamespaceName namespaceName, Source source) {
+ super("Unknown field " + fieldName + " on " + namespaceName, source);
+ this.fieldName = fieldName;
+ this.namespaceName = namespaceName;
+ }
+
+ public String fieldName() {
+ return fieldName;
+ }
+
+ public NamespaceName namespaceName() {
+ return namespaceName;
+ }
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/Fields.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/Fields.java
index 4fc364e..013a844 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/types/Fields.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/Fields.java
@@ -1,6 +1,7 @@
package org.zwobble.hobgoblin.compiler.types;
import java.util.List;
+import java.util.Optional;
public class Fields {
private final List<Field> fields;
@@ -9,12 +10,10 @@ public class Fields {
this.fields = fields;
}
- public Type get(String name) {
+ public Optional<Type> fieldType(String name) {
return fields.stream()
.filter(field -> field.name().equals(name))
.findFirst()
- // TODO: better error handling
- .orElseThrow()
- .type();
+ .map(field -> field.type());
}
}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceTests.java
index c4b31b8..3559578 100644
--- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceTests.java
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceTests.java
@@ -9,6 +9,7 @@ import org.zwobble.hobgoblin.compiler.types.*;
import java.util.List;
import java.util.Optional;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.zwobble.hobgoblin.compiler.types.TypeMatchers.isMetaType;
import static org.zwobble.precisely.AssertThat.assertThat;
import static org.zwobble.precisely.Matchers.*;
@@ -42,7 +43,7 @@ public class TypeCheckerNamespaceTests {
))
));
assertThat(
- context.namespaceFields(NamespaceName.of("a", "b")).get("X"),
+ context.namespaceFields(NamespaceName.of("a", "b")).fieldType("X").orElseThrow(),
isMetaType(new StructType(NamespaceName.of("a", "b"), "X"))
);
}
@@ -97,4 +98,27 @@ public class TypeCheckerNamespaceTests {
)
);
}
+
+ @Test
+ public void whenNamespaceHasNoSuchFieldThenErrorIsThrown() {
+ var untyped = UntypedNamespaceNode.arbitrary()
+ .withImports(List.of(
+ UntypedImportNode.arbitrary()
+ .withAncestorDepth(Optional.empty())
+ .withNamespaceName(NamespaceName.of("a"))
+ .withImportedNames(List.of("A"))
+ .build()
+ ))
+ .build();
+ var context = TypeCheckerContextArb.globalContext();
+ context.defineNamespace(NamespaceName.of("a"), List.of());
+
+ var error = assertThrows(
+ UnknownNamespaceFieldError.class,
+ () -> TypeChecker.typeCheckNamespace(untyped, context)
+ );
+
+ assertThat(error.fieldName(), equalTo("A"));
+ assertThat(error.namespaceName(), equalTo(NamespaceName.of("a")));
+ }
}