From 103edd636205921e1afadd91a284f3ead22afcce Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 5 Mar 2024 12:49:13 -0500 Subject: [PATCH] Fix cyclic structs/enums --- builtins/functions.c | 2 +- builtins/pointer.c | 2 +- builtins/pointer.h | 2 +- typecheck.c | 16 ++++++++++++---- types.h | 2 ++ 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/builtins/functions.c b/builtins/functions.c index c5514ff..8277fbc 100644 --- a/builtins/functions.c +++ b/builtins/functions.c @@ -112,7 +112,7 @@ public bool generic_equal(const void *x, const void *y, const TypeInfo *type) public CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type) { switch (type->tag) { - case PointerInfo: return Pointer__cord(obj, colorize, type); + case PointerInfo: return Pointer__as_text(obj, colorize, type); case FunctionInfo: return Func__as_text(obj, colorize, type); case ArrayInfo: return Array__as_text(obj, colorize, type); case TableInfo: return Table_as_text(obj, colorize, type); diff --git a/builtins/pointer.c b/builtins/pointer.c index bf844cb..54bab4b 100644 --- a/builtins/pointer.c +++ b/builtins/pointer.c @@ -18,7 +18,7 @@ typedef struct recursion_s { struct recursion_s *next; } recursion_t; -public CORD Pointer__cord(const void *x, bool colorize, const TypeInfo *type) { +public CORD Pointer__as_text(const void *x, bool colorize, const TypeInfo *type) { auto ptr_info = type->PointerInfo; if (!x) { CORD typename = generic_as_text(NULL, false, ptr_info.pointed); diff --git a/builtins/pointer.h b/builtins/pointer.h index c355472..32cf365 100644 --- a/builtins/pointer.h +++ b/builtins/pointer.h @@ -5,7 +5,7 @@ #include "types.h" -CORD Pointer__cord(const void *x, bool colorize, const TypeInfo *type); +CORD Pointer__as_text(const void *x, bool colorize, const TypeInfo *type); int32_t Pointer__compare(const void *x, const void *y, const TypeInfo *type); bool Pointer__equal(const void *x, const void *y, const TypeInfo *type); uint32_t Pointer__hash(const void *x, const TypeInfo *type); diff --git a/typecheck.c b/typecheck.c index eb51026..9859733 100644 --- a/typecheck.c +++ b/typecheck.c @@ -118,14 +118,18 @@ void bind_statement(env_t *env, ast_t *statement) env_t *ns_env = namespace_env(env, def->name); arg_t *fields = NULL; - type_t *type = Type(StructType, .name=def->name, .fields=fields); // placeholder + type_t *type = Type(StructType, .name=def->name, .fields=fields, .opaque=true); // placeholder + Table_str_set(env->types, def->name, type); for (arg_ast_t *field_ast = def->fields; field_ast; field_ast = field_ast->next) { type_t *field_t = parse_type_ast(env, field_ast->type); + if ((field_t->tag == StructType && Match(field_t, StructType)->opaque) + || (field_t->tag == EnumType && Match(field_t, EnumType)->opaque)) + code_err(field_ast->type, "This type is recursive and would create an infinitely sized struct. Try using a pointer."); fields = new(arg_t, .name=field_ast->name, .type=field_t, .default_val=field_ast->value, .next=fields); } REVERSE_LIST(fields); type->__data.StructType.fields = fields; // populate placeholder - Table_str_set(env->types, def->name, type); + type->__data.StructType.opaque = false; for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) { bind_statement(ns_env, stmt->ast); @@ -141,11 +145,15 @@ void bind_statement(env_t *env, ast_t *statement) env_t *ns_env = namespace_env(env, def->name); tag_t *tags = NULL; - type_t *type = Type(EnumType, .name=def->name, .tags=tags); // placeholder + type_t *type = Type(EnumType, .name=def->name, .tags=tags, .opaque=true); // placeholder + Table_str_set(env->types, def->name, type); for (tag_ast_t *tag_ast = def->tags; tag_ast; tag_ast = tag_ast->next) { arg_t *fields = NULL; for (arg_ast_t *field_ast = tag_ast->fields; field_ast; field_ast = field_ast->next) { type_t *field_t = parse_type_ast(env, field_ast->type); + if ((field_t->tag == StructType && Match(field_t, StructType)->opaque) + || (field_t->tag == EnumType && Match(field_t, EnumType)->opaque)) + code_err(field_ast->type, "This type is recursive and would create an infinitely sized struct. Try using a pointer."); fields = new(arg_t, .name=field_ast->name, .type=field_t, .default_val=field_ast->value, .next=fields); } REVERSE_LIST(fields); @@ -154,13 +162,13 @@ void bind_statement(env_t *env, ast_t *statement) } REVERSE_LIST(tags); type->__data.EnumType.tags = tags; + type->__data.EnumType.opaque = false; for (tag_t *tag = tags; tag; tag = tag->next) { type_t *constructor_t = Type(FunctionType, .args=Match(tag->type, StructType)->fields, .ret=type); set_binding(ns_env, tag->name, new(binding_t, .type=constructor_t, .code=CORD_all(def->name, "$tagged$", tag->name))); Table_str_set(env->types, heap_strf("%s$%s", def->name, tag->name), tag->type); } - Table_str_set(env->types, def->name, type); type_t *typeinfo_type = Type(TypeInfoType, .name=def->name, .type=type); Table_str_set(env->globals, def->name, new(binding_t, .type=typeinfo_type)); diff --git a/types.h b/types.h index 1a0e8ed..6226ab4 100644 --- a/types.h +++ b/types.h @@ -80,10 +80,12 @@ struct type_s { struct { const char *name; arg_t *fields; + bool opaque; } StructType; struct { const char *name; tag_t *tags; + bool opaque; } EnumType; struct { const char *name;