From 7af8fafc18db21c6995b776ed2404a9febe09c52 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sun, 22 Dec 2024 09:06:55 -0300 Subject: [PATCH] ast,parser,checker: fix identification of abstract vs real interface methods (interface with a str() method) (fix #23006) (#23238) --- vlib/v/ast/types.v | 6 ++--- vlib/v/checker/fn.v | 2 +- vlib/v/parser/struct.v | 1 + .../interfaces/interface_arr_auto_str_test.v | 25 +++++++++++++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 vlib/v/tests/interfaces/interface_arr_auto_str_test.v diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 832521cb1..36ddfab49 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -1722,8 +1722,8 @@ pub fn (t &TypeSymbol) has_method(name string) bool { } pub fn (t &TypeSymbol) has_method_with_generic_parent(name string) bool { - t.find_method_with_generic_parent(name) or { return false } - return true + m := t.find_method_with_generic_parent(name) or { return false } + return t.kind != .interface || !m.no_body } pub fn (t &TypeSymbol) find_method(name string) ?Fn { @@ -1813,7 +1813,7 @@ pub fn (t &TypeSymbol) str_method_info() (bool, bool, int) { mut expects_ptr := false mut nr_args := 0 if sym_str_method := t.find_method_with_generic_parent('str') { - has_str_method = true + has_str_method = t.kind != .interface || !sym_str_method.no_body nr_args = sym_str_method.params.len if nr_args > 0 { expects_ptr = sym_str_method.params[0].typ.is_ptr() diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 353610cd3..572557835 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -2544,7 +2544,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool) c.fail_if_unreadable(node.left, left_type, 'receiver') } if left_sym.language != .js && (!left_sym.is_builtin() && method.mod != 'builtin') - && method.language == .v && method.no_body { + && method.language == .v && final_left_sym.kind != .interface && method.no_body { c.error('cannot call a method that does not have a body', node.pos) } if node.concrete_types.len > 0 && method.generic_names.len > 0 diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index b2d8a4017..ff88f1dc2 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -738,6 +738,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl { is_pub: true is_method: true receiver_type: typ + no_body: true } ts.register_method(tmethod) info.methods << tmethod diff --git a/vlib/v/tests/interfaces/interface_arr_auto_str_test.v b/vlib/v/tests/interfaces/interface_arr_auto_str_test.v new file mode 100644 index 000000000..1d0b79746 --- /dev/null +++ b/vlib/v/tests/interfaces/interface_arr_auto_str_test.v @@ -0,0 +1,25 @@ +interface Interface { + str() string +} + +struct Result[T] { + data []T +} + +struct Foobar { +} + +fn (f Foobar) str() string { + return 'foobar' +} + +fn test_main() { + assert Result[Interface]{}.str() == 'Result[Interface]{ + data: [] +}' + assert Result[Foobar]{ + data: [Foobar{}] + }.str() == 'Result[Foobar]{ + data: [foobar] +}' +} -- 2.39.5