mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
Decoupled generics (#2695)
This commit is contained in:
committed by
GitHub
parent
bf1d401566
commit
d96624c578
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user