checker: allow `map` method name (#7834)
parent
86df5cd1a9
commit
9332f7cac2
|
@ -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) {
|
||||
|
|
|
@ -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 }
|
|
@ -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 }
|
|
@ -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 | }
|
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
a := [1, 2, 3]
|
||||
a.map()
|
||||
a.map(it * 2, 3)
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue