Skip to content

Commit 52b627f

Browse files
checker: check filter, map and sort left type (#6952)
1 parent e03ae19 commit 52b627f

14 files changed

+67
-106
lines changed

vlib/builtin/string.v

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,34 +1490,6 @@ pub fn (s string) fields() []string {
14901490
return s.replace('\t', ' ').split(' ')
14911491
}
14921492

1493-
pub fn (s string) map(func fn(byte) byte) string {
1494-
unsafe {
1495-
mut res := malloc(s.len + 1)
1496-
for i in 0..s.len {
1497-
res[i] = func(s[i])
1498-
}
1499-
return tos(res, s.len)
1500-
}
1501-
}
1502-
1503-
pub fn (s string) filter(func fn(b byte) bool) string {
1504-
mut new_len := 0
1505-
mut buf := malloc(s.len + 1)
1506-
for i in 0 .. s.len {
1507-
mut b := s[i]
1508-
if func(b) {
1509-
unsafe {
1510-
buf[new_len] = b
1511-
}
1512-
new_len++
1513-
}
1514-
}
1515-
unsafe {
1516-
buf[new_len] = 0
1517-
return buf.vstring_with_len(new_len)
1518-
}
1519-
}
1520-
15211493
// Allows multi-line strings to be formatted in a way that removes white-space
15221494
// before a delimeter. by default `|` is used.
15231495
// Note: the delimiter has to be a byte at this time. That means surrounding

vlib/builtin/string_test.v

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -816,41 +816,10 @@ fn test_double_quote_inter() {
816816
assert '${a} ${b}' == "1 2"
817817
}
818818

819-
fn test_string_map() {
820-
$if windows {
821-
// TODO
822-
return
823-
}
824-
original := 'Hello'
825-
println('original.len = $original.len')
826-
a := original.map(fn (b byte) byte {
827-
return b + 1
828-
})
829-
expected := 'Ifmmp'
830-
println('a[0] = ' + a[0].str())
831-
println('a[1] = ' + a[1].str())
832-
println('a[2] = ' + a[2].str())
833-
println('a[3] = ' + a[3].str())
834-
println('a[4] = ' + a[4].str())
835-
println('a.len = $a.len')
836-
assert a.len == expected.len
837-
assert a == expected
838-
839-
assert 'foo'.map(foo) == r'\ee'
840-
}
841-
842819
fn foo(b byte) byte {
843820
return b - 10
844821
}
845822

846-
fn test_string_filter() {
847-
foo := 'V is awesome!!!!'.filter(fn (b byte) bool {
848-
return b != `!`
849-
})
850-
assert foo == 'V is awesome'
851-
assert 'Alexander'.filter(filter) == 'Alexnder'
852-
}
853-
854823
fn filter(b byte) bool {
855824
return b != `a`
856825
}

vlib/v/checker/checker.v

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,15 +1050,15 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ table.Type, call_e
10501050
match arg_expr {
10511051
ast.AnonFn {
10521052
if arg_expr.decl.params.len > 1 {
1053-
c.error('function needs exactly 1 argument', call_expr.pos)
1053+
c.error('function needs exactly 1 argument', arg_expr.decl.pos)
10541054
} else if is_map &&
10551055
(arg_expr.decl.return_type != elem_typ || arg_expr.decl.params[0].typ != elem_typ) {
10561056
c.error('type mismatch, should use `fn(a $elem_sym.source_name) $elem_sym.source_name {...}`',
1057-
call_expr.pos)
1057+
arg_expr.decl.pos)
10581058
} else if !is_map &&
10591059
(arg_expr.decl.return_type != table.bool_type || arg_expr.decl.params[0].typ != elem_typ) {
10601060
c.error('type mismatch, should use `fn(a $elem_sym.source_name) bool {...}`',
1061-
call_expr.pos)
1061+
arg_expr.decl.pos)
10621062
}
10631063
}
10641064
ast.Ident {
@@ -1071,11 +1071,11 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ table.Type, call_e
10711071
c.error('function needs exactly 1 argument', call_expr.pos)
10721072
} else if is_map && (func.return_type != elem_typ || func.params[0].typ != elem_typ) {
10731073
c.error('type mismatch, should use `fn(a $elem_sym.source_name) $elem_sym.source_name {...}`',
1074-
call_expr.pos)
1074+
arg_expr.pos)
10751075
} else if !is_map &&
10761076
(func.return_type != table.bool_type || func.params[0].typ != elem_typ) {
10771077
c.error('type mismatch, should use `fn(a $elem_sym.source_name) bool {...}`',
1078-
call_expr.pos)
1078+
arg_expr.pos)
10791079
}
10801080
}
10811081
}
@@ -1110,13 +1110,15 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
11101110
is_sort := method_name == 'sort'
11111111
if is_filter_map || is_sort {
11121112
array_info := left_type_sym.info as table.Array
1113-
mut scope := c.file.scope.innermost(call_expr.pos.pos)
1113+
args_pos := call_expr.pos.pos + call_expr.name.len
1114+
mut scope := c.file.scope.innermost(args_pos)
11141115
if is_filter_map {
1115-
scope.update_var_type('it', array_info.elem_type)
1116+
// position of `it` doesn't matter
1117+
scope_register_it(mut scope, call_expr.pos, array_info.elem_type)
11161118
} else if is_sort {
11171119
c.fail_if_immutable(call_expr.left)
1118-
scope.update_var_type('a', array_info.elem_type)
1119-
scope.update_var_type('b', array_info.elem_type)
1120+
// position of `a` and `b` doesn't matter, they're the same
1121+
scope_register_ab(mut scope, call_expr.pos, array_info.elem_type)
11201122
// Verify `.sort(a < b)`
11211123
if call_expr.args.len > 0 {
11221124
if call_expr.args[0].expr !is ast.InfixExpr {
@@ -2251,11 +2253,28 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
22512253
}
22522254
}
22532255

2254-
fn (mut c Checker) open_scope(mut parent ast.Scope, start_pos int) &ast.Scope {
2255-
mut s := ast.new_scope(parent, start_pos)
2256-
s.end_pos = parent.end_pos
2257-
parent.children << s
2258-
return s
2256+
fn scope_register_it(mut s ast.Scope, pos token.Position, typ table.Type) {
2257+
s.register('it', ast.Var{
2258+
name: 'it'
2259+
pos: pos
2260+
typ: typ
2261+
is_used: true
2262+
})
2263+
}
2264+
2265+
fn scope_register_ab(mut s ast.Scope, pos token.Position, typ table.Type) {
2266+
s.register('a', ast.Var{
2267+
name: 'a'
2268+
pos: pos
2269+
typ: typ
2270+
is_used: true
2271+
})
2272+
s.register('b', ast.Var{
2273+
name: 'b'
2274+
pos: pos
2275+
typ: typ
2276+
is_used: true
2277+
})
22592278
}
22602279

22612280
fn (mut c Checker) check_array_init_para_type(para string, expr ast.Expr, pos token.Position) {
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
vlib/v/checker/tests/array_filter_anon_fn_err_a.vv:2:23: error: function needs exactly 1 argument
1+
vlib/v/checker/tests/array_filter_anon_fn_err_a.vv:2:24: error: function needs exactly 1 argument
22
1 | fn main() {
33
2 | a := [1,2,3,4].filter(fn(a int, b int) bool { return a > 0 })
4-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4+
| ~~
55
3 | println(a)
6-
4 | }
6+
4 | }
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
vlib/v/checker/tests/array_filter_anon_fn_err_b.vv:2:23: error: type mismatch, should use `fn(a int) bool {...}`
1+
vlib/v/checker/tests/array_filter_anon_fn_err_b.vv:2:24: error: type mismatch, should use `fn(a int) bool {...}`
22
1 | fn main() {
33
2 | a := [1,2,3,4].filter(fn(a string) bool { return a.len > 0 })
4-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4+
| ~~
55
3 | println(a)
6-
4 | }
6+
4 | }
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
vlib/v/checker/tests/array_filter_fn_err_a.vv:5:23: error: function needs exactly 1 argument
1+
vlib/v/checker/tests/array_filter_fn_err_a.vv:5:17: error: function needs exactly 1 argument
22
3 | }
33
4 | fn main() {
44
5 | a := [1,2,3,4].filter(fil)
5-
| ~~~~~
5+
| ~~~~~~~~~~~
66
6 | println(a)
7-
7 | }
7+
7 | }
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
vlib/v/checker/tests/array_filter_fn_err_b.vv:5:23: error: type mismatch, should use `fn(a int) bool {...}`
1+
vlib/v/checker/tests/array_filter_fn_err_b.vv:5:24: error: type mismatch, should use `fn(a int) bool {...}`
22
3 | }
33
4 | fn main() {
44
5 | a := [1,2,3,4].filter(fil)
5-
| ~~~~~
5+
| ~~~
66
6 | println(a)
7-
7 | }
7+
7 | }
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
vlib/v/checker/tests/array_map_anon_fn_err_a.vv:2:20: error: function needs exactly 1 argument
1+
vlib/v/checker/tests/array_map_anon_fn_err_a.vv:2:21: error: function needs exactly 1 argument
22
1 | fn main() {
33
2 | a := [1,2,3,4].map(fn(a int, b int) int {return a + b})
4-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4+
| ~~
55
3 | println(a)
6-
4 | }
6+
4 | }
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
vlib/v/checker/tests/array_map_anon_fn_err_b.vv:2:20: error: type mismatch, should use `fn(a int) int {...}`
1+
vlib/v/checker/tests/array_map_anon_fn_err_b.vv:2:21: error: type mismatch, should use `fn(a int) int {...}`
22
1 | fn main() {
33
2 | a := [1,2,3,4].map(fn(a string) string { return a })
4-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4+
| ~~
55
3 | println(a)
6-
4 | }
6+
4 | }
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
vlib/v/checker/tests/array_map_fn_err_a.vv:5:20: error: function needs exactly 1 argument
1+
vlib/v/checker/tests/array_map_fn_err_a.vv:5:17: error: function needs exactly 1 argument
22
3 | }
33
4 | fn main() {
44
5 | a := [1,2,3,4].map(add)
5-
| ~~~~~
5+
| ~~~~~~~~
66
6 | println(a)
7-
7 | }
7+
7 | }

0 commit comments

Comments
 (0)