From e84e23f7ec70e925d17495cae109d0df5bead52f Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 20 Jan 2026 01:04:12 +0100 Subject: [PATCH] Fix Using @if with methods with generic params only inferred from the parent type fails #2770 --- src/compiler/compiler_internal.h | 1 + src/compiler/sema_name_resolution.c | 15 +++++++++++ src/compiler/sema_passes.c | 27 +++++++++++++++++++ .../generic/generic_with_method_ad_hoc.c3t | 11 ++++++++ 4 files changed, 54 insertions(+) create mode 100644 test/test_suite/generic/generic_with_method_ad_hoc.c3t diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index ccf7abb83..d92c40b0e 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2567,6 +2567,7 @@ Decl *sema_find_label_symbol_anywhere(SemaContext *context, const char *symbol); Decl *sema_find_local(SemaContext *context, const char *symbol); Decl *sema_resolve_symbol(SemaContext *context, const char *symbol, Path *path, SourceSpan span); Decl *sema_resolve_parameterized_symbol(SemaContext *context, const char *symbol, Path *path, SourceSpan span); +Decl *sema_resolve_maybe_parameterized_symbol(SemaContext *context, const char *symbol, Path *path, SourceSpan span); 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); diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 588f3585b..1134cc3f2 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -1190,6 +1190,21 @@ Decl *sema_resolve_parameterized_symbol(SemaContext *context, const char *symbol return resolve.found; } +Decl *sema_resolve_maybe_parameterized_symbol(SemaContext *context, const char *symbol, Path *path, SourceSpan span) +{ + NameResolve resolve = { + .path = path, + .span = span, + .symbol = symbol, + .is_parameterized = true, + .suppress_error = true + }; + if (!sema_resolve_symbol_common(context, &resolve)) return NULL; + Decl *found = resolve.found; + if (!decl_ok(found)) return NULL; + return resolve.found; +} + bool sema_parameterized_type_is_found(SemaContext *context, Path *decl_path, const char *name, SourceSpan span) { NameResolve name_resolve = { diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index a60024e27..99098c080 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -163,11 +163,38 @@ FOUND_ALIAS: DEBUG_LOG("Pass finished processing %d import(s) with %d error(s).", total_import_count, compiler.context.errors_found); } +static bool sema_check_if_implicit_generic(SemaContext *context, Decl *decl) +{ + if (!decl->func_decl.type_parent) return false; + TypeInfo *typedecl = type_infoptr(decl->func_decl.type_parent); + Decl *d = NULL; + if (typedecl->resolve_status == RESOLVE_DONE) + { + CanonicalType *type = typedecl->type->canonical; + if (!type_is_user_defined(type)) return false; + d = type->decl; + } + else if (typedecl->kind == TYPE_INFO_IDENTIFIER && typedecl->subtype == TYPE_COMPRESSED_NONE) + { + d = sema_resolve_maybe_parameterized_symbol(context, typedecl->unresolved.name, typedecl->unresolved.path, typedecl->span); + } + return d && d->is_template; +} + void unit_register_optional_global_decl(CompilationUnit *unit, Decl *decl) { SemaContext context; sema_context_init(&context, unit); if (decl->is_templated) context.generic_instance = declptr(decl->instance_id); + if (!decl->is_templated && (decl->decl_kind == DECL_MACRO || decl->decl_kind == DECL_FUNC)) + { + if (sema_check_if_implicit_generic(&context, decl)) + { + unit_register_global_decl(unit, decl); + sema_context_destroy(&context); + return; + } + } if (sema_decl_if_cond(&context, decl)) { unit_register_global_decl(unit, decl); diff --git a/test/test_suite/generic/generic_with_method_ad_hoc.c3t b/test/test_suite/generic/generic_with_method_ad_hoc.c3t new file mode 100644 index 000000000..b66fc746c --- /dev/null +++ b/test/test_suite/generic/generic_with_method_ad_hoc.c3t @@ -0,0 +1,11 @@ +import std; +struct Foo { int a; } + +fn void Foo.test(self) @if(Type.sizeof > 4) +{ } + +fn int main() +{ + Foo{int} x; + return 0; +}