@@ -127,7 +127,34 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) {
127127 g.expr (arg.expr)
128128 g.writeln (';' )
129129 }
130- call_ret_type := g.unwrap_generic (node.call_expr.return_type)
130+ call_ret_type := if expr.is_fn_var && g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0
131+ && g.cur_fn.generic_names.len > 0 {
132+ // In generic contexts, node.call_expr.return_type may be stale from
133+ // a previous instantiation. Look up the original fn param from the table
134+ // and resolve through convert_generic_type.
135+ mut resolved_ret := g.unwrap_generic (node.call_expr.return_type)
136+ cur_fn_name := g.cur_fn.fkey ()
137+ orig_fn := g.table.find_fn (cur_fn_name) or { ast.Fn{} }
138+ for param in orig_fn.params {
139+ if param.name == expr.name {
140+ if param.typ.has_flag (.generic) || g.type_has_unresolved_generic_parts (param.typ) {
141+ mut muttable := unsafe { & ast.Table (g.table) }
142+ if resolved_type := muttable.convert_generic_type (param.typ, orig_fn.generic_names,
143+ g.cur_concrete_types)
144+ {
145+ fn_sym := g.table.sym (resolved_type)
146+ if fn_sym.info is ast.FnType {
147+ resolved_ret = fn_sym.info.func.return_type
148+ }
149+ }
150+ }
151+ break
152+ }
153+ }
154+ resolved_ret
155+ } else {
156+ g.unwrap_generic (node.call_expr.return_type)
157+ }
131158 s_ret_typ := g.styp (g.unwrap_generic (call_ret_type))
132159 if g.pref.os == .windows && call_ret_type != ast.void_type {
133160 g.writeln ('${arg_tmp_var} ->ret_ptr = (void *) builtin___v_malloc(sizeof(${s_ret_typ} ));' )
@@ -191,6 +218,7 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) {
191218 g.type_definitions.writeln ('\n typedef struct ${wrapper_struct_name} {' )
192219 mut fn_var := ''
193220 mut wrapper_return_type := call_ret_type
221+ mut resolved_fn_params := []ast.Param{}
194222 if node.call_expr.is_fn_var {
195223 mut fn_var_type := node.call_expr.fn_var_type
196224 // In generic contexts, fn_var_type may be stale from the last checker pass.
@@ -217,6 +245,7 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) {
217245 }
218246 fn_sym := g.table.sym (fn_var_type)
219247 info := fn_sym.info as ast.FnType
248+ resolved_fn_params = info.func.params.clone ()
220249 wrapper_return_type = info.func.return_type
221250 fn_var = g.fn_var_signature (ast.void_type, wrapper_return_type, info.func.params.map (it .typ),
222251 'fn' )
@@ -278,16 +307,20 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) {
278307 need_return_ptr := g.pref.os == .windows && wrapper_return_type != ast.void_type
279308 for i, arg in expr.args {
280309 mut arg_typ := arg.typ
281- // For AnonFn calls in generic contexts, use the declared parameter
282- // types instead of argument expression types, since the AST arg types
283- // may be stale from a previous generic instantiation.
310+ // For fn var and AnonFn calls in generic contexts, use the declared
311+ // parameter types instead of argument expression types, since the
312+ // AST arg types may be stale from a previous generic instantiation.
284313 if g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0 {
285314 if expr.left is ast.AnonFn {
286315 anon := expr.left as ast.AnonFn
287316 f := anon.decl
288317 if i < f.params.len {
289318 arg_typ = g.unwrap_generic (f.params[i].typ)
290319 }
320+ } else if expr.is_fn_var && resolved_fn_params.len > 0 {
321+ if i < resolved_fn_params.len {
322+ arg_typ = resolved_fn_params[i].typ
323+ }
291324 } else {
292325 resolved_arg_typ := g.unwrap_generic (arg_typ)
293326 if resolved_arg_typ != 0 {
0 commit comments