diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index e3f696d70f..e645ed666b 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -3660,6 +3660,14 @@ _Interface I_${cctype}_to_Interface_${interface_name}(${cctype}* x) { ._object = (void*) (x), ._interface_idx = ${interface_index_name} }; +} + +_Interface* I_${cctype}_to_Interface_${interface_name}_ptr(${cctype}* x) { + /* TODO Remove memdup */ + return (_Interface*) memdup(&(_Interface) { + ._object = (void*) (x), + ._interface_idx = ${interface_index_name} + }, sizeof(_Interface)); }') methods_struct.writeln('\t{') st_sym := g.table.get_type_symbol(st) @@ -3766,7 +3774,11 @@ fn (mut g Gen) array_init(it ast.ArrayInit) { fn (g &Gen) interface_call(typ, interface_type table.Type) { interface_styp := g.cc_type(interface_type) styp := g.cc_type(typ) - g.write('/* $interface_styp */ I_${styp}_to_Interface_${interface_styp}(') + mut cast_fn_name := 'I_${styp}_to_Interface_${interface_styp}' + if interface_type.is_ptr() { + cast_fn_name += '_ptr' + } + g.write('${cast_fn_name}(') if !typ.is_ptr() { g.write('&') } diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index 6a8c22e5ef..b1bbbdda42 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -298,9 +298,10 @@ fn (mut g Gen) method_call(node ast.CallExpr) { // Speaker_name_table[s._interface_idx].speak(s._object) g.write('${c_name(receiver_type_name)}_name_table[') g.expr(node.left) - g.write('._interface_idx].${node.name}(') + dot := if node.left_type.is_ptr() { '->' } else { '.' } + g.write('${dot}_interface_idx].${node.name}(') g.expr(node.left) - g.write('._object') + g.write('${dot}_object') if node.args.len > 0 { g.write(', ') g.call_args(node.args, node.expected_arg_types) @@ -554,11 +555,14 @@ fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) { // styp := g.typ(arg.typ) // g.table.get_type_symbol(arg.typ) if exp_sym.kind == .interface_ { g.interface_call(arg.typ, expected_types[i]) - // g.write('/*Z*/I_${styp}_to_${exp_styp}(') is_interface = true } } - g.ref_or_deref_arg(arg, expected_types[i]) + if is_interface { + g.expr(arg.expr) + } else { + g.ref_or_deref_arg(arg, expected_types[i]) + } } else { g.expr(arg.expr) } diff --git a/vlib/v/tests/interface_test.v b/vlib/v/tests/interface_test.v index 68807e860b..6ffffc1ede 100644 --- a/vlib/v/tests/interface_test.v +++ b/vlib/v/tests/interface_test.v @@ -3,6 +3,7 @@ struct Dog { } struct Cat { +mut: breed string } @@ -25,6 +26,10 @@ fn (c Cat) name_detailed(pet_name string) string { return '$pet_name the ${typeof(c)}, breed:${c.breed}' } +fn (c mut Cat) set_breed(new string) { + c.breed = new +} + // utility function to convert to string, as a sample fn (c Cat) str() string { return 'Cat: $c.breed' @@ -44,6 +49,10 @@ fn (d Dog) name_detailed(pet_name string) string { return '$pet_name the ${typeof(d)}, breed:${d.breed}' } +fn (d mut Dog) set_breed(new string) { + println('Nah') +} + // do not add to Dog the utility function 'str', as a sample fn test_todo() { if true { @@ -62,11 +71,23 @@ fn perform_speak(a Animal) { println(a.name()) } +fn perform_speak_on_ptr(a &Animal) { + a.speak('Hi !') + assert true + name := a.name() + assert name == 'Dog' || name == 'Cat' + // if a is Dog { + // assert name == 'Dog' + // } + println(a.name()) +} + fn test_perform_speak() { dog := Dog{ breed: 'Labrador Retriever' } perform_speak(dog) + perform_speak_on_ptr(dog) cat := Cat{ breed: 'Persian' } @@ -74,6 +95,10 @@ fn test_perform_speak() { perform_speak(Cat{ breed: 'Persian' }) + perform_speak_on_ptr(cat) + perform_speak_on_ptr(Cat{ + breed: 'Persian' + }) handle_animals([dog, cat]) /* f := Foo { @@ -82,6 +107,19 @@ fn test_perform_speak() { */ } +fn change_animal_breed(a &Animal, new string) { + a.set_breed(new) +} + +fn test_interface_ptr_modification() { + mut cat := Cat{ + breed: 'Persian' + } + // TODO Should fail and require `mut cat` + change_animal_breed(cat, 'Siamese') + assert cat.breed == 'Siamese' +} + fn perform_name_detailed(a Animal) { name_full := a.name_detailed('MyPet') println(name_full) @@ -142,6 +180,7 @@ interface Animal { name() string name_detailed(pet_name string) string speak(s string) + set_breed(s string) } fn test_interface_array() { @@ -150,6 +189,7 @@ fn test_interface_array() { animals = [Cat{}, Dog{ breed: 'Labrador Retriever' }] + assert true animals << Cat{} assert true // TODO .str() from the real types should be called @@ -157,3 +197,14 @@ fn test_interface_array() { // println('Animals array contains: ${animals}') // implicit call to 'str' function assert animals.len == 3 } + +fn test_interface_ptr_array() { + mut animals := []&Animal{} + animals = [Cat{}, Dog{ + breed: 'Labrador Retriever' + }] + assert true + animals << Cat{} + assert true + assert animals.len == 3 +}