From 349d9ef3cf20478c7b085281ea02e1055912e515 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 28 May 2025 15:39:35 +0200 Subject: [PATCH] Allow recursive generic modules. --- releasenotes.md | 1 + src/compiler/sema_decls.c | 14 ++++++++------ src/compiler/sema_types.c | 4 +++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/releasenotes.md b/releasenotes.md index 08ae9861b..7b8af8c74 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -21,6 +21,7 @@ - Add `$$matrix_mul` and `$$matrix_transpose` builtins. - Add `d` as floating point suffix for `double` types. - Deprecate `f32`, `f64` and `f128` suffixes. +- Allow recursive generic modules. ### Fixes - Assert triggered when casting from `int[2]` to `uint[2]` #2115 diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index d504e318d..28e86c0ca 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -2374,6 +2374,14 @@ static inline bool unit_add_method(SemaContext *context, Type *parent_type, Decl other = sema_resolve_method(unit, parent, name, &ambiguous, &private); if (other) { + if (unit->module->generic_module && other->unit->module->generic_module == unit->module->generic_module) + { + const char *module_name = unit->module->generic_module->name->module; + RETURN_SEMA_ERROR(method, "The same method is generated by multiple instances of '%s': '%s%s' and '%s%s'. " + "You need to use `@if` to restrict it to one of them, or move it out of the generic module entirely.", + module_name, module_name, unit->module->generic_suffix, module_name, other->unit->module->generic_suffix); + } + SEMA_ERROR(method, "This %s is already defined for '%s'.", method_name_by_decl(method), parent_type->name); SEMA_NOTE(other, "The previous definition was here."); @@ -4890,12 +4898,6 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con ASSERT(alias); Module *module = alias->unit->module; - if (c->unit->module->generic_module == module) - { - sema_error_at(c, span, "This identifier is recursively using %s.", module->name->module); - return poisoned_decl; - } - unsigned parameter_count = vec_size(module->parameters); ASSERT(parameter_count > 0); if (parameter_count != vec_size(params)) diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index ed79af4ec..b9097c8e0 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -246,6 +246,7 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in case DECL_TYPEDEF: if (!sema_analyse_decl(context, decl)) return type_info_poison(type_info); type_info->type = decl->type; + assert (type_info->type->canonical->type_kind != TYPE_TYPEDEF); type_info->resolve_status = RESOLVE_DONE; return true; case DECL_POISONED: @@ -415,12 +416,13 @@ INLINE bool sema_resolve_generic_type(SemaContext *context, TypeInfo *type_info) Decl *type = sema_analyse_parameterized_identifier(context, inner->unresolved.path, inner->unresolved.name, inner->span, type_info->generic.params, &was_recursive); if (!decl_ok(type)) return false; + if (!sema_analyse_decl(context, type)) return false; type_info->type = type->type; if (!was_recursive) return true; if (!context->current_macro && (context->call_env.kind == CALL_ENV_FUNCTION || context->call_env.kind == CALL_ENV_FUNCTION_STATIC) && !context->call_env.current_function->func_decl.in_macro) { - RETURN_SEMA_ERROR(type_info, "Recursively generic type declarations are only allowed inside of macros. Use `def` to define an alias for the type instead."); + RETURN_SEMA_ERROR(type_info, "Recursively generic type declarations are only allowed inside of macros. Use `alias` to define an alias for the type instead."); } return true; }