checker: check array.map/filter fn or anon_fn
							parent
							
								
									8f3f27f286
								
							
						
					
					
						commit
						a66753871d
					
				|  | @ -754,6 +754,37 @@ pub fn (mut c Checker) call_expr(mut call_expr ast.CallExpr) table.Type { | |||
| 	return c.call_fn(call_expr) | ||||
| } | ||||
| 
 | ||||
| fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ table.Type, call_expr ast.CallExpr) { | ||||
| 	elem_sym := c.table.get_type_symbol(elem_typ) | ||||
| 	match call_expr.args[0].expr { | ||||
| 		ast.AnonFn { | ||||
| 			if it.decl.args.len > 1 { | ||||
| 				c.error('function needs exactly 1 argument', call_expr.pos) | ||||
| 			} else if is_map && (it.decl.return_type != elem_typ || it.decl.args[0].typ != elem_typ) { | ||||
| 				c.error('type mismatch, should use `fn(a $elem_sym.name) $elem_sym.name {...}`', call_expr.pos) | ||||
| 			} else if !is_map && (it.decl.return_type != table.bool_type || it.decl.args[0].typ != elem_typ) { | ||||
| 				c.error('type mismatch, should use `fn(a $elem_sym.name) bool {...}`', call_expr.pos) | ||||
| 			} | ||||
| 		} | ||||
| 		ast.Ident { | ||||
| 			if it.kind == .function { | ||||
| 				func := c.table.find_fn(it.name) or { | ||||
| 					c.error('$it.name is not exist', it.pos) | ||||
| 					return | ||||
| 				} | ||||
| 				if func.args.len > 1 { | ||||
| 					c.error('function needs exactly 1 argument', call_expr.pos) | ||||
| 				} else if is_map && (func.return_type != elem_typ || func.args[0].typ != elem_typ) { | ||||
| 					c.error('type mismatch, should use `fn(a $elem_sym.name) $elem_sym.name {...}`', call_expr.pos) | ||||
| 				} else if !is_map && (func.return_type != table.bool_type || func.args[0].typ != elem_typ) { | ||||
| 					c.error('type mismatch, should use `fn(a $elem_sym.name) bool {...}`', call_expr.pos) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else {} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { | ||||
| 	left_type := c.expr(call_expr.left) | ||||
| 	is_generic := left_type == table.t_type | ||||
|  | @ -764,10 +795,12 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { | |||
| 	// FIXME: Argument count != 1 will break these
 | ||||
| 	if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse', | ||||
| 		'map', 'slice'] { | ||||
| 		mut elem_typ := table.void_type | ||||
| 		if method_name in ['filter', 'map'] { | ||||
| 			array_info := left_type_sym.info as table.Array | ||||
| 			mut scope := c.file.scope.innermost(call_expr.pos.pos) | ||||
| 			scope.update_var_type('it', array_info.elem_type) | ||||
| 			elem_typ = array_info.elem_type | ||||
| 		} | ||||
| 		// map/filter are supposed to have 1 arg only
 | ||||
| 		mut arg_type := left_type | ||||
|  | @ -777,6 +810,8 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { | |||
| 		call_expr.return_type = left_type | ||||
| 		call_expr.receiver_type = left_type | ||||
| 		if method_name == 'map' { | ||||
| 			// check fn
 | ||||
| 			c.check_map_and_filter(true, elem_typ, call_expr) | ||||
| 			arg_sym := c.table.get_type_symbol(arg_type) | ||||
| 			// FIXME: match expr failed for now
 | ||||
| 			mut ret_type := 0 | ||||
|  | @ -785,6 +820,9 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { | |||
| 				else { ret_type = arg_type } | ||||
| 			} | ||||
| 			call_expr.return_type = c.table.find_or_register_array(ret_type, 1, c.mod) | ||||
| 		} else if method_name == 'filter' { | ||||
| 			// check fn
 | ||||
| 			c.check_map_and_filter(false, elem_typ, call_expr) | ||||
| 		} else if method_name == 'clone' { | ||||
| 			// need to return `array_xxx` instead of `array`
 | ||||
| 			// in ['clone', 'str'] {
 | ||||
|  |  | |||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/array_filter_anon_fn_err_a.v:2:23: error: function needs exactly 1 argument | ||||
|     1 | fn main() { | ||||
|     2 |     a := [1,2,3,4].filter(fn(a int, b int) bool { return a > 0 }) | ||||
|       |                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|     3 |     println(a) | ||||
|     4 | } | ||||
|  | @ -0,0 +1,4 @@ | |||
| fn main() { | ||||
| 	a := [1,2,3,4].filter(fn(a int, b int) bool { return a > 0 }) | ||||
| 	println(a) | ||||
| } | ||||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/array_filter_anon_fn_err_b.v:2:23: error: type mismatch, should use `fn(a int) bool {...}` | ||||
|     1 | fn main() { | ||||
|     2 |     a := [1,2,3,4].filter(fn(a string) bool { return a.len > 0 }) | ||||
|       |                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|     3 |     println(a) | ||||
|     4 | } | ||||
|  | @ -0,0 +1,4 @@ | |||
| fn main() { | ||||
| 	a := [1,2,3,4].filter(fn(a string) bool { return a.len > 0 }) | ||||
| 	println(a) | ||||
| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| vlib/v/checker/tests/array_filter_fn_err_a.v:5:23: error: function needs exactly 1 argument | ||||
|     3 | } | ||||
|     4 | fn main() { | ||||
|     5 |     a := [1,2,3,4].filter(fil) | ||||
|       |                          ~~~~~ | ||||
|     6 |     println(a) | ||||
|     7 | } | ||||
|  | @ -0,0 +1,7 @@ | |||
| fn fil(a int, b int) bool { | ||||
| 	return a > 0 | ||||
| } | ||||
| fn main() { | ||||
| 	a := [1,2,3,4].filter(fil) | ||||
| 	println(a) | ||||
| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| vlib/v/checker/tests/array_filter_fn_err_b.v:5:23: error: type mismatch, should use `fn(a int) bool {...}` | ||||
|     3 | } | ||||
|     4 | fn main() { | ||||
|     5 |     a := [1,2,3,4].filter(fil) | ||||
|       |                          ~~~~~ | ||||
|     6 |     println(a) | ||||
|     7 | } | ||||
|  | @ -0,0 +1,7 @@ | |||
| fn fil(a string) bool { | ||||
| 	return a.len > 0 | ||||
| } | ||||
| fn main() { | ||||
| 	a := [1,2,3,4].filter(fil) | ||||
| 	println(a) | ||||
| } | ||||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/array_map_anon_fn_err_a.v:2:20: error: function needs exactly 1 argument | ||||
|     1 | fn main() { | ||||
|     2 |     a := [1,2,3,4].map(fn(a int, b int) int {return a + b}) | ||||
|       |                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|     3 |     println(a) | ||||
|     4 | } | ||||
|  | @ -0,0 +1,4 @@ | |||
| fn main() { | ||||
| 	a := [1,2,3,4].map(fn(a int, b int) int {return a + b}) | ||||
| 	println(a) | ||||
| } | ||||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/array_map_anon_fn_err_b.v:2:20: error: type mismatch, should use `fn(a int) int {...}` | ||||
|     1 | fn main() { | ||||
|     2 |     a := [1,2,3,4].map(fn(a string) string { return a }) | ||||
|       |                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|     3 |     println(a) | ||||
|     4 | } | ||||
|  | @ -0,0 +1,4 @@ | |||
| fn main() { | ||||
| 	a := [1,2,3,4].map(fn(a string) string { return a }) | ||||
| 	println(a) | ||||
| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| vlib/v/checker/tests/array_map_fn_err_a.v:5:20: error: function needs exactly 1 argument | ||||
|     3 | } | ||||
|     4 | fn main() { | ||||
|     5 |     a := [1,2,3,4].map(add) | ||||
|       |                       ~~~~~ | ||||
|     6 |     println(a) | ||||
|     7 | } | ||||
|  | @ -0,0 +1,7 @@ | |||
| fn add(a int, b int) int { | ||||
| 	return a + b | ||||
| } | ||||
| fn main() { | ||||
| 	a := [1,2,3,4].map(add) | ||||
| 	println(a) | ||||
| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| vlib/v/checker/tests/array_map_fn_err_b.v:5:20: error: type mismatch, should use `fn(a int) int {...}` | ||||
|     3 | } | ||||
|     4 | fn main() { | ||||
|     5 |     a := [1,2,3,4].map(add) | ||||
|       |                       ~~~~~ | ||||
|     6 |     println(a) | ||||
|     7 | } | ||||
|  | @ -0,0 +1,7 @@ | |||
| fn add(a string) string { | ||||
| 	return a | ||||
| } | ||||
| fn main() { | ||||
| 	a := [1,2,3,4].map(add) | ||||
| 	println(a) | ||||
| } | ||||
		Loading…
	
		Reference in New Issue