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_compilers = ['gcc', 'tinyc', 'clang', 'mingw', 'msvc', 'cplusplus']
|
||||||
valid_comp_if_platforms = ['amd64', 'aarch64', 'x64', 'x32', 'little_endian', 'big_endian']
|
valid_comp_if_platforms = ['amd64', 'aarch64', 'x64', 'x32', 'little_endian', 'big_endian']
|
||||||
valid_comp_if_other = ['js', 'debug', 'test', 'glibc', 'prealloc', 'no_bounds_checking']
|
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 {
|
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) {
|
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)
|
elem_sym := c.table.get_type_symbol(elem_typ)
|
||||||
arg_expr := call_expr.args[0].expr
|
arg_expr := call_expr.args[0].expr
|
||||||
match arg_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
|
// TODO: remove this for actual methods, use only for compiler magic
|
||||||
// FIXME: Argument count != 1 will break these
|
// FIXME: Argument count != 1 will break these
|
||||||
if left_type_sym.kind == .array &&
|
if left_type_sym.kind == .array &&
|
||||||
method_name in
|
method_name in array_builtin_methods {
|
||||||
['filter', 'clone', 'repeat', 'reverse', 'map', 'slice', 'sort', 'contains', 'index'] {
|
|
||||||
mut elem_typ := table.void_type
|
mut elem_typ := table.void_type
|
||||||
is_filter_map := method_name in ['filter', 'map']
|
is_filter_map := method_name in ['filter', 'map']
|
||||||
is_sort := method_name == 'sort'
|
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)
|
mut sym := c.table.get_type_symbol(node.receiver.typ)
|
||||||
if sym.kind == .interface_ {
|
if sym.kind == .interface_ {
|
||||||
c.error('interfaces cannot be used as method receiver', node.receiver_pos)
|
c.error('interfaces cannot be used as method receiver', node.receiver_pos)
|
||||||
}
|
} else if sym.kind == .array && !c.is_builtin_mod && node.name == 'map' {
|
||||||
if sym.kind == .sum_type && node.name == 'type_name' {
|
// 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)
|
c.error('method overrides built-in sum type method', node.pos)
|
||||||
}
|
}
|
||||||
// if sym.has_method(node.name) {
|
// 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
|
p.name_error = true
|
||||||
}
|
}
|
||||||
is_filter := field_name in ['filter', 'map']
|
is_filter := field_name in ['filter', 'map']
|
||||||
if is_filter {
|
if is_filter || field_name == 'sort' {
|
||||||
p.open_scope()
|
|
||||||
} else if field_name == 'sort' {
|
|
||||||
p.open_scope()
|
p.open_scope()
|
||||||
}
|
}
|
||||||
// ! in mutable methods
|
// ! in mutable methods
|
||||||
|
@ -1444,10 +1442,6 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
||||||
if p.tok.kind == .lpar {
|
if p.tok.kind == .lpar {
|
||||||
p.next()
|
p.next()
|
||||||
args := p.call_args()
|
args := p.call_args()
|
||||||
if is_filter && args.len != 1 {
|
|
||||||
p.error('needs exactly 1 argument')
|
|
||||||
return ast.Expr{}
|
|
||||||
}
|
|
||||||
p.check(.rpar)
|
p.check(.rpar)
|
||||||
mut or_stmts := []ast.Stmt{}
|
mut or_stmts := []ast.Stmt{}
|
||||||
mut or_kind := ast.OrKind.absent
|
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