Generic modules parameterized with constants would sometimes get the wrong parameterized module name causing conversion errors #1192.

This commit is contained in:
Christoffer Lerno
2024-05-04 23:34:37 +02:00
parent 60805fd11d
commit b09aa74f2f
4 changed files with 43 additions and 24 deletions

View File

@@ -12,6 +12,7 @@
### Fixes
- Incorrect length passed to scratch buffer printf.
- Casting to a bitstruct would be allowed even if the type was the wrong size.
- Generic modules parameterized with constants would sometimes get the wrong parameterized module name causing conversion errors #1192.
### Stdlib changes
- Add 'zstr' variants for `string::new_format` / `string::tformat`.

View File

@@ -366,6 +366,7 @@ typedef enum
SCOPE_ENSURE_MACRO = 1 << 2,
SCOPE_EXPR_BLOCK = 1 << 3,
SCOPE_MACRO = 1 << 4,
SCOPE_COND = 1 << 5,
} ScopeFlags;
typedef enum

View File

@@ -3471,8 +3471,38 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module,
return new_module;
}
static bool sema_append_generate_parameterized_name(SemaContext *c, Module *module, Expr **params, bool mangled)
static bool sema_generate_parameterized_name_to_scratch(SemaContext *c, Module *module, Expr **params, bool mangled)
{
// First resolve
FOREACH_BEGIN_IDX(i, Expr *param, params)
if (param->expr_kind == EXPR_TYPEINFO)
{
TypeInfo *type_info = param->type_expr;
if (!sema_resolve_type_info(c, type_info, RESOLVE_TYPE_DEFAULT)) return false;
Type *type = type_info->type->canonical;
if (type->type_kind == TYPE_OPTIONAL) RETURN_SEMA_ERROR(type_info, "Expected a non-optional type.");
if (type_is_void(type)) RETURN_SEMA_ERROR(type_info, "A 'void' type cannot be used as a parameter type.");
if (type_is_invalid_storage_type(type)) RETURN_SEMA_ERROR(type_info, "Expected a runtime type.");
if (type_is_func_ptr(type))
{
if (!sema_resolve_type_decl(c, type->pointer)) return false;
}
}
else
{
if (!sema_analyse_ct_expr(c, param)) return false;
Type *type = param->type->canonical;
bool is_enum_like = type_kind_is_enumlike(type->type_kind);
if (!type_is_integer_or_bool_kind(type) && !is_enum_like)
{
SEMA_ERROR(param, "Only integer, bool, fault and enum values may be generic arguments.");
return poisoned_decl;
}
assert(expr_is_const(param));
}
FOREACH_END();
scratch_buffer_clear();
if (mangled)
{
scratch_buffer_append_len(module->name->module, module->name->len);
@@ -3489,36 +3519,20 @@ static bool sema_append_generate_parameterized_name(SemaContext *c, Module *modu
}
if (param->expr_kind == EXPR_TYPEINFO)
{
TypeInfo *type_info = param->type_expr;
if (!sema_resolve_type_info(c, type_info, RESOLVE_TYPE_DEFAULT)) return false;
Type *type = type_info->type->canonical;
if (type->type_kind == TYPE_OPTIONAL) RETURN_SEMA_ERROR(type_info, "Expected a non-optional type.");
if (type_is_void(type)) RETURN_SEMA_ERROR(type_info, "A 'void' type cannot be used as a parameter type.");
if (type_is_invalid_storage_type(type)) RETURN_SEMA_ERROR(type_info, "Expected a runtime type.");
if (type_is_func_ptr(type))
{
if (!sema_resolve_type_decl(c, type->pointer)) return false;
}
Type *type = param->type_expr->type->canonical;
if (mangled)
{
type_mangle_introspect_name_to_buffer(type);
}
else
{
scratch_buffer_append(type_info->type->name);
scratch_buffer_append(type->name);
}
}
else
{
if (!sema_analyse_ct_expr(c, param)) return false;
Type *type = param->type->canonical;
bool is_enum_like = type_kind_is_enumlike(type->type_kind);
if (!type_is_integer_or_bool_kind(type) && !is_enum_like)
{
SEMA_ERROR(param, "Only integer, bool, fault and enum values may be generic arguments.");
return poisoned_decl;
}
assert(expr_is_const(param));
if (type == type_bool)
{
if (mangled)
@@ -3656,8 +3670,7 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con
vec_size(params));
return poisoned_decl;
}
scratch_buffer_clear();
if (!sema_append_generate_parameterized_name(c, module, params, true)) return poisoned_decl;
if (!sema_generate_parameterized_name_to_scratch(c, module, params, true)) return poisoned_decl;
TokenType ident_type = TOKEN_IDENT;
const char *path_string = scratch_buffer_interned();
Module *instantiated_module = global_context_find_module(path_string);
@@ -3671,8 +3684,7 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con
path->span = module->name->span;
path->len = scratch_buffer.len;
instantiated_module = module_instantiate_generic(c, module, path, params, span);
scratch_buffer_clear();
if (!sema_append_generate_parameterized_name(c, module, params, false)) return poisoned_decl;
if (!sema_generate_parameterized_name_to_scratch(c, module, params, false)) return poisoned_decl;
if (!instantiated_module) return poisoned_decl;
instantiated_module->generic_suffix = scratch_buffer_copy();
if (c->unit->module->generic_module)

View File

@@ -1025,7 +1025,12 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType
assert(expr->expr_kind == EXPR_COND && "Conditional expressions should always be of type EXPR_DECL_LIST");
// 1. Analyse the declaration list.
if (!sema_analyse_cond_list(context, expr, cond_type)) return false;
ScopeFlags current_flags = context->active_scope.flags;
context->active_scope.flags |= SCOPE_COND;
bool success = sema_analyse_cond_list(context, expr, cond_type);
context->active_scope.flags = current_flags;
if (!success) return false;
// 2. If we get "void", either through a void call or an empty list,
// signal that.