From 8caf3829d7be841f5b0671848a5c9683b2b1d9c7 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Wed, 9 Dec 2020 18:51:37 +0200 Subject: [PATCH] checker: fix interface checking of array arguments; closes #2377 --- vlib/v/checker/checker.v | 10 +++---- vlib/v/gen/cgen.v | 4 +++ vlib/v/gen/fn.v | 3 ++ .../array_of_interfaces_test.v | 28 +++++++++++++++++++ ...array_of_interfaces_with_utility_fn_test.v | 28 +++++++++++++++++++ 5 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 vlib/v/tests/interface_edge_cases/array_of_interfaces_test.v create mode 100644 vlib/v/tests/interface_edge_cases/array_of_interfaces_with_utility_fn_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 206138a7ff..fc4977c3bd 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1575,12 +1575,6 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { c.type_implements(typ, arg.typ, call_arg.expr.position()) continue } - // Handle expected interface array - /* - if exp_type_sym.kind == .array && t.get_type_symbol(t.value_type(exp_idx)).kind == .interface_ { - return true - } - */ c.check_expected(typ, arg.typ) or { // str method, allow type with str method if fn arg is string // Passing an int or a string array produces a c error here @@ -1631,6 +1625,9 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { } fn (mut c Checker) type_implements(typ table.Type, inter_typ table.Type, pos token.Position) bool { + $if debug_interface_type_implements ? { + eprintln('> type_implements typ: $typ.debug() | inter_typ: $inter_typ.debug()') + } typ_sym := c.table.get_type_symbol(typ) mut inter_sym := c.table.get_type_symbol(inter_typ) styp := c.table.type_to_str(typ) @@ -2388,6 +2385,7 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type { if i == 0 { elem_type = expected_value_type c.expected_type = elem_type + c.type_implements(typ, elem_type, expr.position()) } continue } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index f2931bb3ba..b5ee219562 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -5638,6 +5638,10 @@ fn (mut g Gen) interface_table() string { // cctype is the Cleaned Concrete Type name, *without ptr*, // i.e. cctype is always just Cat, not Cat_ptr: cctype := g.cc_type(st) + $if debug_interface_table ? { + eprintln('>> interface name: $ityp.name | concrete type: $st.debug() | st symname: ' + + g.table.get_type_symbol(st).name) + } // Speaker_Cat_index = 0 interface_index_name := '_${interface_name}_${cctype}_index' if already_generated_mwrappers[interface_index_name] > 0 { diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index c115a5d66d..dd8541bc27 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -324,6 +324,9 @@ fn (mut g Gen) method_call(node ast.CallExpr) { mut receiver_type_name := util.no_dots(g.cc_type2(g.unwrap_generic(node.receiver_type))) if typ_sym.kind == .interface_ { // Speaker_name_table[s._interface_idx].speak(s._object) + $if debug_interface_method_call ? { + eprintln('>>> interface typ_sym.name: $typ_sym.name | receiver_type_name: $receiver_type_name') + } g.write('${c_name(receiver_type_name)}_name_table[') g.expr(node.left) dot := if node.left_type.is_ptr() { '->' } else { '.' } diff --git a/vlib/v/tests/interface_edge_cases/array_of_interfaces_test.v b/vlib/v/tests/interface_edge_cases/array_of_interfaces_test.v new file mode 100644 index 0000000000..0d32b22bbc --- /dev/null +++ b/vlib/v/tests/interface_edge_cases/array_of_interfaces_test.v @@ -0,0 +1,28 @@ +struct Dog { + breed string +} + +fn (d Dog) name() string { + return 'Dog' +} + +// Utility helper function, to force interface _name_table generation +fn get_name(s Speaker) { +} + +// +fn test_an_array_of_interfaces_works() { + dog := Dog{} + // get_name(dog) // uncommenting this line fixes the example + get_names([dog, dog]) +} + +fn get_names(speakers []Speaker) { + for s in speakers { + println(s.name()) + } +} + +interface Speaker { + name() string +} diff --git a/vlib/v/tests/interface_edge_cases/array_of_interfaces_with_utility_fn_test.v b/vlib/v/tests/interface_edge_cases/array_of_interfaces_with_utility_fn_test.v new file mode 100644 index 0000000000..32c794b7b6 --- /dev/null +++ b/vlib/v/tests/interface_edge_cases/array_of_interfaces_with_utility_fn_test.v @@ -0,0 +1,28 @@ +struct Dog { + breed string +} + +fn (d Dog) name() string { + return 'Dog' +} + +// Utility helper function, to force interface _name_table generation +fn get_name(s Speaker) { +} + +// +fn test_an_array_of_interfaces_works() { + dog := Dog{} + get_name(dog) // NB: this line does nothing, but forces interface _name_table generation + get_names([dog, dog]) +} + +fn get_names(speakers []Speaker) { + for s in speakers { + println(s.name()) + } +} + +interface Speaker { + name() string +}