diff options
8 files changed, 70 insertions, 20 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/DuplicateVariableNameError.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/DuplicateVariableNameError.java new file mode 100644 index 0000000..1fc79bf --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/DuplicateVariableNameError.java @@ -0,0 +1,17 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.zwobble.hobgoblin.compiler.errors.SourceError; +import org.zwobble.hobgoblin.compiler.sources.Source; + +public class DuplicateVariableNameError extends SourceError { + private final String name; + + public DuplicateVariableNameError(String name, Source source) { + super("A variable with the name " + name + " has already been declared", source); + this.name = name; + } + + public String name() { + return name; + } +} 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 f313333..793e1f6 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java @@ -40,7 +40,7 @@ public class TypeChecker { importedNamespace, untypedImport.source() )); - namespaceContext.declare(importedName, fieldType); + namespaceContext.declare(importedName, fieldType, untypedImport.source()); } } @@ -109,7 +109,7 @@ public class TypeChecker { ) { var nativeType = new EnumType(context.namespaceName(), untyped.name()); var metaType = new TypeLevelValueType(nativeType); - context.declare(untyped.name(), metaType); + context.declare(untyped.name(), metaType, untyped.source()); return metaType; } @@ -146,7 +146,7 @@ public class TypeChecker { ) { var nativeType = new SimpleNativeType(context.namespaceName(), untyped.name()); var metaType = new TypeLevelValueType(nativeType); - context.declare(untyped.name(), metaType); + context.declare(untyped.name(), metaType, untyped.source()); return metaType; } @@ -169,7 +169,7 @@ public class TypeChecker { ) { var structType = new StructType(context.namespaceName(), untyped.name()); var metaType = new TypeLevelValueType(structType); - context.declare(untyped.name(), metaType); + context.declare(untyped.name(), metaType, untyped.source()); return metaType; } @@ -233,7 +233,7 @@ public class TypeChecker { ) { var sumType = new SumType(context.namespaceName(), untyped.name()); var metaType = new TypeLevelValueType(sumType); - context.declare(untyped.name(), metaType); + context.declare(untyped.name(), metaType, untyped.source()); return metaType; } 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 82c8273..51e11d6 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java @@ -1,5 +1,6 @@ package org.zwobble.hobgoblin.compiler.typechecker; +import org.zwobble.hobgoblin.compiler.sources.Source; import org.zwobble.hobgoblin.compiler.types.*; import java.util.HashMap; @@ -43,8 +44,11 @@ public class TypeCheckerNamespaceContext { return this.namespaceName; } - public void declare(String name, Type type) { - // TODO: Check variable is not already declared. + public void declare(String name, Type type, Source source) { + if (this.variables.containsKey(name)) { + throw new DuplicateVariableNameError(name, source); + } + this.variables.put(name, type); } diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerConstructedTypeTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerConstructedTypeTests.java index ef55465..fa511ba 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerConstructedTypeTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerConstructedTypeTests.java @@ -2,6 +2,7 @@ package org.zwobble.hobgoblin.compiler.typechecker; import org.junit.jupiter.api.Test; import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedArb; +import org.zwobble.hobgoblin.compiler.sources.NullSource; import org.zwobble.hobgoblin.compiler.types.*; import java.util.List; @@ -20,9 +21,9 @@ public class TypeCheckerConstructedTypeTests { var context = TypeCheckerContextArb.namespaceContext(); var listType = SimpleNativeType.builtin("List"); var listTypeConstructor = new TypeConstructor<>(List.of(new TypeParam("T")), listType); - context.declare("List", new TypeLevelValueType(listTypeConstructor)); + context.declare("List", new TypeLevelValueType(listTypeConstructor), NullSource.INSTANCE); var int32Type = SimpleNativeType.builtin("Int32"); - context.declare("Int32", new TypeLevelValueType(int32Type)); + context.declare("Int32", new TypeLevelValueType(int32Type), NullSource.INSTANCE); var typed = TypeChecker.typeCheckTypeLevelExpression(untyped, context); diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerMetaTypeTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerMetaTypeTests.java index 1f966b1..2c37d22 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerMetaTypeTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerMetaTypeTests.java @@ -3,6 +3,7 @@ package org.zwobble.hobgoblin.compiler.typechecker; import org.junit.jupiter.api.Test; import org.zwobble.hobgoblin.compiler.ast.typed.TypedTypeLevelReferenceNode; import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedArb; +import org.zwobble.hobgoblin.compiler.sources.NullSource; import org.zwobble.hobgoblin.compiler.types.*; import java.util.List; @@ -18,7 +19,7 @@ public class TypeCheckerMetaTypeTests { var untyped = UntypedArb.typeLevelReference("X"); var context = TypeCheckerContextArb.namespaceContext(); var nativeType = SimpleNativeType.builtin("Int"); - context.declare("X", nativeType); + context.declare("X", nativeType, NullSource.INSTANCE); var error = assertThrows( UnexpectedTypeError.class, @@ -34,7 +35,7 @@ public class TypeCheckerMetaTypeTests { var untyped = UntypedArb.typeLevelReference("List"); var context = TypeCheckerContextArb.namespaceContext(); var typeConstructor = new TypeConstructor<>(List.of(new TypeParam("T")), SimpleNativeType.builtin("List")); - context.declare("List", new TypeLevelValueType(typeConstructor)); + context.declare("List", new TypeLevelValueType(typeConstructor), NullSource.INSTANCE); var error = assertThrows( UnexpectedTypeError.class, @@ -50,7 +51,7 @@ public class TypeCheckerMetaTypeTests { var untyped = UntypedArb.typeLevelReference("X"); var context = TypeCheckerContextArb.namespaceContext(); var nativeType = SimpleNativeType.builtin("Int"); - context.declare("X", new TypeLevelValueType(nativeType)); + context.declare("X", new TypeLevelValueType(nativeType), NullSource.INSTANCE); var typed = TypeChecker.typeCheckMetaType(untyped, context); diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContextTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContextTests.java new file mode 100644 index 0000000..72c9702 --- /dev/null +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContextTests.java @@ -0,0 +1,26 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.junit.jupiter.api.Test; +import org.zwobble.hobgoblin.compiler.sources.NullSource; +import org.zwobble.hobgoblin.compiler.types.NamespaceName; +import org.zwobble.hobgoblin.compiler.types.SumType; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.zwobble.precisely.AssertThat.assertThat; +import static org.zwobble.precisely.Matchers.equalTo; + +public class TypeCheckerNamespaceContextTests { + @Test + public void declaringVariablesWithSameThrowsError() { + var context = TypeCheckerGlobalContext.initial() + .enterNamespace(NamespaceName.of()); + context.declare("Shape", new SumType(NamespaceName.of(), "Shape"), NullSource.INSTANCE); + + var error = assertThrows( + DuplicateVariableNameError.class, + () -> context.declare("Shape", new SumType(NamespaceName.of(), "Shape"), NullSource.INSTANCE) + ); + + assertThat(error.name(), equalTo("Shape")); + } +} diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java index 597fb42..718460f 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerSumDefinitionTests.java @@ -50,8 +50,8 @@ public class TypeCheckerSumDefinitionTests { var globalContext = TypeCheckerGlobalContext.initial(); var namespaceContext = globalContext .enterNamespace(NamespaceName.of("a", "b")); - namespaceContext.declare(rectangleType.name(), new TypeLevelValueType(rectangleType)); - namespaceContext.declare(triangleType.name(), new TypeLevelValueType(triangleType)); + namespaceContext.declare(rectangleType.name(), new TypeLevelValueType(rectangleType), NullSource.INSTANCE); + namespaceContext.declare(triangleType.name(), new TypeLevelValueType(triangleType), NullSource.INSTANCE); var typed = typeCheckNamespaceStatement(untyped, namespaceContext); @@ -156,7 +156,7 @@ public class TypeCheckerSumDefinitionTests { var namespaceContext = globalContext .enterNamespace(namespaceName); var variantType = new StructType(namespaceName, "Square"); - namespaceContext.declare("Square", new TypeLevelValueType(variantType)); + namespaceContext.declare("Square", new TypeLevelValueType(variantType), NullSource.INSTANCE); namespaceContext.defineStructType(variantType, List.of()); var error = assertThrows( @@ -193,7 +193,7 @@ public class TypeCheckerSumDefinitionTests { var namespaceContext = globalContext .enterNamespace(namespaceName); var variantType = new StructType(namespaceName, "Square"); - namespaceContext.declare("Square", new TypeLevelValueType(variantType)); + namespaceContext.declare("Square", new TypeLevelValueType(variantType), NullSource.INSTANCE); namespaceContext.defineStructType(variantType, List.of(new Field("area", int64Type, NullSource.INSTANCE))); // TODO: more specific error @@ -229,7 +229,7 @@ public class TypeCheckerSumDefinitionTests { var namespaceContext = globalContext .enterNamespace(namespaceName); var variantType = new StructType(namespaceName, "Square"); - namespaceContext.declare("Square", new TypeLevelValueType(variantType)); + namespaceContext.declare("Square", new TypeLevelValueType(variantType), NullSource.INSTANCE); namespaceContext.defineStructType(variantType, List.of()); assertThrows( @@ -251,7 +251,7 @@ public class TypeCheckerSumDefinitionTests { .enterNamespace(namespaceName); var sumType = new SumType(namespaceName, "Shape"); var variantType = new StructType(namespaceName, "Square"); - namespaceContext.declare("Sum", new TypeLevelValueType(sumType)); + namespaceContext.declare("Sum", new TypeLevelValueType(sumType), NullSource.INSTANCE); namespaceContext.defineSumType( sumType, List.of(variantType), diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTypeLevelReferenceTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTypeLevelReferenceTests.java index 0924eee..bb99952 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTypeLevelReferenceTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTypeLevelReferenceTests.java @@ -3,6 +3,7 @@ package org.zwobble.hobgoblin.compiler.typechecker; import org.junit.jupiter.api.Test; import org.zwobble.hobgoblin.compiler.ast.typed.TypedTypeLevelReferenceNode; import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedArb; +import org.zwobble.hobgoblin.compiler.sources.NullSource; import org.zwobble.hobgoblin.compiler.types.SimpleNativeType; import org.zwobble.hobgoblin.compiler.types.TypeLevelValueType; import org.zwobble.hobgoblin.compiler.types.TypeSet; @@ -30,7 +31,7 @@ public class TypeCheckerTypeLevelReferenceTests { var untyped = UntypedArb.typeLevelReference("X"); var context = TypeCheckerContextArb.namespaceContext(); var nativeType = SimpleNativeType.builtin("Int"); - context.declare("X", nativeType); + context.declare("X", nativeType, NullSource.INSTANCE); var error = assertThrows( UnexpectedTypeError.class, @@ -46,7 +47,7 @@ public class TypeCheckerTypeLevelReferenceTests { var untyped = UntypedArb.typeLevelReference("X"); var context = TypeCheckerContextArb.namespaceContext(); var nativeType = SimpleNativeType.builtin("Int"); - context.declare("X", new TypeLevelValueType(nativeType)); + context.declare("X", new TypeLevelValueType(nativeType), NullSource.INSTANCE); var typed = TypeChecker.typeCheckTypeLevelExpression(untyped, context); |
