Decoupled generics (#2695)

This commit is contained in:
Christoffer Lerno
2025-12-29 17:01:03 +01:00
committed by GitHub
parent bf1d401566
commit d96624c578
68 changed files with 1263 additions and 808 deletions

View File

@@ -46,7 +46,7 @@ static bool sema_analyse_variable_type(SemaContext *context, Type *type, SourceS
static inline bool sema_analyse_alias(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl, bool *erase_decl);
static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit);
static CompilationUnit *unit_copy_for_generic(Module *module, CompilationUnit *unit);
static inline bool sema_resolve_align_expr(SemaContext *context, Expr *expr, AlignSize *result)
{
@@ -71,8 +71,6 @@ static inline bool sema_resolve_align_expr(SemaContext *context, Expr *expr, Ali
*result = (AlignSize)align;
return true;
}
static Module *module_instantiate_generic(SemaContext *context, Module *module, Path *path, Expr **params, SourceSpan from_span);
static inline bool sema_analyse_enum_param(SemaContext *context, Decl *param);
static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_raw_enum(SemaContext *context, Decl *decl, bool *erase_decl);
@@ -192,7 +190,7 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent
if (decl->resolve_status == RESOLVE_RUNNING) RETURN_SEMA_ERROR(decl, "Circular dependency resolving member.");
// Mark the unit, it should not have been assigned at this point.
ASSERT_SPAN(decl, !decl->unit || decl->unit->module->is_generic || decl->unit == parent->unit);
ASSERT_SPAN(decl, !decl->unit || decl->is_templated || decl->unit == parent->unit);
decl->unit = parent->unit;
// Pick the domain for attribute analysis.
@@ -2613,7 +2611,6 @@ NONE:
*/
static inline bool type_add_method(SemaContext *context, Type *parent_type, Decl *method)
{
CompilationUnit *unit = context->unit;
ASSERT(parent_type->canonical == parent_type);
const char *name = method->name;
@@ -2634,18 +2631,12 @@ static inline bool type_add_method(SemaContext *context, Type *parent_type, Decl
if (!decl_ok(other)) return false;
if (other)
{
if (unit->module->generic_module && other->unit->module->generic_module == unit->module->generic_module && other->unit->module != unit->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);
}
// We might sometimes end up adding the same method twice.
if (other == method) return false;
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.");
return false;
return decl_poison(method);
}
DEBUG_LOG("Method-like '%s.%s' analysed.", parent->name, method->name);
@@ -3104,6 +3095,7 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
[ATTRIBUTE_EXTERN] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES,
[ATTRIBUTE_FINALIZER] = ATTR_FUNC,
[ATTRIBUTE_FORMAT] = ATTR_FUNC | ATTR_MACRO | ATTR_FNTYPE,
[ATTRIBUTE_GENERIC] = ATTR_FUNC | ATTR_MACRO | ATTR_GLOBAL | ATTR_CONST | ATTR_UNION | ATTR_STRUCT | ATTR_INTERFACE | ATTR_ALIAS,
[ATTRIBUTE_IF] = (AttributeDomain)~(ATTR_CALL | ATTR_PARAM),
[ATTRIBUTE_INIT] = ATTR_FUNC,
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
@@ -3298,9 +3290,9 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
case ATTRIBUTE_WASM:
if (args > 2) RETURN_SEMA_ERROR(attr->exprs[2], "Too many arguments to '@wasm', expected 0, 1 or 2 arguments");
decl->is_export = true;
if (context->unit->module->is_generic)
if (decl->is_templated)
{
RETURN_SEMA_ERROR(attr, "'@wasm' is not allowed in generic modules.");
RETURN_SEMA_ERROR(attr, "'@wasm' is not allowed on generic declarations.");
}
if (args == 0) return true;
if (decl->has_extname)
@@ -3332,9 +3324,9 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
decl->has_extname = true;
return true;
case ATTRIBUTE_EXPORT:
if (context->unit->module->is_generic)
if (decl->is_templated)
{
RETURN_SEMA_ERROR(attr, "'@export' is not allowed in generic modules.");
RETURN_SEMA_ERROR(attr, "'@export' is not allowed on generic declarations.");
}
if (expr)
{
@@ -3358,6 +3350,8 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
case ATTRIBUTE_NOALIAS:
decl->var.no_alias = true;
return true;
case ATTRIBUTE_GENERIC:
UNREACHABLE;
case ATTRIBUTE_IF:
if (!expr) RETURN_SEMA_ERROR(attr, "'@if' requires a boolean argument.");
if (!sema_analyse_expr_rvalue(context, expr)) return false;
@@ -3446,9 +3440,9 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
case ATTRIBUTE_SECTION:
case ATTRIBUTE_CNAME:
case ATTRIBUTE_EXTERN:
if (context->unit->module->is_generic)
if (decl->is_templated)
{
RETURN_SEMA_ERROR(attr, "'%s' attributes are not allowed in generic modules.", attr->name);
RETURN_SEMA_ERROR(attr, "'%s' attributes are not allowed for generic declarations.", attr->name);
}
if (!expr)
{
@@ -4928,15 +4922,15 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local, bool *c
if (is_static) context->call_env.kind = CALL_ENV_FUNCTION_STATIC;
decl->in_init = true;
Module *generic = type_find_generic(decl->type);
Decl *generic = declptrzero(type_find_generic(decl->type));
if (generic)
{
Module *temp = context->generic.infer;
context->generic.infer = generic;
Decl *temp = context->generic_infer;
context->generic_infer = generic;
generic = temp;
}
success = sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false, true, check_defined);
context->generic.infer = generic;
context->generic_infer = generic;
if (!success && check_defined) return false;
decl->in_init = false;
context->call_env.kind = env_kind;
@@ -4991,83 +4985,6 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local, bool *c
return success;
}
static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit)
{
CompilationUnit *copy = unit_create(unit->file);
copy->imports = copy_decl_list_single(unit->imports);
copy->module_aliases = copy_decl_list_single(unit->module_aliases);
copy->public_imports = NULL;
if (unit->public_imports)
{
FOREACH(Decl *, import, copy->imports)
{
if (import->import.import_private_as_public) vec_add(copy->public_imports, import);
}
}
copy->global_decls = copy_decl_list_single_for_unit(unit->global_decls);
copy->global_cond_decls = copy_decl_list_single_for_unit(unit->global_cond_decls);
copy->module = module;
ASSERT(!unit->functions && !unit->macro_methods && !unit->methods && !unit->enums && !unit->ct_includes && !unit->types);
return copy;
}
static Module *module_instantiate_generic(SemaContext *context, Module *module, Path *path, Expr **params, SourceSpan from_span)
{
unsigned decls = 0;
Decl* params_decls[MAX_PARAMS];
unsigned count = vec_size(module->parameters);
for (unsigned i = 0; i < count; i++)
{
const char *param_name = module->parameters[i];
bool is_value = str_is_valid_constant(param_name);
Expr *param = params[i];
if (param->expr_kind != EXPR_TYPEINFO)
{
if (!is_value) RETURN_NULL_SEMA_ERROR(param, "Expected a type, not a value.");
Decl *decl = decl_new_var(param_name, param->span, NULL, VARDECL_CONST);
decl->var.init_expr = param;
decl->type = param->type;
decl->resolve_status = RESOLVE_NOT_DONE;
params_decls[decls++] = decl;
continue;
}
if (is_value) RETURN_NULL_SEMA_ERROR(param, "Expected a value, not a type.");
TypeInfo *type_info = param->type_expr;
if (!sema_resolve_type_info(context, type_info, RESOLVE_TYPE_DEFAULT)) return NULL;
Decl *decl = decl_new_with_type(param_name, params[i]->span, DECL_TYPE_ALIAS);
decl->resolve_status = RESOLVE_DONE;
ASSERT(type_info->resolve_status == RESOLVE_DONE);
decl->type_alias_decl.type_info = type_info;
decl->type->name = decl->name;
decl->type->canonical = type_info->type->canonical;
params_decls[decls++] = decl;
}
Module *new_module = compiler_find_or_create_module(path, NULL);
new_module->is_generic = false;
new_module->generic_module = module;
FOREACH(CompilationUnit *, unit, module->units)
{
vec_add(new_module->units, unit_copy(new_module, unit));
}
CompilationUnit *first_context = new_module->units[0];
for (unsigned i = 0; i < decls; i++)
{
vec_add(first_context->global_decls, params_decls[i]);
}
if (module->contracts)
{
copy_begin();
new_module->contracts = astid(copy_ast_macro(astptr(module->contracts)));
copy_end();
}
new_module->inlined_at = (InliningSpan) { .span = from_span, .prev = copy_inlining_span(context->inlined_at) };
return new_module;
}
static inline void mangle_type_param(Type *type, bool mangled)
{
type = type->canonical;
@@ -5078,81 +4995,23 @@ static inline void mangle_type_param(Type *type, bool mangled)
else
{
scratch_buffer_append(type->name);
if (type_is_user_defined(type) && type->decl->unit->module->generic_suffix)
{
scratch_buffer_append(type->decl->unit->module->generic_suffix);
}
}
}
static bool sema_generate_parameterized_name_to_scratch(SemaContext *context, Module *module, Expr **params,
bool mangled, bool *was_recursive_ref)
static bool sema_generate_parameter_suffix_to_scratch(SemaContext *context, Expr **params, bool mangled, bool *was_recursive_ref)
{
// First resolve
FOREACH_IDX(i, Expr *, param, params)
{
if (param->expr_kind == EXPR_TYPEINFO)
{
TypeInfo *type_info = param->type_expr;
if (was_recursive_ref && type_info->kind == TYPE_INFO_GENERIC) *was_recursive_ref = true;
if (!sema_resolve_type_info(context, 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.");
switch (sema_resolve_storage_type(context, type))
{
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
case STORAGE_VOID:
break;
case STORAGE_WILDCARD:
RETURN_SEMA_ERROR(type_info, "The type is undefined and cannot be used as a parameter type.");
case STORAGE_COMPILE_TIME:
RETURN_SEMA_ERROR(type_info, "Expected a runtime type but it was %s.", type_invalid_storage_type_name(type));
case STORAGE_UNKNOWN:
RETURN_SEMA_ERROR(type_info,
"%s doesn't have a well defined size and cannot be used as a parameter type.",
type_quoted_error_string(type));
}
if (type_is_func_ptr(type))
{
if (!sema_resolve_type_decl(context, type->pointer)) return false;
}
}
else
{
if (!sema_analyse_ct_expr(context, param)) return false;
Type *type = param->type->canonical;
if (type->type_kind == TYPE_TYPEDEF) type = type_flatten(type);
bool is_enum_or_fault = type_kind_is_enum_or_fault(type->type_kind);
if (!type_is_integer_or_bool_kind(type) && !is_enum_or_fault)
{
RETURN_SEMA_ERROR(param, "Only integer, bool, fault and enum values may be generic arguments.");
}
ASSERT(expr_is_const(param));
}
}
scratch_buffer_clear();
if (mangled)
{
scratch_buffer_append_module(module, true);
scratch_buffer_append("$");
}
else
{
scratch_buffer_append("{");
}
scratch_buffer_append(mangled ? "$" : "{");
FOREACH_IDX(j, Expr *, param, params)
{
if (j != 0)
{
scratch_buffer_append(mangled ? "$" : ", ");
}
if (param->expr_kind == EXPR_TYPEINFO)
if (expr_is_const_typeid(param))
{
mangle_type_param(param->type_expr->type, mangled);
mangle_type_param(param->const_expr.typeid, mangled);
}
else
{
@@ -5226,14 +5085,13 @@ static bool sema_generate_parameterized_name_to_scratch(SemaContext *context, Mo
return true;
}
static bool sema_analyse_generic_module_contracts(SemaContext *c, Module *module, SourceSpan param_span, SourceSpan invocation_span)
static bool sema_analyse_generic_module_contracts(SemaContext *c, Module *module, Decl *instance, AstId contracts, SourceSpan param_span, SourceSpan invocation_span)
{
ASSERT(module->contracts);
AstId contract = module->contracts;
while (contract)
ASSERT(contracts);
while (contracts)
{
Ast *ast = astptr(contract);
contract = ast->next;
Ast *ast = astptr(contracts);
contracts = ast->next;
ASSERT_SPAN(ast, ast->ast_kind == AST_CONTRACT);
SemaContext temp_context;
if (ast->contract_stmt.kind == CONTRACT_COMMENT) continue;
@@ -5241,7 +5099,9 @@ static bool sema_analyse_generic_module_contracts(SemaContext *c, Module *module
InliningSpan *old_span = c->inlined_at;
InliningSpan new_span = { .prev = old_span, .span = invocation_span };
SemaContext *new_context = context_transform_for_eval(c, &temp_context, module->units[0]);
Decl *old_generic_instance = new_context->generic_instance;
InliningSpan *old_inlined_at = new_context->inlined_at;
new_context->generic_instance = instance;
new_context->inlined_at = &new_span;
FOREACH(Expr *, expr, ast->contract_stmt.contract.decl_exprs->expression_list)
@@ -5266,83 +5126,239 @@ static bool sema_analyse_generic_module_contracts(SemaContext *c, Module *module
return false;
}
new_context->inlined_at = old_inlined_at;
new_context->generic_instance = old_generic_instance;
sema_context_destroy(&temp_context);
}
return true;
}
Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, const char *name, SourceSpan span,
Decl *sema_analyse_parameterized_identifier(SemaContext *context, Path *decl_path, const char *name, SourceSpan span,
Expr **params, bool *was_recursive_ref, SourceSpan invocation_span)
{
Decl *alias = sema_resolve_parameterized_symbol(c, name, decl_path, span);
Decl *alias = sema_resolve_parameterized_symbol(context, name, decl_path, span);
if (!alias) return poisoned_decl;
Module *module = alias->unit->module;
unsigned parameter_count = vec_size(module->parameters);
ASSERT_AT(invocation_span, alias->is_template && alias->generic_id);
Decl *generic = declptr(alias->generic_id);
unsigned parameter_count = vec_size(generic->generic_decl.parameters);
ASSERT(parameter_count > 0);
unsigned count = vec_size(params);
if (parameter_count != count)
{
if (!count)
{
sema_error_at(c, invocation_span,
"'%s' must be instantiatied with generic module arguments inside the '{}', did you forget them?", name, (int)parameter_count);
sema_error_at(context, invocation_span,
"'%s' requires generic arguments inside the '{}', did you forget them?", name, (int)parameter_count);
}
else
{
sema_error_at(c, extend_span_with_token(params[0]->span, vectail(params)->span),
"The generic module expected %d argument(s), but you supplied %d, did you make a mistake?",
// 'Foo' expects 2 generic arguments, but you supplied 1, did you make a mistake?
sema_error_at(context, extend_span_with_token(params[0]->span, vectail(params)->span),
"'%s' expects %d %s, but you supplied %d, did you make a mistake?",
name,
parameter_count,
parameter_count == 1 ? "argument" : "arguments",
vec_size(params));
}
return poisoned_decl;
}
if (!sema_generate_parameterized_name_to_scratch(c, module, params, true, was_recursive_ref)) return poisoned_decl;
const char *path_string = scratch_buffer_interned();
Module *instantiated_module = global_context_find_module(path_string);
AnalysisStage stage = c->unit->module->generic_module
? c->unit->module->stage
: c->unit->module->stage - 1;
bool instantiation = false;
if (!instantiated_module)
// First resolve
FOREACH_IDX(i, Expr *, param, params)
{
instantiation = true;
Path *path = CALLOCS(Path);
path->module = path_string;
path->span = module->name->span;
path->len = scratch_buffer.len;
instantiated_module = module_instantiate_generic(c, module, path, params, invocation_span);
if (!instantiated_module) return poisoned_decl;
if (!sema_generate_parameterized_name_to_scratch(c, module, params, false, NULL)) return poisoned_decl;
instantiated_module->generic_suffix = scratch_buffer_copy();
sema_analyze_stage(instantiated_module, stage > ANALYSIS_POST_REGISTER ? ANALYSIS_POST_REGISTER : stage);
}
if (compiler.context.errors_found) return poisoned_decl;
Decl *symbol = module_find_symbol(instantiated_module, name);
if (!symbol)
{
sema_error_at(c, span, "The generic module '%s' does not have '%s' for this parameterization.", module->name->module, name);
return poisoned_decl;
}
if (instantiation)
{
if (instantiated_module->contracts)
if (!sema_analyse_expr_rvalue(context, param)) return poisoned_decl;
const char *param_name = generic->generic_decl.parameters[i];
bool is_type = str_is_type(param_name);
if (expr_is_const_typeid(param))
{
SourceSpan param_span = extend_span_with_token(params[0]->span, params[parameter_count - 1]->span);
if (!sema_analyse_generic_module_contracts(c, instantiated_module, param_span, invocation_span))
if (!is_type)
{
SEMA_ERROR(param, "Expected a value, not a type, for parameter '%s'.", param_name);
return poisoned_decl;
}
Type *type = param->const_expr.typeid;
if (type_is_func_ptr(type))
{
if (!sema_resolve_type_decl(context, type->pointer)) return poisoned_decl;
}
}
if (stage > ANALYSIS_POST_REGISTER)
else
{
sema_analyze_stage(instantiated_module, stage);
if (compiler.context.errors_found) return poisoned_decl;
if (is_type)
{
SEMA_ERROR(param, "Expected a type, not a value, for parameter '%s'.", param_name);
return poisoned_decl;
}
if (!sema_analyse_ct_expr(context, param)) return poisoned_decl;
Type *type = param->type->canonical;
if (type->type_kind == TYPE_TYPEDEF) type = type_flatten(type);
bool is_enum_or_fault = type_kind_is_enum_or_fault(type->type_kind);
if (!type_is_integer_or_bool_kind(type) && !is_enum_or_fault)
{
SEMA_ERROR(param, "Only integer, bool, fault and enum values may be generic arguments.");
return poisoned_decl;
}
ASSERT(expr_is_const(param));
}
}
Module *module = alias->unit->module;
if (!sema_generate_parameter_suffix_to_scratch(context, params, true, was_recursive_ref)) return poisoned_decl;
const char *suffix = scratch_buffer_interned();
Decl *instance = NULL;
unsigned id = generic->generic_decl.id;
FOREACH(Decl *, g, alias->unit->module->generic_sections)
{
FOREACH (Decl *, candidate, g->generic_decl.instances)
{
if (candidate->name == suffix)
{
instance = candidate;
goto FOUND;
}
}
}
FOUND:;
bool instantiation = instance == NULL;
if (!instance)
{
DEBUG_LOG("Generate generic instance %s", suffix);
if (compiler.context.errors_found) return poisoned_decl;
instance = decl_new(DECL_GENERIC_INSTANCE, suffix, generic->span);
FOREACH_IDX(i, const char *, param_name, generic->generic_decl.parameters)
{
Decl *decl;
Expr *param = params[i];
ASSERT_SPAN(param, param->expr_kind == EXPR_CONST);
if (expr_is_const_typeid(param))
{
decl = decl_new_var(param_name, param->span, NULL, VARDECL_PARAM_CT_TYPE);
}
else
{
ASSERT(param->expr_kind == EXPR_CONST);
decl = decl_new_var(param_name, param->span, NULL, VARDECL_CONST);
}
decl->var.init_expr = param;
decl->unit = alias->unit;
decl->resolve_status = RESOLVE_DONE;
decl->type = param->type;
vec_add(instance->instance_decl.params, decl);
}
instance->unit = alias->unit;
Decl **copied = NULL;
Decl **copied_cond = NULL;
if (!sema_generate_parameter_suffix_to_scratch(context, params, false, was_recursive_ref)) return poisoned_decl;
instance->instance_decl.name_suffix = scratch_buffer_copy();
if (!sema_generate_parameter_suffix_to_scratch(context, params, true, was_recursive_ref)) return poisoned_decl;
instance->instance_decl.cname_suffix = scratch_buffer_copy();
instance->instance_decl.id = id;
FOREACH(Decl *, g, module->generic_sections)
{
if (g->generic_decl.id == generic->generic_decl.id)
{
vec_add(instance->instance_decl.templates, g);
Decl **decls = g->generic_decl.decls;
Decl **cond_decls = g->generic_decl.conditional_decls;
decls = decls ? copy_decl_list_single_for_generic(decls, instance) : NULL;
cond_decls = cond_decls ? copy_decl_list_single_for_generic(cond_decls, instance) : NULL;
FOREACH(Decl *, d, decls) vec_add(copied, d);
FOREACH(Decl *, d, cond_decls) vec_add(copied_cond, d);
}
}
vec_add(generic->generic_decl.instances, instance);
AnalysisStage stage = module->stage;
ASSERT(stage > ANALYSIS_IMPORTS);
// Add all the normal top level declarations
FOREACH(Decl *, decl, copied) unit_register_global_decl(decl->unit, decl);
// Add all the conditional declarations
FOREACH(Decl *, decl, copied_cond)
{
unit_register_optional_global_decl(decl->unit, decl);
if (decl->decl_kind != DECL_ERASED) vec_add(copied, decl);
}
if (compiler.context.errors_found) return poisoned_decl;
// Check contracts
FOREACH(Decl *, decl, module->generic_sections)
{
if (decl->generic_decl.id == generic->generic_decl.id)
{
AstId contracts = decl->generic_decl.contracts;
if (!contracts) continue;
copy_begin();
contracts = astid(copy_ast_macro(astptr(contracts)));
copy_end();
SourceSpan param_span = extend_span_with_token(params[0]->span, params[parameter_count - 1]->span);
if (!sema_analyse_generic_module_contracts(context, module, instance, contracts, param_span, invocation_span))
{
return poisoned_decl;
}
}
}
if (stage < ANALYSIS_METHODS_REGISTER) goto EXIT;
FOREACH(Decl *, decl, copied)
{
if (decl->decl_kind != DECL_FUNC && decl->decl_kind != DECL_MACRO) continue;
if (!decl->func_decl.type_parent) continue;
SemaContext gen_context;
sema_context_init(&gen_context, decl->unit);
gen_context.generic_instance = instance;
if (sema_analyse_method_register(&gen_context, decl))
{
if (decl->decl_kind == DECL_MACRO)
{
vec_add(decl->unit->macro_methods, decl);
}
else
{
vec_add(decl->unit->methods, decl);
}
}
}
if (stage < ANALYSIS_DECLS) goto EXIT;
FOREACH(Decl *, decl, copied)
{
SemaContext context_gen;
sema_context_init(&context_gen, decl->unit);
context_gen.active_scope = (DynamicScope) { .depth = 0 };
sema_analyse_decl(&context_gen, decl);
context_gen.generic_instance = instance;
sema_analyse_inner_func_ptr(&context_gen, decl);
FOREACH(TypeInfo *, info, decl->unit->check_type_variable_array)
{
sema_check_type_variable_array(&context_gen, info);
}
sema_context_destroy(&context_gen);
}
if (stage < ANALYSIS_FUNCTIONS) goto EXIT;
if (compiler.context.errors_found) return poisoned_decl;
FOREACH(Decl *, decl, copied)
{
SemaContext context_gen;
switch (decl->decl_kind)
{
case DECL_FUNC:
sema_context_init(&context_gen, decl->unit);
analyse_func_body(&context_gen, decl);
sema_context_destroy(&context_gen);
break;
default:
break;
}
}
ASSERT(stage < ANALYSIS_INTERFACE);
EXIT:;
if (compiler.context.errors_found) return poisoned_decl;
}
Decl *symbol = sema_find_generic_instance(context, module, generic, instance, name);
if (!symbol)
{
sema_error_at(context, span, "The generic '%s' does not exist for this parameterization.", name);
return poisoned_decl;
}
CompilationUnit *unit = symbol->unit;
if (unit->module->stage < ANALYSIS_POST_REGISTER)
{
@@ -5350,9 +5366,9 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con
}
else
{
if (!sema_analyse_decl(c, symbol)) return poisoned_decl;
if (!sema_analyse_decl(context, symbol)) return poisoned_decl;
}
unit_register_external_symbol(c, symbol);
unit_register_external_symbol(context, symbol);
return symbol;
}
@@ -5514,6 +5530,7 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl)
SemaContext temp_context;
context = context_transform_for_eval(context, &temp_context, decl->unit);
context->generic_instance = decl->is_templated ? declptr(decl->instance_id) : NULL;
if (decl->resolve_status == RESOLVE_RUNNING)
{
SEMA_ERROR(decl, decl->name
@@ -5522,7 +5539,7 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl)
goto FAILED;
}
decl->resolve_status = RESOLVE_RUNNING;
ASSERT(decl->unit);
ASSERT_SPAN(decl, decl->unit);
bool erase_decl = false;
switch (decl->decl_kind)
{
@@ -5583,6 +5600,8 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl)
case DECL_IMPORT:
case DECL_LABEL:
case DECL_POISONED:
case DECL_GENERIC:
case DECL_GENERIC_INSTANCE:
UNREACHABLE
}
if (erase_decl)