@@ -71,21 +71,22 @@ mut:
7171 // in_return is true only while generating a `return` statement's value, so a bare
7272 // generic literal (`return Box{...}`) may adopt `cur_fn_ret`'s concrete instance —
7373 // but a literal in a local decl / argument elsewhere in the body does not.
74- in_return bool
75- expected_expr_type types.Type = types.Type(types.void_)
76- expected_enum string
77- needed_optional_types map[string]string
78- emitted_optional_types map[string]bool
79- emitted_fns map[string]bool
80- array_method_cache map[string]string
81- param_types_cache map[string][]types.Type // (name|fallback) -> resolved param types
82- embedded_fields_by_type map[string][]types.StructField // type name -> its embedded fields (usually empty)
83- param_types_by_short map[string][]types.Type // method short-name suffix -> param types (fallback index)
84- spawn_wrapper_names map[string]string
85- spawn_wrapper_defs []string
86- callback_wrapper_names map[string]string
87- callback_wrapper_defs []string
88- parallel_used bool
74+ in_return bool
75+ expected_expr_type types.Type = types.Type(types.void_)
76+ expected_enum string
77+ needed_optional_types map[string]string
78+ emitted_optional_types map[string]bool
79+ emitted_fns map[string]bool
80+ array_method_cache map[string]string
81+ param_types_cache map[string][]types.Type // (name|fallback) -> resolved param types
82+ embedded_fields_by_type map[string][]types.StructField // type name -> its embedded fields (usually empty)
83+ param_types_by_short map[string][]types.Type // method short-name suffix -> param types (fallback index)
84+ generic_method_candidates map[string][]GenericMethodCandidate
85+ spawn_wrapper_names map[string]string
86+ spawn_wrapper_defs []string
87+ callback_wrapper_names map[string]string
88+ callback_wrapper_defs []string
89+ parallel_used bool
8990}
9091
9192struct FixedArrayTypedefInfo {
@@ -166,6 +167,7 @@ pub fn FlatGen.new() FlatGen {
166167 param_types_cache: map[string][]types.Type{}
167168 embedded_fields_by_type: map[string][]types.StructField{}
168169 param_types_by_short: map[string][]types.Type{}
170+ generic_method_candidates: map[string][]GenericMethodCandidate{}
169171 spawn_wrapper_names: map[string]string{}
170172 spawn_wrapper_defs: []string{}
171173 callback_wrapper_names: map[string]string{}
@@ -260,6 +262,7 @@ pub fn (mut g FlatGen) gen_with_used_options(a &flat.FlatAst, used_fns map[strin
260262 g.param_types_cache = map[string][]types.Type{}
261263 g.embedded_fields_by_type = map[string][]types.StructField{}
262264 g.param_types_by_short = map[string][]types.Type{}
265+ g.generic_method_candidates = map[string][]GenericMethodCandidate{}
263266 g.spawn_wrapper_names = map[string]string{}
264267 g.spawn_wrapper_defs = []string{}
265268 g.callback_wrapper_names = map[string]string{}
@@ -277,6 +280,7 @@ pub fn (mut g FlatGen) gen_with_used_options(a &flat.FlatAst, used_fns map[strin
277280 g.preseed_struct_fn_ptr_types()
278281 g.preseed_global_fn_ptr_types()
279282 g.preseed_c_extern_fn_ptr_types()
283+ g.precompute_generic_method_candidate_index()
280284 // Decide fixed-array return wrappers before generating function bodies, so
281285 // signatures, returns and call sites all agree on the wrapped types.
282286 g.populate_fixed_array_ret_wrappers()
@@ -24,6 +24,12 @@ struct TopLevelStmt {
2424 module string
2525}
2626
27+struct GenericMethodCandidate {
28+ name string
29+ ret types.Type
30+ params []types.Type
31+}
32+
2733// gen_fns emits fns output for c.
2834fn (mut g FlatGen) gen_fns() {
2935 preferred_fns := g.preferred_c_backend_fn_nodes()
@@ -292,6 +298,45 @@ fn (g &FlatGen) emitted_fn_contains(name string) bool {
292298 return name.len > 0 && g.emitted_fns[name]
293299}
294300
301+fn generic_method_candidate_key(receiver string, method string) string {
302+ return '${receiver}\n${method}'
303+}
304+
305+fn (mut g FlatGen) precompute_generic_method_candidate_index() {
306+ g.generic_method_candidates = map[string][]GenericMethodCandidate{}
307+ for name, ret in g.tc.fn_ret_types {
308+ if !name.contains('[') || !name.contains('.') {
309+ continue
310+ }
311+ method := name.all_after_last('.')
312+ receiver := name.all_before_last('.')
313+ if method.len == 0 || !receiver.contains('[') {
314+ continue
315+ }
316+ base_receiver := receiver.all_before('[')
317+ if base_receiver.len == 0 {
318+ continue
319+ }
320+ candidate := GenericMethodCandidate{
321+ name: name
322+ ret: ret
323+ params: g.tc.fn_param_types[name] or { []types.Type{} }
324+ }
325+ g.add_generic_method_candidate(base_receiver, method, candidate)
326+ short_receiver := base_receiver.all_after_last('.')
327+ if short_receiver != base_receiver {
328+ g.add_generic_method_candidate(short_receiver, method, candidate)
329+ }
330+ }
331+}
332+
333+fn (mut g FlatGen) add_generic_method_candidate(receiver string, method string, candidate GenericMethodCandidate) {
334+ key := generic_method_candidate_key(receiver, method)
335+ mut candidates := g.generic_method_candidates[key] or { []GenericMethodCandidate{} }
336+ candidates << candidate
337+ g.generic_method_candidates[key] = candidates
338+}
339+
295340// qualified_fn_name supports qualified fn name handling for FlatGen.
296341fn (g &FlatGen) qualified_fn_name(name string) string {
297342 return qualified_fn_name_in_module(g.tc.cur_module, name)
@@ -545,26 +590,21 @@ fn (g &FlatGen) specialized_generic_method_name_for_call_with_arg_count(id flat.
545590 }
546591 }
547592 }
548- for allow_short_receiver in [false, true] {
549- for candidate, ret in g.tc.fn_ret_types {
550- if !candidate.contains('[') || candidate.all_after_last('.') != method {
593+ for lookup_receiver in [receiver, receiver.all_after_last('.')] {
594+ candidates := g.generic_method_candidates[generic_method_candidate_key(lookup_receiver,
595+ method)] or { continue }
596+ for candidate in candidates {
597+ if arg_count >= 0 && candidate.params.len != arg_count {
551598 continue
552599 }
553- candidate_receiver := candidate.all_before_last('.')
554- base_receiver := candidate_receiver.all_before('[')
555- receiver_matches := base_receiver == receiver || (allow_short_receiver
556- && base_receiver.all_after_last('.') == receiver.all_after_last('.'))
557- if !receiver_matches {
558- continue
559- }
560- params := g.tc.fn_param_types[candidate] or { []types.Type{} }
561- if arg_count >= 0 && params.len != arg_count {
562- continue
563- }
564- if g.type_names_match(call_ret, ret) || call_ret.name() == ret.name() {
565- return candidate
600+ if g.type_names_match(call_ret, candidate.ret)
601+ || call_ret.name() == candidate.ret.name() {
602+ return candidate.name
566603 }
567604 }
605+ if lookup_receiver == receiver.all_after_last('.') {
606+ break
607+ }
568608 }
569609 return none
570610}
@@ -362,62 +362,63 @@ fn (mut g FlatGen) fn_ptr_type_key(typ types.FnType) string {
362362// worker and, under -gc none, never freed.
363363fn (g &FlatGen) new_parallel_worker(worker_id int) &FlatGen {
364364 return &FlatGen{
365- sb: strings.new_builder(64_000)
366- a: unsafe { g.a }
367- used_fns: g.used_fns
368- used_fn_names: g.used_fn_names
369- test_files: g.test_files.clone()
370- str_lits: g.str_lits.clone()
371- str_lit_ids: g.str_lit_ids.clone()
372- global_types: g.global_types
373- enum_vals: g.enum_vals
374- interfaces: g.interfaces
375- const_vals: g.const_vals
376- const_modules: g.const_modules
377- const_init_order: g.const_init_order
378- global_modules: g.global_modules
379- global_inits: g.global_inits
380- global_init_order: g.global_init_order
381- iface_impls: g.iface_impls
382- iface_type_ids: g.iface_type_ids
383- module_init_fns: g.module_init_fns
384- module_init_fn_modules: g.module_init_fn_modules
385- module_imports: g.module_imports
386- libc_compat_fns: g.libc_compat_fns.clone()
387- tc: g.clone_parallel_type_checker()
388- has_builtins: g.has_builtins
389- tmp_count: (worker_id + 1) * 100_000
390- line_start: true
391- modules: g.modules
392- fn_ptr_types: g.fn_ptr_types.clone()
393- fixed_array_ret_wrappers: g.fixed_array_ret_wrappers
394- fn_decl_param_types: g.fn_decl_param_types
395- fn_decl_ret_types: g.fn_decl_ret_types
396- struct_decl_infos: g.struct_decl_infos
397- struct_decl_short_infos: g.struct_decl_short_infos
398- const_runtime_inits: g.const_runtime_inits.clone()
399- runtime_inits: g.runtime_inits.clone()
400- compiler_vroot: g.compiler_vroot
401- cur_param_names: g.cur_param_names.clone()
402- cur_param_type_values: g.cur_param_type_values.clone()
403- cur_param_types: g.cur_param_types.clone()
404- cur_mut_params: g.cur_mut_params.clone()
405- cur_fn_ret: g.cur_fn_ret
406- cur_fn_ret_is_optional: g.cur_fn_ret_is_optional
407- cur_fn_ret_base: g.cur_fn_ret_base
408- expected_expr_type: g.expected_expr_type
409- expected_enum: g.expected_enum
410- needed_optional_types: g.needed_optional_types.clone()
411- emitted_optional_types: g.emitted_optional_types.clone()
412- emitted_fns: g.emitted_fns.clone()
413- array_method_cache: g.array_method_cache.clone()
414- param_types_cache: g.param_types_cache.clone()
415- embedded_fields_by_type: g.embedded_fields_by_type
416- param_types_by_short: g.param_types_by_short
417- spawn_wrapper_names: g.spawn_wrapper_names.clone()
418- spawn_wrapper_defs: g.spawn_wrapper_defs.clone()
419- callback_wrapper_names: g.callback_wrapper_names.clone()
420- callback_wrapper_defs: g.callback_wrapper_defs.clone()
365+ sb: strings.new_builder(64_000)
366+ a: unsafe { g.a }
367+ used_fns: g.used_fns
368+ used_fn_names: g.used_fn_names
369+ test_files: g.test_files.clone()
370+ str_lits: g.str_lits.clone()
371+ str_lit_ids: g.str_lit_ids.clone()
372+ global_types: g.global_types
373+ enum_vals: g.enum_vals
374+ interfaces: g.interfaces
375+ const_vals: g.const_vals
376+ const_modules: g.const_modules
377+ const_init_order: g.const_init_order
378+ global_modules: g.global_modules
379+ global_inits: g.global_inits
380+ global_init_order: g.global_init_order
381+ iface_impls: g.iface_impls
382+ iface_type_ids: g.iface_type_ids
383+ module_init_fns: g.module_init_fns
384+ module_init_fn_modules: g.module_init_fn_modules
385+ module_imports: g.module_imports
386+ libc_compat_fns: g.libc_compat_fns.clone()
387+ tc: g.clone_parallel_type_checker()
388+ has_builtins: g.has_builtins
389+ tmp_count: (worker_id + 1) * 100_000
390+ line_start: true
391+ modules: g.modules
392+ fn_ptr_types: g.fn_ptr_types.clone()
393+ fixed_array_ret_wrappers: g.fixed_array_ret_wrappers
394+ fn_decl_param_types: g.fn_decl_param_types
395+ fn_decl_ret_types: g.fn_decl_ret_types
396+ struct_decl_infos: g.struct_decl_infos
397+ struct_decl_short_infos: g.struct_decl_short_infos
398+ const_runtime_inits: g.const_runtime_inits.clone()
399+ runtime_inits: g.runtime_inits.clone()
400+ compiler_vroot: g.compiler_vroot
401+ cur_param_names: g.cur_param_names.clone()
402+ cur_param_type_values: g.cur_param_type_values.clone()
403+ cur_param_types: g.cur_param_types.clone()
404+ cur_mut_params: g.cur_mut_params.clone()
405+ cur_fn_ret: g.cur_fn_ret
406+ cur_fn_ret_is_optional: g.cur_fn_ret_is_optional
407+ cur_fn_ret_base: g.cur_fn_ret_base
408+ expected_expr_type: g.expected_expr_type
409+ expected_enum: g.expected_enum
410+ needed_optional_types: g.needed_optional_types.clone()
411+ emitted_optional_types: g.emitted_optional_types.clone()
412+ emitted_fns: g.emitted_fns.clone()
413+ array_method_cache: g.array_method_cache.clone()
414+ param_types_cache: g.param_types_cache.clone()
415+ embedded_fields_by_type: g.embedded_fields_by_type
416+ param_types_by_short: g.param_types_by_short
417+ generic_method_candidates: g.generic_method_candidates
418+ spawn_wrapper_names: g.spawn_wrapper_names.clone()
419+ spawn_wrapper_defs: g.spawn_wrapper_defs.clone()
420+ callback_wrapper_names: g.callback_wrapper_names.clone()
421+ callback_wrapper_defs: g.callback_wrapper_defs.clone()
421422 }
422423}