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