mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Improve ordering of method registration to support adding methods to generic modules with method constraints #1746
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
- Add `"name"` project property to override the name of the resulting binary. #1719
|
||||
- Improved `add-project` to take arguments.
|
||||
- Improve error reporting when using type names as the function argument #1750.
|
||||
- Improve ordering of method registration to support adding methods to generic modules with method constraints #1746
|
||||
|
||||
### Fixes
|
||||
- Fix case trying to initialize a `char[*]*` from a String.
|
||||
|
||||
@@ -1636,6 +1636,7 @@ struct CompilationUnit_
|
||||
Decl **vars;
|
||||
Decl **macros;
|
||||
Decl **methods_to_register;
|
||||
Decl **generic_methods_to_register;
|
||||
Decl **methods;
|
||||
Decl **macro_methods;
|
||||
Decl **global_decls;
|
||||
@@ -2312,6 +2313,7 @@ bool sema_cast_const(Expr *expr);
|
||||
bool sema_expr_check_discard(SemaContext *context, Expr *expr);
|
||||
bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr);
|
||||
bool sema_analyse_decl(SemaContext *context, Decl *decl);
|
||||
|
||||
bool sema_analyse_method_register(SemaContext *context, Decl *method);
|
||||
bool sema_resolve_type_structure(SemaContext *context, Type *type, SourceSpan span);
|
||||
bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl);
|
||||
@@ -2347,6 +2349,7 @@ BoolErr sema_symbol_is_defined_in_scope(SemaContext *c, const char *symbol);
|
||||
bool sema_resolve_array_like_len(SemaContext *context, TypeInfo *type_info, ArraySize *len_ref);
|
||||
|
||||
bool sema_resolve_type_info(SemaContext *context, TypeInfo *type_info, ResolveTypeKind kind);
|
||||
bool sema_unresolved_type_is_generic(SemaContext *context, TypeInfo *type_info);
|
||||
|
||||
void print_error_at(SourceSpan loc, const char *message, ...);
|
||||
void print_error_after(SourceSpan loc, const char *message, ...);
|
||||
|
||||
@@ -187,6 +187,11 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
|
||||
ASSERT0(decl->name);
|
||||
if (decl->func_decl.type_parent)
|
||||
{
|
||||
if (type_infoptr(decl->func_decl.type_parent)->kind == TYPE_INFO_GENERIC)
|
||||
{
|
||||
vec_add(unit->generic_methods_to_register, decl);
|
||||
return;
|
||||
}
|
||||
vec_add(unit->methods_to_register, decl);
|
||||
return;
|
||||
}
|
||||
@@ -200,6 +205,11 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
|
||||
ASSERT0(decl->name);
|
||||
if (decl->func_decl.type_parent)
|
||||
{
|
||||
if (type_infoptr(decl->func_decl.type_parent)->kind == TYPE_INFO_GENERIC)
|
||||
{
|
||||
vec_add(unit->generic_methods_to_register, decl);
|
||||
return;
|
||||
}
|
||||
vec_add(unit->methods_to_register, decl);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -47,11 +47,14 @@ typedef enum
|
||||
ANALYSIS_IMPORTS,
|
||||
ANALYSIS_REGISTER_GLOBAL_DECLARATIONS,
|
||||
ANALYSIS_METHODS_REGISTER,
|
||||
ANALYSIS_METHODS_REGISTER_GENERIC,
|
||||
ANALYSIS_INCLUDES,
|
||||
ANALYSIS_METHODS_INCLUDES,
|
||||
ANALYSIS_METHODS_INCLUDES_GENERIC,
|
||||
ANALYSIS_REGISTER_CONDITIONAL_UNITS,
|
||||
ANALYSIS_REGISTER_CONDITIONAL_DECLARATIONS,
|
||||
ANALYSIS_METHODS_CONDITIONAL,
|
||||
ANALYSIS_METHODS_CONDITIONAL_GENERIC,
|
||||
ANALYSIS_POST_REGISTER,
|
||||
ANALYSIS_DECLS,
|
||||
ANALYSIS_CT_ECHO,
|
||||
|
||||
@@ -77,7 +77,7 @@ void sema_analysis_pass_register_global_declarations(Module *module);
|
||||
void sema_analysis_pass_process_includes(Module *module);
|
||||
void sema_analysis_pass_register_conditional_units(Module *module);
|
||||
void sema_analysis_pass_register_conditional_declarations(Module *module);
|
||||
void sema_analysis_pass_process_methods(Module *module);
|
||||
void sema_analysis_pass_process_methods(Module *module, bool process_generic);
|
||||
void sema_analysis_pass_decls(Module *module);
|
||||
void sema_analysis_pass_ct_assert(Module *module);
|
||||
void sema_analysis_pass_ct_echo(Module *module);
|
||||
|
||||
@@ -386,15 +386,21 @@ void sema_analysis_pass_process_includes(Module *module)
|
||||
}
|
||||
|
||||
|
||||
void sema_analysis_pass_process_methods(Module *module)
|
||||
void sema_analysis_pass_process_methods(Module *module, bool process_generic)
|
||||
{
|
||||
DEBUG_LOG("Pass: Process methods register for module '%s'.", module->name->module);
|
||||
FOREACH(CompilationUnit *, unit, module->units)
|
||||
{
|
||||
SemaContext context;
|
||||
sema_context_init(&context, unit);
|
||||
FOREACH(Decl *, method, unit->methods_to_register)
|
||||
FOREACH(Decl *, method, process_generic ? unit->generic_methods_to_register : unit->methods_to_register)
|
||||
{
|
||||
TypeInfo *parent_type_info = type_infoptr(method->func_decl.type_parent);
|
||||
if (!process_generic && sema_unresolved_type_is_generic(&context, parent_type_info))
|
||||
{
|
||||
vec_add(unit->generic_methods_to_register, method);
|
||||
continue;
|
||||
}
|
||||
sema_analyse_method_register(&context, method);
|
||||
if (method->decl_kind == DECL_MACRO)
|
||||
{
|
||||
@@ -406,7 +412,14 @@ void sema_analysis_pass_process_methods(Module *module)
|
||||
}
|
||||
}
|
||||
sema_context_destroy(&context);
|
||||
vec_resize(unit->methods_to_register, 0);
|
||||
if (process_generic)
|
||||
{
|
||||
vec_resize(unit->generic_methods_to_register, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_resize(unit->methods_to_register, 0);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG("Pass finished with %d error(s).", compiler.context.errors_found);
|
||||
|
||||
@@ -363,6 +363,21 @@ INLINE bool sema_resolve_vatype(SemaContext *context, TypeInfo *type_info)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sema_unresolved_type_is_generic(SemaContext *context, TypeInfo *type_info)
|
||||
{
|
||||
RETRY:
|
||||
if (type_info->kind == TYPE_INFO_GENERIC) return true;
|
||||
if (type_info->resolve_status == RESOLVE_DONE) return false;
|
||||
if (type_info->kind != TYPE_INFO_IDENTIFIER) return false;
|
||||
if (type_info->subtype != TYPE_COMPRESSED_NONE) return false;
|
||||
Decl *decl = sema_resolve_symbol(context, type_info->unresolved.name, type_info->unresolved.path, type_info->span);
|
||||
if (decl->decl_kind != DECL_TYPEDEF) return false;
|
||||
if (decl->resolve_status == RESOLVE_DONE) return false;
|
||||
if (decl->typedef_decl.is_func) return false;
|
||||
type_info = decl->typedef_decl.type_info;
|
||||
goto RETRY;
|
||||
}
|
||||
|
||||
// Foo(<...>)
|
||||
INLINE bool sema_resolve_generic_type(SemaContext *context, TypeInfo *type_info)
|
||||
{
|
||||
|
||||
@@ -159,13 +159,19 @@ void sema_analyze_stage(Module *module, AnalysisStage stage)
|
||||
sema_analysis_pass_register_global_declarations(module);
|
||||
break;
|
||||
case ANALYSIS_METHODS_REGISTER:
|
||||
sema_analysis_pass_process_methods(module);
|
||||
sema_analysis_pass_process_methods(module, false);
|
||||
break;
|
||||
case ANALYSIS_METHODS_REGISTER_GENERIC:
|
||||
sema_analysis_pass_process_methods(module, true);
|
||||
break;
|
||||
case ANALYSIS_INCLUDES:
|
||||
sema_analysis_pass_process_includes(module);
|
||||
break;
|
||||
case ANALYSIS_METHODS_INCLUDES:
|
||||
sema_analysis_pass_process_methods(module);
|
||||
sema_analysis_pass_process_methods(module, false);
|
||||
break;
|
||||
case ANALYSIS_METHODS_INCLUDES_GENERIC:
|
||||
sema_analysis_pass_process_methods(module, true);
|
||||
break;
|
||||
case ANALYSIS_REGISTER_CONDITIONAL_UNITS:
|
||||
sema_analysis_pass_register_conditional_units(module);
|
||||
@@ -174,7 +180,10 @@ void sema_analyze_stage(Module *module, AnalysisStage stage)
|
||||
sema_analysis_pass_register_conditional_declarations(module);
|
||||
break;
|
||||
case ANALYSIS_METHODS_CONDITIONAL:
|
||||
sema_analysis_pass_process_methods(module);
|
||||
sema_analysis_pass_process_methods(module, false);
|
||||
break;
|
||||
case ANALYSIS_METHODS_CONDITIONAL_GENERIC:
|
||||
sema_analysis_pass_process_methods(module, true);
|
||||
break;
|
||||
case ANALYSIS_POST_REGISTER:
|
||||
break;
|
||||
@@ -265,7 +274,6 @@ static void sema_analyze_to_stage(AnalysisStage stage)
|
||||
{
|
||||
if (stage <= ANALYSIS_MODULE_TOP)
|
||||
{
|
||||
|
||||
FOREACH(Module *, module, compiler.context.generic_module_list)
|
||||
{
|
||||
sema_analyze_stage(module, stage);
|
||||
|
||||
19
test/test_suite/methods/extension_method_check.c3
Normal file
19
test/test_suite/methods/extension_method_check.c3
Normal file
@@ -0,0 +1,19 @@
|
||||
module test;
|
||||
|
||||
def Bob = Test(<any>);
|
||||
fn void Bob.crash(&self) {}
|
||||
|
||||
fn int main()
|
||||
{
|
||||
Test(<any>) foo;
|
||||
return 0;
|
||||
}
|
||||
<*
|
||||
@require $defined(String.hash)
|
||||
*>
|
||||
module test::generic(<Some_Type>);
|
||||
|
||||
enum Test
|
||||
{
|
||||
ABC
|
||||
}
|
||||
Reference in New Issue
Block a user