From 9332f7cac28337b911b3a06a84220f16cf37ead3 Mon Sep 17 00:00:00 2001 From: Enzo Date: Sun, 3 Jan 2021 16:57:29 +0100 Subject: [PATCH] checker: allow `map` method name (#7834) --- vlib/v/checker/checker.v | 15 +++++--- .../tests/array_builtin_redefinition.out | 7 ++++ .../tests/array_builtin_redefinition.vv | 11 ++++++ .../checker/tests/array_map_arg_mismatch.out | 13 +++++++ .../v/checker/tests/array_map_arg_mismatch.vv | 5 +++ vlib/v/parser/parser.v | 8 +---- vlib/v/tests/struct_map_method_test.v | 35 +++++++++++++++++++ 7 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 vlib/v/checker/tests/array_builtin_redefinition.out create mode 100644 vlib/v/checker/tests/array_builtin_redefinition.vv create mode 100644 vlib/v/checker/tests/array_map_arg_mismatch.out create mode 100644 vlib/v/checker/tests/array_map_arg_mismatch.vv create mode 100644 vlib/v/tests/struct_map_method_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 0df7475c83..a805d88d75 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -26,6 +26,7 @@ const ( valid_comp_if_compilers = ['gcc', 'tinyc', 'clang', 'mingw', 'msvc', 'cplusplus'] valid_comp_if_platforms = ['amd64', 'aarch64', 'x64', 'x32', 'little_endian', 'big_endian'] valid_comp_if_other = ['js', 'debug', 'test', 'glibc', 'prealloc', 'no_bounds_checking'] + array_builtin_methods = ['filter', 'clone', 'repeat', 'reverse', 'map', 'slice', 'sort', 'contains', 'index'] ) pub struct Checker { @@ -1131,6 +1132,11 @@ pub fn (mut c Checker) call_expr(mut call_expr ast.CallExpr) table.Type { } fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ table.Type, call_expr ast.CallExpr) { + if call_expr.args.len != 1 { + c.error('expected 1 arguments, but got $call_expr.args.len', call_expr.pos) + // Finish early so that it doesn't fail later + return + } elem_sym := c.table.get_type_symbol(elem_typ) arg_expr := call_expr.args[0].expr match arg_expr { @@ -1200,8 +1206,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { // TODO: remove this for actual methods, use only for compiler magic // FIXME: Argument count != 1 will break these if left_type_sym.kind == .array && - method_name in - ['filter', 'clone', 'repeat', 'reverse', 'map', 'slice', 'sort', 'contains', 'index'] { + method_name in array_builtin_methods { mut elem_typ := table.void_type is_filter_map := method_name in ['filter', 'map'] is_sort := method_name == 'sort' @@ -4947,8 +4952,10 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { mut sym := c.table.get_type_symbol(node.receiver.typ) if sym.kind == .interface_ { c.error('interfaces cannot be used as method receiver', node.receiver_pos) - } - if sym.kind == .sum_type && node.name == 'type_name' { + } else if sym.kind == .array && !c.is_builtin_mod && node.name == 'map' { + // TODO `node.map in array_builtin_methods` + c.error('method overrides built-in array method', node.pos) + } else if sym.kind == .sum_type && node.name == 'type_name' { c.error('method overrides built-in sum type method', node.pos) } // if sym.has_method(node.name) { diff --git a/vlib/v/checker/tests/array_builtin_redefinition.out b/vlib/v/checker/tests/array_builtin_redefinition.out new file mode 100644 index 0000000000..da5c05da1d --- /dev/null +++ b/vlib/v/checker/tests/array_builtin_redefinition.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/array_builtin_redefinition.vv:7:1: error: method overrides built-in array method + 5 | // fn (a []Abc) repeat() int { return 0 } + 6 | // fn (a []Abc) reverse() int { return 0 } + 7 | fn (a []Abc) map() int { return 0 } + | ~~~~~~~~~~~~~~~~~~~~~~ + 8 | // fn (a []Abc) slice() int { return 0 } + 9 | // fn (a []Abc) sort() int { return 0 } diff --git a/vlib/v/checker/tests/array_builtin_redefinition.vv b/vlib/v/checker/tests/array_builtin_redefinition.vv new file mode 100644 index 0000000000..809b86a5f8 --- /dev/null +++ b/vlib/v/checker/tests/array_builtin_redefinition.vv @@ -0,0 +1,11 @@ +type Abc = int + +// fn (a []Abc) filter() int { return 0 } +// fn (a []Abc) clone() int { return 0 } +// fn (a []Abc) repeat() int { return 0 } +// fn (a []Abc) reverse() int { return 0 } +fn (a []Abc) map() int { return 0 } +// fn (a []Abc) slice() int { return 0 } +// fn (a []Abc) sort() int { return 0 } +// fn (a []Abc) contains() int { return 0 } +// fn (a []Abc) index() int { return 0 } diff --git a/vlib/v/checker/tests/array_map_arg_mismatch.out b/vlib/v/checker/tests/array_map_arg_mismatch.out new file mode 100644 index 0000000000..ca77c7b2fa --- /dev/null +++ b/vlib/v/checker/tests/array_map_arg_mismatch.out @@ -0,0 +1,13 @@ +vlib/v/checker/tests/array_map_arg_mismatch.vv:3:4: error: expected 1 arguments, but got 0 + 1 | fn main() { + 2 | a := [1, 2, 3] + 3 | a.map() + | ~~~~~ + 4 | a.map(it * 2, 3) + 5 | } +vlib/v/checker/tests/array_map_arg_mismatch.vv:4:4: error: expected 1 arguments, but got 2 + 2 | a := [1, 2, 3] + 3 | a.map() + 4 | a.map(it * 2, 3) + | ~~~~~~~~~~~~~~ + 5 | } diff --git a/vlib/v/checker/tests/array_map_arg_mismatch.vv b/vlib/v/checker/tests/array_map_arg_mismatch.vv new file mode 100644 index 0000000000..629707b4ad --- /dev/null +++ b/vlib/v/checker/tests/array_map_arg_mismatch.vv @@ -0,0 +1,5 @@ +fn main() { + a := [1, 2, 3] + a.map() + a.map(it * 2, 3) +} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index d73d901c2c..fa4c0ae4fb 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1416,9 +1416,7 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr { p.name_error = true } is_filter := field_name in ['filter', 'map'] - if is_filter { - p.open_scope() - } else if field_name == 'sort' { + if is_filter || field_name == 'sort' { p.open_scope() } // ! in mutable methods @@ -1444,10 +1442,6 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr { if p.tok.kind == .lpar { p.next() args := p.call_args() - if is_filter && args.len != 1 { - p.error('needs exactly 1 argument') - return ast.Expr{} - } p.check(.rpar) mut or_stmts := []ast.Stmt{} mut or_kind := ast.OrKind.absent diff --git a/vlib/v/tests/struct_map_method_test.v b/vlib/v/tests/struct_map_method_test.v new file mode 100644 index 0000000000..0dd6524d2d --- /dev/null +++ b/vlib/v/tests/struct_map_method_test.v @@ -0,0 +1,35 @@ +type Foo = int + +fn (a Foo) map(add int) string { + return (a + add).str() +} + +fn test_map_one_arg() { + a := Foo(0) + assert a.map(1) == '1' + assert Foo(3).map(3) == '6' +} + +type Bar = int + +fn (b Bar) map() int { + return b + 1 +} + +fn test_map_no_arg() { + b := Bar(0) + assert b.map() == 1 + assert Bar(1).map() == 2 +} + +type Baz = int + +fn (b Baz) map(a int, c int) int { + return b + (a - c) +} + +fn test_map_more_args() { + b := Baz(0) + assert b.map(5, 2) == 3 + assert Baz(3).map(2, 5) == 0 +}