commit 8fcadc2d6e54c377ca8e816c36b60ec5f3a64709
parent fcb4b5f352c01905cca5075de822e4f28a6b7e33
Author: Bor Grošelj Simić <bgs@turminal.net>
Date: Thu, 2 Jun 2022 00:33:45 +0200
complete enum types immediately
Enums never have any dependencies, so resolving them immediately upon
encounter is safe. This simplifies a bunch of things because there is no
need to handle the incomplete enum case everywhere.
Signed-off-by: Bor Grošelj Simić <bgs@turminal.net>
Diffstat:
4 files changed, 63 insertions(+), 67 deletions(-)
diff --git a/include/check.h b/include/check.h
@@ -105,14 +105,13 @@ struct unit {
enum idecl_type {
IDECL_DECL,
- IDECL_ENUM_TYPE,
IDECL_ENUM_FLD,
};
// Keeps track of enum specific context required for enum field resolution
struct incomplete_enum_field {
struct ast_enum_field *field;
- struct ast_type *type;
+ const struct type *type;
struct scope *enum_scope;
};
@@ -124,11 +123,7 @@ struct incomplete_declaration {
enum idecl_type type;
bool in_progress;
union {
- struct {
- struct ast_decl decl;
- struct scope *enum_values;
- struct identifiers *enum_aliases;
- };
+ struct ast_decl decl;
struct incomplete_enum_field *field;
};
};
diff --git a/include/type_store.h b/include/type_store.h
@@ -58,4 +58,7 @@ const struct type *type_store_tagged_to_union(
const struct type *type_store_lookup_tuple(struct type_store *store,
struct type_tuple *values, struct location loc);
+const struct type *type_store_lookup_enum(struct type_store *store,
+ const struct ast_type *atype, bool exported);
+
#endif
diff --git a/src/check.c b/src/check.c
@@ -3184,11 +3184,12 @@ check_type(struct context *ctx,
decl->ident = adecl->ident;
}
decl->type = DECL_TYPE;
- const struct type *type =
- type_store_lookup_atype(ctx->store, adecl->type);
if (adecl->type->storage == STORAGE_ENUM) {
- decl->_type = type;
+ decl->_type =
+ type_store_lookup_enum(ctx->store, adecl->type, exported);
} else {
+ const struct type *type =
+ type_store_lookup_atype(ctx->store, adecl->type);
struct type _alias = {
.storage = STORAGE_ALIAS,
.alias = {
@@ -3297,7 +3298,7 @@ incomplete_declaration_create(struct context *ctx, struct location loc,
static void
incomplete_enum_field_create(struct context *ctx, struct scope *imports,
- struct scope *enum_scope, struct ast_type *etype,
+ struct scope *enum_scope, const struct type *etype,
struct ast_enum_field *f)
{
// We have to process the last field first
@@ -3320,27 +3321,27 @@ incomplete_enum_field_create(struct context *ctx, struct scope *imports,
.name = strdup(f->name),
};
struct identifier name_ns = {
- .name = etype->alias.name,
- .ns = etype->alias.ns,
+ .name = etype->alias.name.name,
+ .ns = etype->alias.name.ns,
};
struct identifier name = {
.name = strdup(f->name),
.ns = &name_ns,
};
struct incomplete_declaration *fld =
- incomplete_declaration_create(ctx, etype->loc, enum_scope,
+ incomplete_declaration_create(ctx, f->loc, enum_scope,
&name, &localname);
fld->type = IDECL_ENUM_FLD;
fld->imports = imports;
fld->field = field;
struct identifier _ident = {0};
- mkident(ctx, &_ident, &etype->alias);
+ mkident(ctx, &_ident, &etype->alias.name);
struct identifier ident = {
.name = strdup(f->name),
.ns = &_ident,
};
- fld = incomplete_declaration_create(ctx, etype->loc, ctx->scope,
+ fld = incomplete_declaration_create(ctx, f->loc, ctx->scope,
&ident, &name);
fld->type = IDECL_ENUM_FLD,
fld->imports = imports,
@@ -3365,10 +3366,17 @@ incomplete_types_create(struct context *ctx, struct scope *imp, struct ast_decl
};
idecl->imports = imp;
if (t->type->storage == STORAGE_ENUM) {
- scope_push(&idecl->enum_values, SCOPE_ENUM);
- incomplete_enum_field_create(ctx, imp, idecl->enum_values,
- t->type, t->type->_enum.values);
- idecl->type = IDECL_ENUM_TYPE;
+ bool exported = idecl->decl.exported;
+ const struct type *type = type_store_lookup_enum(
+ ctx->store, t->type, exported);
+ if (type->storage == STORAGE_VOID) {
+ return; // error occured
+ }
+ scope_push((struct scope **)&type->_enum.values, SCOPE_ENUM);
+ incomplete_enum_field_create(ctx, imp,
+ type->_enum.values, type, t->type->_enum.values);
+ scope_insert(ctx->scope, O_TYPE, &with_ns,
+ &t->ident, type, NULL);
} else {
idecl->type = IDECL_DECL;
}
@@ -3490,8 +3498,7 @@ resolve_enum_field(struct context *ctx, const struct scope_object *obj)
assert(ctx->resolving_enum == NULL);
assert(idecl->type == IDECL_ENUM_FLD);
- const struct type *type =
- type_store_lookup_atype(ctx->store, idecl->field->type);
+ const struct type *type = idecl->field->type;
struct identifier nsident, nsname, localname = {
.name = idecl->obj.ident.name
@@ -3522,9 +3529,11 @@ resolve_enum_field(struct context *ctx, const struct scope_object *obj)
return obj;
}
+ idecl = (struct incomplete_declaration *)obj;
+ assert(idecl->type == IDECL_ENUM_FLD);
+
ctx->resolving_enum = idecl->field->enum_scope;
- struct expression *value =
- xcalloc(1, sizeof(struct expression));
+ struct expression *value = xcalloc(1, sizeof(struct expression));
value->result = type;
if (idecl->field->field->value) { // explicit value
struct expression *initializer =
@@ -3587,9 +3596,6 @@ resolve_enum_field(struct context *ctx, const struct scope_object *obj)
return scope_insert(idecl->field->enum_scope, O_CONST, &name, &localname, type, value);
}
-static const struct scope_object *
-resolve_enum_type(struct context *ctx, const struct scope_object *obj);
-
const struct scope_object *
resolve_enum_alias(struct context *ctx, const struct scope_object *obj)
{
@@ -3602,10 +3608,6 @@ resolve_enum_alias(struct context *ctx, const struct scope_object *obj)
switch (idecl->type) {
case IDECL_ENUM_FLD:
return NULL;
- case IDECL_ENUM_TYPE:
- // XXX: does this need to be wrapped?
- obj = resolve_enum_type(ctx, obj);
- return obj;
case IDECL_DECL:
if (idecl->decl.decl_type != AST_DECL_TYPE) {
return NULL;
@@ -3673,21 +3675,6 @@ resolve_enum_alias(struct context *ctx, const struct scope_object *obj)
return obj;
}
-static const struct scope_object *
-resolve_enum_type(struct context *ctx, const struct scope_object *obj)
-{
- struct incomplete_declaration *idecl = (struct incomplete_declaration*)obj;
- assert(idecl->type == IDECL_ENUM_TYPE);
- struct type *type = (struct type *)type_store_lookup_atype(ctx->store,
- idecl->decl.type.type);
- type->_enum.values = idecl->enum_values;
- type->_enum.aliases = idecl->enum_aliases;
- type->alias.exported = idecl->decl.exported;
- type_store_lookup_alias(ctx->store, type);
- return scope_insert(ctx->scope, O_TYPE,
- &idecl->obj.ident, &idecl->obj.name, type, NULL);
-}
-
const struct scope_object *
resolve_dimensions(struct context *ctx, const struct scope_object *obj)
{
@@ -3705,10 +3692,11 @@ resolve_dimensions(struct context *ctx, const struct scope_object *obj)
const struct scope_object *
resolve_type(struct context *ctx, const struct scope_object *obj)
{
- struct incomplete_declaration *idecl = (struct incomplete_declaration*)obj;
- if (idecl->type == IDECL_ENUM_TYPE) {
- return resolve_enum_type(ctx, obj);
+ if (obj->otype != O_SCAN) {
+ assert(obj->otype == O_TYPE);
+ return obj;
}
+ struct incomplete_declaration *idecl = (struct incomplete_declaration*)obj;
if (idecl->type != IDECL_DECL || idecl->decl.decl_type != AST_DECL_TYPE) {
struct location loc;
if (idecl->type == IDECL_ENUM_FLD) {
@@ -3825,8 +3813,6 @@ resolve_decl(struct context *ctx, const struct scope_object *obj)
switch (idecl->type) {
case IDECL_ENUM_FLD:
return resolve_enum_field(ctx, obj);
- case IDECL_ENUM_TYPE:
- return resolve_enum_type(ctx, obj);
case IDECL_DECL:
break;
}
@@ -4111,7 +4097,10 @@ check_internal(struct type_store *ts,
// Perform actual declaration resolution
ctx.resolving_enum = NULL;
for (const struct scope_object *obj = ctx.scope->objects;
- obj && obj->otype == O_SCAN; obj = obj->lnext) {
+ obj; obj = obj->lnext) {
+ if (obj->otype != O_SCAN) {
+ continue;
+ }
wrap_resolver(&ctx, obj, resolve_decl);
assert(ctx.resolving_enum == NULL);
}
diff --git a/src/type_store.c b/src/type_store.c
@@ -608,6 +608,7 @@ type_init_from_atype(struct type_store *store,
case STORAGE_FCONST:
case STORAGE_ICONST:
case STORAGE_RCONST:
+ case STORAGE_ENUM:
assert(0); // Invariant
case STORAGE_BOOL:
case STORAGE_CHAR:
@@ -704,21 +705,6 @@ type_init_from_atype(struct type_store *store,
type->size = memb.size * type->array.length;
}
break;
- case STORAGE_ENUM:
- mkident(store->check_context, &type->alias.ident, &atype->alias);
- identifier_dup(&type->alias.name, &atype->alias);
- type->alias.type =
- builtin_type_for_storage(atype->_enum.storage, false);
- if (!type_is_integer(type->alias.type)
- && type->alias.type->storage != STORAGE_RUNE) {
- error(store->check_context, atype->loc,
- "Enum storage must be an integer or rune");
- *type = builtin_type_void;
- return (struct dimensions){0};
- }
- type->size = type->alias.type->size;
- type->align = type->alias.type->size;
- break;
case STORAGE_FUNCTION:
type->size = SIZE_UNDEFINED;
type->align = ALIGN_UNDEFINED;
@@ -1066,6 +1052,29 @@ type_store_lookup_tuple(struct type_store *store, struct type_tuple *values,
return type_store_lookup_type(store, &type);
}
+const struct type *
+type_store_lookup_enum(struct type_store *store, const struct ast_type *atype,
+ bool exported)
+{
+ struct type type = {0};
+ type.storage = STORAGE_ENUM;
+ type.flags = atype->flags;
+ mkident(store->check_context, &type.alias.ident, &atype->alias);
+ identifier_dup(&type.alias.name, &atype->alias);
+ type.alias.exported = exported;
+ type.alias.type =
+ builtin_type_for_storage(atype->_enum.storage, false);
+ if (!type_is_integer(type.alias.type)
+ && type.alias.type->storage != STORAGE_RUNE) {
+ error(store->check_context, atype->loc,
+ "Enum storage must be an integer or rune");
+ return &builtin_type_void;
+ }
+ type.size = type.alias.type->size;
+ type.align = type.alias.type->size;
+ return type_store_lookup_type(store, &type);
+}
+
// Algorithm:
// - Deduplicate and collect nested unions
// - Merge *type with nullable *type