diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 98396b24c5..15de443f75 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -78,7 +78,7 @@ mut: is_sql bool // Inside `sql db{}` statement, generating sql instead of C (e.g. `and` instead of `&&` etc) is_shared bool // for initialization of hidden mutex in `[rw]shared` literals is_vlines_enabled bool // is it safe to generate #line directives when -g is passed - is_cast_in_heap bool // fn return struct_init to interface type (cannot use stack, should use heap) + inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls) arraymap_set_pos int // map or array set value position vlines_path string // set to the proper path for generating #line directives optionals []string // to avoid duplicates TODO perf, use map @@ -1833,11 +1833,21 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ } if exp_sym.kind == .interface_ && got_type_raw.idx() != expected_type.idx() && !expected_type.has_flag(.optional) { - got_styp := g.cc_type(got_type, true) - exp_styp := g.cc_type(expected_type, true) - fname := 'I_${got_styp}_to_Interface_$exp_styp' - g.call_cfn_for_casting_expr(fname, expr, expected_is_ptr, exp_styp, got_is_ptr, - got_styp) + if expr is ast.StructInit && !got_type.is_ptr() { + g.inside_cast_in_heap++ + got_styp := g.cc_type(got_type.to_ptr(), true) + exp_styp := g.cc_type(expected_type, true) + fname := 'I_${got_styp}_to_Interface_$exp_styp' + g.call_cfn_for_casting_expr(fname, expr, expected_is_ptr, exp_styp, true, + got_styp) + g.inside_cast_in_heap-- + } else { + got_styp := g.cc_type(got_type, true) + exp_styp := g.cc_type(expected_type, true) + fname := 'I_${got_styp}_to_Interface_$exp_styp' + g.call_cfn_for_casting_expr(fname, expr, expected_is_ptr, exp_styp, got_is_ptr, + got_styp) + } return } // cast to sum type @@ -4733,14 +4743,7 @@ fn (mut g Gen) return_stmt(node ast.Return) { g.expr(expr0) } } else { - rs := g.table.get_type_symbol(g.fn_decl.return_type) - if node.exprs[0] is ast.StructInit && rs.kind == .interface_ && !node.types[0].is_ptr() { - g.is_cast_in_heap = true - g.expr_with_cast(node.exprs[0], node.types[0].to_ptr(), g.fn_decl.return_type) - g.is_cast_in_heap = false - } else { - g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type) - } + g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type) } if use_tmp_var { g.writeln(';') @@ -4928,7 +4931,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { mut shared_typ := struct_init.typ.set_flag(.shared_f) shared_styp = g.typ(shared_typ) g.writeln('($shared_styp*)__dup${shared_styp}(&($shared_styp){.mtx = {0}, .val =($styp){') - } else if is_amp || g.is_cast_in_heap { + } else if is_amp || g.inside_cast_in_heap > 0 { g.write('($styp*)memdup(&($styp){') } else if struct_init.typ.is_ptr() { basetyp := g.typ(struct_init.typ.set_nr_muls(0)) @@ -5118,7 +5121,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { g.write('}') if g.is_shared && !g.inside_opt_data && !g.is_arraymap_set { g.write('}, sizeof($shared_styp))') - } else if is_amp || g.is_cast_in_heap { + } else if is_amp || g.inside_cast_in_heap > 0 { g.write(', sizeof($styp))') } } diff --git a/vlib/v/tests/interface_fn_return_array_of_interface_test.v b/vlib/v/tests/interface_fn_return_array_of_interface_test.v new file mode 100644 index 0000000000..834e5783f0 --- /dev/null +++ b/vlib/v/tests/interface_fn_return_array_of_interface_test.v @@ -0,0 +1,26 @@ +import os + +interface Node { + name string +} + +struct NodeEmpty { + name string = 'abc' +} + +fn pusher(lines []string) []Node { + mut nodes := []Node{} + + for line in lines { + nodes << NodeEmpty{} + } + + return nodes +} + +fn test_fn_return_array_of_interface() { + lines := os.read_lines(@FILE) or { panic(err) } + pushed := pusher(lines) + println(pushed) + assert pushed.len > 0 +}