@@ -2044,22 +2044,36 @@ fn (mut g FlatGen) param_types_for_uncached(name string, fallback string) []type
20442044 return decl_types
20452045 }
20462046 if name.contains ('.' ) {
2047+ // O(1) lookup via the precomputed short-name index instead of scanning the whole
2048+ // function table on every (cache-missing) call — this fallback ran ~3000× and was
2049+ // a top cgen self-time cost (each scan is O(functions)).
20472050 short_name := name.all_after_last ('.' )
2048- suffix := '.${short_name }'
2049- // Look up the value only on a match: `for _, v in map` copies every array value
2050- // on every iteration, which is wasteful for a table-wide scan.
2051- for candidate, _ in g.fn_decl_param_types {
2052- if candidate.ends_with (suffix) {
2053- return g.fn_decl_param_types[candidate]
2051+ if params := g.param_types_by_short[short_name] {
2052+ return params
2053+ }
2054+ }
2055+ return []types.Type{}
2056+ }
2057+
2058+ // precompute_param_type_index builds short-name -> param-types, preserving the fallback's
2059+ // priority (fn_decl_param_types first, then the checker's fn_param_types; first match wins).
2060+ fn (mut g FlatGen) precompute_param_type_index () {
2061+ for name, params in g.fn_decl_param_types {
2062+ if name.contains ('.' ) {
2063+ short := name.all_after_last ('.' )
2064+ if short ! in g.param_types_by_short {
2065+ g.param_types_by_short[short] = params
20542066 }
20552067 }
2056- for candidate, _ in g.tc.fn_param_types {
2057- if candidate.ends_with (suffix) {
2058- return g.tc.fn_param_types[candidate]
2068+ }
2069+ for name, params in g.tc.fn_param_types {
2070+ if name.contains ('.' ) {
2071+ short := name.all_after_last ('.' )
2072+ if short ! in g.param_types_by_short {
2073+ g.param_types_by_short[short] = params
20592074 }
20602075 }
20612076 }
2062- return []types.Type{}
20632077}
20642078
20652079fn (g &FlatGen) interface_method_param_types (name string ) ? []types.Type {
@@ -3051,11 +3065,46 @@ fn fn_ptr_typedef_is_generic_placeholder(typ string) bool {
30513065 return short.len == 1 && short[0 ] > = `A` && short[0 ] < = `Z`
30523066}
30533067
3054- // multi_return_typedefs supports multi return typedefs handling for FlatGen.
3068+ // multi_return_forward_decls forward-declares every multi-return struct that the
3069+ // generated C can reference by name. It must run before fn_ptr_typedefs(), because
3070+ // a function-pointer typedef may name a multi-return as its (by-value) return type
3071+ // — and a `typedef RET (*fp)(...)` only needs RET's tag declared, not its full
3072+ // layout. The full struct bodies are emitted later by multi_return_typedefs(),
3073+ // after the member struct definitions they depend on are available.
3074+ fn (mut g FlatGen) multi_return_forward_decls () {
3075+ mut emitted := map [string ]bool {}
3076+ g.walk_multi_return_typedefs (mut emitted, true )
3077+ // Also cover multi-returns reachable only as a fn-pointer return type: parallel
3078+ // cgen preseeds fn-ptr types that the serial path never materializes, so their
3079+ // return multi-returns may not appear among the function/expression types above.
3080+ for encoded, _ in g.fn_ptr_types {
3081+ ret , _ := fn_ptr_typedef_parts (encoded)
3082+ if ret.starts_with ('multi_return_' ) && ret ! in emitted {
3083+ emitted[ret] = true
3084+ g.writeln ('typedef struct ${ret } ${ret };' )
3085+ }
3086+ }
3087+ if emitted.len > 0 {
3088+ g.writeln ('' )
3089+ }
3090+ }
3091+
3092+ // multi_return_typedefs emits the full struct definitions for multi-return types.
30553093fn (mut g FlatGen) multi_return_typedefs () {
30563094 mut emitted := map [string ]bool {}
3095+ g.walk_multi_return_typedefs (mut emitted, false )
3096+ if emitted.len > 0 {
3097+ g.writeln ('' )
3098+ }
3099+ }
3100+
3101+ // walk_multi_return_typedefs visits every multi-return type reachable from a
3102+ // function return type or an expression type and emits it via emit_multi_return_typedef.
3103+ // Shared by the forward-declaration and full-definition passes so both see the same
3104+ // set in the same (deterministic) order.
3105+ fn (mut g FlatGen) walk_multi_return_typedefs (mut emitted map [string ]bool , forward_only bool ) {
30573106 for _, ret in g.tc.fn_ret_types {
3058- g.emit_multi_return_typedef (ret, mut emitted)
3107+ g.emit_multi_return_typedef (ret, mut emitted, forward_only )
30593108 }
30603109 mut cur_module := ''
30613110 mut cur_file := ''
@@ -3076,23 +3125,28 @@ fn (mut g FlatGen) multi_return_typedefs() {
30763125 }
30773126 g.tc.cur_file = cur_file
30783127 g.tc.cur_module = cur_module
3079- if node.typ.len > 0 {
3080- g.emit_multi_return_typedef (g.tc.parse_type (node.typ), mut emitted)
3128+ // emit_multi_return_typedef only acts on (optionally `?`/`!`-wrapped) multi-return
3129+ // types, whose string form always begins with `(`. Skip parse_type for everything
3130+ // else — this ran on every node's type (~hundreds of thousands of parse_type calls).
3131+ typ := node.typ
3132+ if typ.len > 0 && (typ[0 ] == `(` || ((typ[0 ] == `?` || typ[0 ] == `!` ) && typ.len > 1
3133+ && typ[1 ] == `(` )) {
3134+ g.emit_multi_return_typedef (g.tc.parse_type (typ), mut emitted, forward_only)
30813135 }
30823136 }
3083- if emitted.len > 0 {
3084- g.writeln ('' )
3085- }
30863137}
30873138
3088- // emit_multi_return_typedef emits emit multi return typedef output for c.
3089- fn (mut g FlatGen) emit_multi_return_typedef (ret types.Type, mut emitted map [string ]bool ) {
3139+ // emit_multi_return_typedef emits one multi-return type: a forward declaration
3140+ // (`typedef struct NAME NAME;`) when forward_only, otherwise the full struct body
3141+ // (`struct NAME { ... };`). The two forms are paired — the forward decl provides the
3142+ // typedef name, the body completes the tagged struct.
3143+ fn (mut g FlatGen) emit_multi_return_typedef (ret types.Type, mut emitted map [string ]bool , forward_only bool ) {
30903144 if ret is types.OptionType {
3091- g.emit_multi_return_typedef (ret.base_type, mut emitted)
3145+ g.emit_multi_return_typedef (ret.base_type, mut emitted, forward_only )
30923146 return
30933147 }
30943148 if ret is types.ResultType {
3095- g.emit_multi_return_typedef (ret.base_type, mut emitted)
3149+ g.emit_multi_return_typedef (ret.base_type, mut emitted, forward_only )
30963150 return
30973151 }
30983152 if ret is types.MultiReturn {
@@ -3101,11 +3155,15 @@ fn (mut g FlatGen) emit_multi_return_typedef(ret types.Type, mut emitted map[str
31013155 return
31023156 }
31033157 emitted[name] = true
3104- g.writeln ('typedef struct {' )
3105- for i, typ in ret.types {
3106- g.writeln ('\t ${g .tc .c_type (typ )} arg${i };' )
3158+ if forward_only {
3159+ g.writeln ('typedef struct ${name } ${name };' )
3160+ } else {
3161+ g.writeln ('struct ${name } {' )
3162+ for i, typ in ret.types {
3163+ g.writeln ('\t ${g .tc .c_type (typ )} arg${i };' )
3164+ }
3165+ g.writeln ('};' )
31073166 }
3108- g.writeln ('} ${name };' )
31093167 }
31103168}
31113169
0 commit comments