diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index c980844e5e..a159592360 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -4196,6 +4196,10 @@ fn (mut g Gen) return_statement(node ast.Return) { if !g.fn_decl.return_type.is_ptr() && node.types[0].is_ptr() { // Automatic Dereference for optional g.write('*') + // Fixes returning a mutable receiver with interface as return type + if node.exprs[0] is ast.Ident && !g.is_amp { + g.write('&') + } } for i, expr in node.exprs { g.expr(expr) diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index d698456f83..b63e522f58 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -788,7 +788,9 @@ fn (mut g Gen) call_args(node ast.CallExpr) { exp_sym := g.table.get_type_symbol(expected_types[i]) // exp_styp := g.typ(expected_types[arg_no]) // g.table.get_type_symbol(expected_types[arg_no]) // styp := g.typ(arg.typ) // g.table.get_type_symbol(arg.typ) - if exp_sym.kind == .interface_ { + // NB: the second check avoids casting the interface into itself + // aka avoid 'I__Speaker_to_Interface_Speaker' thing for example + if exp_sym.kind == .interface_ && expected_types[i] != arg.typ { g.interface_call(arg.typ, expected_types[i]) is_interface = true } diff --git a/vlib/v/tests/interface_test.v b/vlib/v/tests/interface_test.v index 1deca146e5..8059418679 100644 --- a/vlib/v/tests/interface_test.v +++ b/vlib/v/tests/interface_test.v @@ -188,6 +188,52 @@ fn test_register() { interface Speaker2 { name() string speak() + return_speaker() Speaker2 + return_speaker2() ?Speaker2 +} + +struct Boss { +mut: + name string +} + +fn (b Boss) name() string { + return b.name +} + +fn (b Boss) speak() { + println("i'm $b.name") +} + +fn (b &Boss) return_speaker() Speaker2 { + return b +} + +fn (mut b Boss) return_speaker2() ?Speaker2 { + if b.name == 'richard' { + return none + } + b.name = 'boss' + return b +} + +fn return_speaker2(sp Speaker2) Speaker2 { + s := sp.return_speaker() + s2 := sp.return_speaker2() or { + return sp + } + s.speak() + s2.speak() + return s2 +} + +fn test_interface_returning_interface() { + mut b := Boss{'bob'} + assert b.name == 'bob' + s2 := return_speaker2(b) + if s2 is Boss { + assert s2.name == 'boss' + } } struct Foo {