diff options
| author | Michael Williamson <mike@zwobble.org> | 2026-10-16 08:21:19 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2026-10-16 08:21:19 +0100 |
| commit | 8fe3ffe8c7aad4c3270b889bce0efaf4ab912157 (patch) | |
| tree | 9f538e30de2edf5ee0ef4468f9f878f4726b1aac /src | |
| parent | 698596aeb11ed334d1edd95458561300d86f4d15 (diff) | |
Check row type is struct
Diffstat (limited to 'src')
3 files changed, 53 insertions, 4 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 eb3e09d..211726b 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java @@ -468,12 +468,18 @@ public class TypeChecker { UntypedTableDefinitionNode untyped, TypeCheckerNamespaceContext context ) { - var rowType = typeCheckMetaType(untyped.rowType(), context); + var rowTypeTypedNode = typeCheckMetaType(untyped.rowType(), context); + + if (!(rowTypeTypedNode.value() instanceof StructType rowType)) { + throw new TableRowTypeMustBeStructError( + rowTypeTypedNode.value(), + rowTypeTypedNode.source() + ); + } return new TypedTableDefinitionNode( untyped.name(), - // TODO: handle not struct type. - (StructType) rowType.value(), + rowType, // TODO: check primary key is valid. untyped.primaryKey(), untyped.docComment(), diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/TableRowTypeMustBeStructError.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/TableRowTypeMustBeStructError.java new file mode 100644 index 0000000..17b93d4 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/TableRowTypeMustBeStructError.java @@ -0,0 +1,18 @@ +package org.zwobble.hobgoblin.compiler.typechecker.errors; + +import org.zwobble.hobgoblin.compiler.errors.SourceError; +import org.zwobble.hobgoblin.compiler.sources.Source; +import org.zwobble.hobgoblin.compiler.types.Type; + +public class TableRowTypeMustBeStructError extends SourceError { + private final Type rowType; + + public TableRowTypeMustBeStructError(Type rowType, Source source) { + super("row types must be structs, but was " + rowType.describe(), source); + this.rowType = rowType; + } + + public Type rowType() { + return rowType; + } +} diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTableDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTableDefinitionTests.java index 7c08688..a4e1cf4 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTableDefinitionTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTableDefinitionTests.java @@ -4,10 +4,13 @@ import org.junit.jupiter.api.Test; import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode; import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode; import org.zwobble.hobgoblin.compiler.sources.NullSource; +import org.zwobble.hobgoblin.compiler.typechecker.errors.TableRowTypeMustBeStructError; import org.zwobble.hobgoblin.compiler.types.NamespaceName; +import org.zwobble.hobgoblin.compiler.types.SimpleNativeType; import org.zwobble.hobgoblin.compiler.types.SimpleStructType; import org.zwobble.hobgoblin.compiler.types.Types; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.zwobble.hobgoblin.compiler.ast.typed.TypedTableDefinitionNodeMatcher.isTypedTableDefinitionNode; import static org.zwobble.hobgoblin.compiler.typechecker.TypeChecker.typeCheckDatabaseSchemaStatement; import static org.zwobble.precisely.AssertThat.assertThat; @@ -15,7 +18,7 @@ import static org.zwobble.precisely.Matchers.equalTo; public class TypeCheckerTableDefinitionTests { @Test - public void databaseSchemaStatementsAreTypeChecked() { + public void minimalTableDefinition() { var untyped = UntypedTableDefinitionNode.arbitrary() .withName("authors") .withRowType(UntypedTypeLevelReferenceNode.arbitrary() @@ -35,4 +38,26 @@ public class TypeCheckerTableDefinitionTests { .withRowType(equalTo(authorType)) ); } + + @Test + public void whenRowTypeIsNotStructTypeThenErrorIsThrown() { + var untyped = UntypedTableDefinitionNode.arbitrary() + .withName("authors") + .withRowType(UntypedTypeLevelReferenceNode.arbitrary() + .withName("Author") + .build() + ) + .build(); + var globalContext = TypeCheckerContextArb.globalContext(); + var namespaceContext = globalContext.enterNamespace(NamespaceName.of("App")); + var authorType = new SimpleNativeType(NamespaceName.of("App"), "Author"); + namespaceContext.declare("Author", Types.metaType(authorType), NullSource.INSTANCE); + + var error = assertThrows( + TableRowTypeMustBeStructError.class, + () -> typeCheckDatabaseSchemaStatement(untyped, namespaceContext) + ); + + assertThat(error.rowType(), equalTo(authorType)); + } } |
