checker: extract into call_array_builtin_method to cleanup (#9225)
							parent
							
								
									ef73e07e62
								
							
						
					
					
						commit
						f280a5c230
					
				|  | @ -1315,89 +1315,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 checker.array_builtin_methods { | ||||
| 		mut elem_typ := table.void_type | ||||
| 		is_filter_map := method_name in ['filter', 'map'] | ||||
| 		is_sort := method_name == 'sort' | ||||
| 		is_slice := method_name == 'slice' | ||||
| 		is_wait := method_name == 'wait' | ||||
| 		if is_slice && !c.is_builtin_mod { | ||||
| 			c.error('.slice() is a private method, use `x[start..end]` instead', call_expr.pos) | ||||
| 		} | ||||
| 		if is_filter_map || is_sort || is_wait { | ||||
| 			array_info := left_type_sym.info as table.Array | ||||
| 			if is_filter_map { | ||||
| 				// position of `it` doesn't matter
 | ||||
| 				scope_register_it(mut call_expr.scope, call_expr.pos, array_info.elem_type) | ||||
| 			} else if is_sort { | ||||
| 				c.fail_if_immutable(call_expr.left) | ||||
| 				// position of `a` and `b` doesn't matter, they're the same
 | ||||
| 				scope_register_ab(mut call_expr.scope, call_expr.pos, array_info.elem_type) | ||||
| 
 | ||||
| 				if call_expr.args.len > 1 { | ||||
| 					c.error('expected 0 or 1 argument, but got $call_expr.args.len', call_expr.pos) | ||||
| 				} | ||||
| 				// Verify `.sort(a < b)`
 | ||||
| 				if call_expr.args.len > 0 { | ||||
| 					if call_expr.args[0].expr !is ast.InfixExpr { | ||||
| 						c.error( | ||||
| 							'`.sort()` requires a `<` or `>` comparison as the first and only argument' + | ||||
| 							'\ne.g. `users.sort(a.id < b.id)`', call_expr.pos) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			elem_typ = array_info.elem_type | ||||
| 			if is_wait { | ||||
| 				elem_sym := c.table.get_type_symbol(elem_typ) | ||||
| 				if elem_sym.kind == .thread { | ||||
| 					if call_expr.args.len != 0 { | ||||
| 						c.error('`.wait()` does not have any arguments', call_expr.args[0].pos) | ||||
| 					} | ||||
| 					thread_ret_type := elem_sym.thread_info().return_type | ||||
| 					if thread_ret_type.has_flag(.optional) { | ||||
| 						c.error('`.wait()` cannot be called for an array when thread functions return optionals. Iterate over the arrays elements instead and handle each returned optional with `or`.', | ||||
| 							call_expr.pos) | ||||
| 					} | ||||
| 					call_expr.return_type = c.table.find_or_register_array(thread_ret_type) | ||||
| 				} else { | ||||
| 					c.error('`$left_type_sym.name` has no method `wait()` (only thread handles and arrays of them have)', | ||||
| 						call_expr.left.position()) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		// map/filter are supposed to have 1 arg only
 | ||||
| 		mut arg_type := left_type | ||||
| 		for arg in call_expr.args { | ||||
| 			arg_type = c.expr(arg.expr) | ||||
| 		} | ||||
| 		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) | ||||
| 			ret_type := match arg_sym.info { | ||||
| 				table.FnType { arg_sym.info.func.return_type } | ||||
| 				else { arg_type } | ||||
| 			} | ||||
| 			call_expr.return_type = c.table.find_or_register_array(ret_type) | ||||
| 		} 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'] {
 | ||||
| 			call_expr.receiver_type = left_type.to_ptr() | ||||
| 			if call_expr.left.is_auto_deref_var() { | ||||
| 				call_expr.return_type = left_type.deref() | ||||
| 			} else { | ||||
| 				call_expr.return_type = call_expr.receiver_type.set_nr_muls(0) | ||||
| 			} | ||||
| 		} else if method_name == 'sort' { | ||||
| 			call_expr.return_type = table.void_type | ||||
| 		} else if method_name == 'contains' { | ||||
| 			call_expr.return_type = table.bool_type | ||||
| 		} else if method_name == 'index' { | ||||
| 			call_expr.return_type = table.int_type | ||||
| 		} | ||||
| 		return call_expr.return_type | ||||
| 		return c.call_array_builtin_method(mut call_expr, left_type, left_type_sym) | ||||
| 	} else if left_type_sym.kind == .map && method_name in ['clone', 'keys', 'move'] { | ||||
| 		mut ret_type := table.void_type | ||||
| 		match method_name { | ||||
|  | @ -1696,6 +1614,93 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { | |||
| 	return table.void_type | ||||
| } | ||||
| 
 | ||||
| fn (mut c Checker) call_array_builtin_method(mut call_expr ast.CallExpr, left_type table.Type, left_type_sym table.TypeSymbol) table.Type { | ||||
| 	method_name := call_expr.name | ||||
| 	mut elem_typ := table.void_type | ||||
| 	is_filter_map := method_name in ['filter', 'map'] | ||||
| 	is_sort := method_name == 'sort' | ||||
| 	is_slice := method_name == 'slice' | ||||
| 	is_wait := method_name == 'wait' | ||||
| 	if is_slice && !c.is_builtin_mod { | ||||
| 		c.error('.slice() is a private method, use `x[start..end]` instead', call_expr.pos) | ||||
| 	} | ||||
| 	if is_filter_map || is_sort || is_wait { | ||||
| 		array_info := left_type_sym.info as table.Array | ||||
| 		if is_filter_map { | ||||
| 			// position of `it` doesn't matter
 | ||||
| 			scope_register_it(mut call_expr.scope, call_expr.pos, array_info.elem_type) | ||||
| 		} else if is_sort { | ||||
| 			c.fail_if_immutable(call_expr.left) | ||||
| 			// position of `a` and `b` doesn't matter, they're the same
 | ||||
| 			scope_register_ab(mut call_expr.scope, call_expr.pos, array_info.elem_type) | ||||
| 
 | ||||
| 			if call_expr.args.len > 1 { | ||||
| 				c.error('expected 0 or 1 argument, but got $call_expr.args.len', call_expr.pos) | ||||
| 			} | ||||
| 			// Verify `.sort(a < b)`
 | ||||
| 			if call_expr.args.len > 0 { | ||||
| 				if call_expr.args[0].expr !is ast.InfixExpr { | ||||
| 					c.error( | ||||
| 						'`.sort()` requires a `<` or `>` comparison as the first and only argument' + | ||||
| 						'\ne.g. `users.sort(a.id < b.id)`', call_expr.pos) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		elem_typ = array_info.elem_type | ||||
| 		if is_wait { | ||||
| 			elem_sym := c.table.get_type_symbol(elem_typ) | ||||
| 			if elem_sym.kind == .thread { | ||||
| 				if call_expr.args.len != 0 { | ||||
| 					c.error('`.wait()` does not have any arguments', call_expr.args[0].pos) | ||||
| 				} | ||||
| 				thread_ret_type := elem_sym.thread_info().return_type | ||||
| 				if thread_ret_type.has_flag(.optional) { | ||||
| 					c.error('`.wait()` cannot be called for an array when thread functions return optionals. Iterate over the arrays elements instead and handle each returned optional with `or`.', | ||||
| 						call_expr.pos) | ||||
| 				} | ||||
| 				call_expr.return_type = c.table.find_or_register_array(thread_ret_type) | ||||
| 			} else { | ||||
| 				c.error('`$left_type_sym.name` has no method `wait()` (only thread handles and arrays of them have)', | ||||
| 					call_expr.left.position()) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// map/filter are supposed to have 1 arg only
 | ||||
| 	mut arg_type := left_type | ||||
| 	for arg in call_expr.args { | ||||
| 		arg_type = c.expr(arg.expr) | ||||
| 	} | ||||
| 	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) | ||||
| 		ret_type := match arg_sym.info { | ||||
| 			table.FnType { arg_sym.info.func.return_type } | ||||
| 			else { arg_type } | ||||
| 		} | ||||
| 		call_expr.return_type = c.table.find_or_register_array(ret_type) | ||||
| 	} 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'] {
 | ||||
| 		call_expr.receiver_type = left_type.to_ptr() | ||||
| 		if call_expr.left.is_auto_deref_var() { | ||||
| 			call_expr.return_type = left_type.deref() | ||||
| 		} else { | ||||
| 			call_expr.return_type = call_expr.receiver_type.set_nr_muls(0) | ||||
| 		} | ||||
| 	} else if method_name == 'sort' { | ||||
| 		call_expr.return_type = table.void_type | ||||
| 	} else if method_name == 'contains' { | ||||
| 		call_expr.return_type = table.bool_type | ||||
| 	} else if method_name == 'index' { | ||||
| 		call_expr.return_type = table.int_type | ||||
| 	} | ||||
| 	return call_expr.return_type | ||||
| } | ||||
| 
 | ||||
| pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { | ||||
| 	fn_name := call_expr.name | ||||
| 	if fn_name == 'main' { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue