From 2ee8f93d60054bf651136858704b10e412d5d4e4 Mon Sep 17 00:00:00 2001 From: Enzo Date: Wed, 15 Jul 2020 10:23:21 +0200 Subject: [PATCH] parser: duplicate method declaration on interface (#5825) --- .../tests/no_interface_receiver_duplicate_a.out | 6 ++++++ .../checker/tests/no_interface_receiver_duplicate_a.vv | 6 ++++++ .../tests/no_interface_receiver_duplicate_b.out | 5 +++++ .../checker/tests/no_interface_receiver_duplicate_b.vv | 6 ++++++ vlib/v/parser/fn.v | 10 +++++++--- vlib/v/parser/struct.v | 5 +++++ vlib/v/parser/tests/interface_duplicate_method.out | 6 ++++++ vlib/v/parser/tests/interface_duplicate_method.vv | 4 ++++ 8 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 vlib/v/checker/tests/no_interface_receiver_duplicate_a.out create mode 100644 vlib/v/checker/tests/no_interface_receiver_duplicate_a.vv create mode 100644 vlib/v/checker/tests/no_interface_receiver_duplicate_b.out create mode 100644 vlib/v/checker/tests/no_interface_receiver_duplicate_b.vv create mode 100644 vlib/v/parser/tests/interface_duplicate_method.out create mode 100644 vlib/v/parser/tests/interface_duplicate_method.vv diff --git a/vlib/v/checker/tests/no_interface_receiver_duplicate_a.out b/vlib/v/checker/tests/no_interface_receiver_duplicate_a.out new file mode 100644 index 0000000000..cac199162e --- /dev/null +++ b/vlib/v/checker/tests/no_interface_receiver_duplicate_a.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/no_interface_receiver_duplicate_a.v:5:5: error: interfaces cannot be used as method receiver + 3 | } + 4 | + 5 | fn (a Abc) fun() { + | ~~~~~ + 6 | } diff --git a/vlib/v/checker/tests/no_interface_receiver_duplicate_a.vv b/vlib/v/checker/tests/no_interface_receiver_duplicate_a.vv new file mode 100644 index 0000000000..0c28871b47 --- /dev/null +++ b/vlib/v/checker/tests/no_interface_receiver_duplicate_a.vv @@ -0,0 +1,6 @@ +interface Abc { + fun() +} + +fn (a Abc) fun() { +} diff --git a/vlib/v/checker/tests/no_interface_receiver_duplicate_b.out b/vlib/v/checker/tests/no_interface_receiver_duplicate_b.out new file mode 100644 index 0000000000..09a8738240 --- /dev/null +++ b/vlib/v/checker/tests/no_interface_receiver_duplicate_b.out @@ -0,0 +1,5 @@ +vlib/v/checker/tests/no_interface_receiver_duplicate_b.v:1:5: error: interfaces cannot be used as method receiver + 1 | fn (a Abc) fun() { + | ~~~~~ + 2 | } + 3 | diff --git a/vlib/v/checker/tests/no_interface_receiver_duplicate_b.vv b/vlib/v/checker/tests/no_interface_receiver_duplicate_b.vv new file mode 100644 index 0000000000..ff8e015c08 --- /dev/null +++ b/vlib/v/checker/tests/no_interface_receiver_duplicate_b.vv @@ -0,0 +1,6 @@ +fn (a Abc) fun() { +} + +interface Abc { + fun() +} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 7b66df8b11..040080db08 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -196,7 +196,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl { if language == .v && !p.pref.translated && util.contains_capital(name) { p.error('function names cannot contain uppercase letters, use snake_case instead') } - if is_method && p.table.get_type_symbol(rec_type).has_method(name) { + type_sym := p.table.get_type_symbol(rec_type) + // interfaces are handled in the checker, methods can not be defined on them this way + if is_method && (type_sym.has_method(name) && type_sym.kind != .interface_) { p.error('duplicate method `$name`') } } @@ -476,7 +478,8 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool, bool) { p.check_fn_mutable_arguments(typ, pos) } } else if is_shared || is_atomic { - p.error_with_pos('generic object cannot be `atomic` or `shared`', pos) + p.error_with_pos('generic object cannot be `atomic` or `shared`', + pos) } typ = typ.set_nr_muls(1) if is_shared { @@ -527,7 +530,8 @@ fn (mut p Parser) check_fn_mutable_arguments(typ table.Type, pos token.Position) fn (mut p Parser) check_fn_shared_arguments(typ table.Type, pos token.Position) { sym := p.table.get_type_symbol(typ) if sym.kind !in [.array, .struct_, .map, .placeholder] && !typ.is_ptr() { - p.error_with_pos('shared arguments are only allowed for arrays, maps, and structs\n', pos) + p.error_with_pos('shared arguments are only allowed for arrays, maps, and structs\n', + pos) } } diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index b2796e7266..89fb5f2cb3 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -359,12 +359,17 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl { } typ := table.new_type(reg_idx) ts := p.table.get_type_symbol(typ) + // if methods were declared before, it's an error, ignore them + ts.methods.clear() // Parse methods mut methods := []ast.FnDecl{} for p.tok.kind != .rcbr && p.tok.kind != .eof { method_start_pos := p.tok.position() line_nr := p.tok.line_nr name := p.check_name() + if ts.has_method(name) { + p.error_with_pos('duplicate method `$name`', method_start_pos) + } if util.contains_capital(name) { p.error('interface methods cannot contain uppercase letters, use snake_case instead') } diff --git a/vlib/v/parser/tests/interface_duplicate_method.out b/vlib/v/parser/tests/interface_duplicate_method.out new file mode 100644 index 0000000000..e15cd7b51c --- /dev/null +++ b/vlib/v/parser/tests/interface_duplicate_method.out @@ -0,0 +1,6 @@ +vlib/v/parser/tests/interface_duplicate_method.v:3:2: error: duplicate method `fun` + 1 | interface Abc { + 2 | fun() + 3 | fun() + | ~~~ + 4 | } diff --git a/vlib/v/parser/tests/interface_duplicate_method.vv b/vlib/v/parser/tests/interface_duplicate_method.vv new file mode 100644 index 0000000000..96fdc37143 --- /dev/null +++ b/vlib/v/parser/tests/interface_duplicate_method.vv @@ -0,0 +1,4 @@ +interface Abc { + fun() + fun() +}