From b487c9d38ed276f2e750383592b5bf73a4deed03 Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Tue, 31 Jan 2023 13:06:33 +0530 Subject: [PATCH] parser: add more precise errors, for `fn (p Point) += (q Point) Point {` (#17167) --- vlib/v/parser/fn.v | 18 ++++++++++--- .../argumented_op_overloading_fn_decl_err.out | 7 ++++++ .../argumented_op_overloading_fn_decl_err.vv | 21 ++++++++++++++++ ..._overloading_fn_op_overloaded_decl_err.out | 7 ++++++ ...p_overloading_fn_op_overloaded_decl_err.vv | 25 +++++++++++++++++++ 5 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 vlib/v/parser/tests/argumented_op_overloading_fn_decl_err.out create mode 100644 vlib/v/parser/tests/argumented_op_overloading_fn_decl_err.vv create mode 100644 vlib/v/parser/tests/argumented_op_overloading_fn_op_overloaded_decl_err.out create mode 100644 vlib/v/parser/tests/argumented_op_overloading_fn_op_overloaded_decl_err.vv diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index aa149b486..2f86e393b 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -280,6 +280,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { p.fn_language = language } mut name := '' + mut type_sym := p.table.sym(rec.typ) name_pos := p.tok.pos() if p.tok.kind == .name { // TODO high order fn @@ -292,12 +293,11 @@ fn (mut p Parser) fn_decl() ast.FnDecl { scope: 0 } } - type_sym := p.table.sym(rec.typ) if is_method { mut is_duplicate := type_sym.has_method(name) // make sure this is a normal method and not an interface method if type_sym.kind == .interface_ && is_duplicate { - if type_sym.info is ast.Interface { + if mut type_sym.info is ast.Interface { // if the method is in info then its an interface method is_duplicate = !type_sym.info.has_method(name) } @@ -327,6 +327,19 @@ fn (mut p Parser) fn_decl() ast.FnDecl { } else if p.tok.kind in [.ne, .gt, .ge, .le] && p.peek_tok.kind == .lpar { p.error_with_pos('cannot overload `!=`, `>`, `<=` and `>=` as they are auto generated from `==` and`<`', p.tok.pos()) + } else if p.tok.kind in [.plus_assign, .minus_assign, .div_assign, .mult_assign, .mod_assign] { + extracted_op := match p.tok.kind { + .plus_assign { '+' } + .minus_assign { '-' } + .div_assign { '/' } + .mod_assign { '%' } + .mult_assign { '*' } + else { 'unknown op' } + } + if type_sym.has_method(extracted_op) { + p.error('cannot overload `${p.tok.kind}`, operator is implicitly overloaded because the `${extracted_op}` operator is overloaded') + } + p.error('cannot overload `${p.tok.kind}`, overload `${extracted_op}` and `${p.tok.kind}` will be automatically generated') } else { p.error_with_pos('expecting method name', p.tok.pos()) return ast.FnDecl{ @@ -412,7 +425,6 @@ run them via `v file.v` instead', } // Register if is_method { - mut type_sym := p.table.sym(rec.typ) // Do not allow to modify / add methods to types from other modules // arrays/maps dont belong to a module only their element types do // we could also check if kind is .array, .array_fixed, .map instead of mod.len diff --git a/vlib/v/parser/tests/argumented_op_overloading_fn_decl_err.out b/vlib/v/parser/tests/argumented_op_overloading_fn_decl_err.out new file mode 100644 index 000000000..d4caecbec --- /dev/null +++ b/vlib/v/parser/tests/argumented_op_overloading_fn_decl_err.out @@ -0,0 +1,7 @@ +vlib/v/parser/tests/argumented_op_overloading_fn_decl_err.vv:10:14: error: cannot overload `+=`, overload `+` and `+=` will be automatically generated + 8 | } + 9 | + 10 | fn (p Point) += (q Point) Point { + | ~~ + 11 | return Point{p.x + q.x, p.y + q.y} + 12 | } diff --git a/vlib/v/parser/tests/argumented_op_overloading_fn_decl_err.vv b/vlib/v/parser/tests/argumented_op_overloading_fn_decl_err.vv new file mode 100644 index 000000000..141c3cfcd --- /dev/null +++ b/vlib/v/parser/tests/argumented_op_overloading_fn_decl_err.vv @@ -0,0 +1,21 @@ +struct Point { + x i64 + y i64 +} + +fn (p Point) foo() { + println(p.x) +} + +fn (p Point) += (q Point) Point { + return Point{p.x + q.x, p.y + q.y} +} + +fn main() { + mut p := Point{1, 2} + q := Point{3, 4} + p += q + p -= q + println(p) +} + diff --git a/vlib/v/parser/tests/argumented_op_overloading_fn_op_overloaded_decl_err.out b/vlib/v/parser/tests/argumented_op_overloading_fn_op_overloaded_decl_err.out new file mode 100644 index 000000000..e0b9029a8 --- /dev/null +++ b/vlib/v/parser/tests/argumented_op_overloading_fn_op_overloaded_decl_err.out @@ -0,0 +1,7 @@ +vlib/v/parser/tests/argumented_op_overloading_fn_op_overloaded_decl_err.vv:14:14: error: cannot overload `+=`, operator is implicitly overloaded because the `+` operator is overloaded + 12 | } + 13 | + 14 | fn (p Point) += (q Point) Point { + | ~~ + 15 | return Point{p.x + q.x, p.y + q.y} + 16 | } diff --git a/vlib/v/parser/tests/argumented_op_overloading_fn_op_overloaded_decl_err.vv b/vlib/v/parser/tests/argumented_op_overloading_fn_op_overloaded_decl_err.vv new file mode 100644 index 000000000..a7848c822 --- /dev/null +++ b/vlib/v/parser/tests/argumented_op_overloading_fn_op_overloaded_decl_err.vv @@ -0,0 +1,25 @@ +struct Point { + x i64 + y i64 +} + +fn (p Point) foo() { + println(p.x) +} + +fn (p Point) + (q Point) Point { + return Point{p.x + q.x, p.y + q.y} +} + +fn (p Point) += (q Point) Point { + return Point{p.x + q.x, p.y + q.y} +} + +fn main() { + mut p := Point{1, 2} + q := Point{3, 4} + p += q + p -= q + println(p) +} + -- 2.30.2