commit f84e891ddd0cbdc6471ef97300e3a27960bf1152
parent 5ea0e291896fa9cf6b67af8c5089ada284f47b8c
Author: Bor Grošelj Simić <bgs@turminal.net>
Date: Sat, 21 May 2022 03:03:07 +0200
handle circular dependencies in enums
Signed-off-by: Bor Grošelj Simić <bgs@turminal.net>
Diffstat:
2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/src/check.c b/src/check.c
@@ -3685,9 +3685,21 @@ scan_decl_finish(struct context *ctx, const struct scope_object *obj,
// load this declaration's subunit context
ctx->unit->parent = idecl->imports;
+ // resolving a declaration that is already in progress -> cycle
+ if (idecl->in_progress) {
+ struct location *loc;
+ if (idecl->type == IDECL_ENUM_FLD) {
+ loc = &idecl->field->type->loc;
+ } else {
+ loc = &idecl->decl.loc;
+ }
+ expect(loc, false, "Circular dependency for '%s'\n",
+ identifier_unparse(&idecl->obj.ident));
+ }
+ idecl->in_progress = true;
+
switch (idecl->type) {
case IDECL_ENUM_FLD:
- // TODO handle circular enum dependencies
obj = scan_enum_field(ctx, idecl);
goto exit;
case IDECL_ENUM_TYPE:
@@ -3697,14 +3709,6 @@ scan_decl_finish(struct context *ctx, const struct scope_object *obj,
break;
}
- // resolving a declaration that is already in progress -> cycle
- if (idecl->in_progress) {
- expect(&idecl->decl.loc, false,
- "Circular dependency for '%s'\n",
- identifier_unparse(&idecl->obj.ident));
- }
- idecl->in_progress = true;
-
switch (idecl->decl.decl_type) {
case AST_DECL_CONST:
obj = scan_const(ctx, &idecl->decl.constant);
diff --git a/tests/15-enums.ha b/tests/15-enums.ha
@@ -60,8 +60,22 @@ fn storage() void = {
};
fn reject() void = {
+ // enum type definition used outside type declaration
assert(rt::compile("export let a: enum { A, B } = 0;") != 0);
assert(rt::compile("export let a: int = 0: enum{A, B}: int;") != 0);
+
+ // enum circular dependencies
+ assert(rt::compile("type a = enum { A = B, B = A };") != 0);
+ assert(rt::compile("type a = enum { A = b::B },
+ b = enum { B = a::A };") != 0);
+ assert(rt::compile("
+ def a: int = e::VAL1;
+ type e = enum { VAL1 = a };
+ ") != 0);
+ assert(rt::compile("
+ def a: int = e::VAL1;
+ type e = enum { VAL1 = VAL2, VAL2 = a };
+ ") != 0);
};
type interdependent1 = enum {