checker: minor cleanup in fn_call (#9681)

pull/9700/head
yuyi 2021-04-12 05:57:00 +08:00 committed by GitHub
parent 5a1a1b7c12
commit b0b3c51658
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 54 additions and 49 deletions

View File

@ -1968,7 +1968,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
return ret_type return ret_type
} }
// look for function in format `mod.fn` or `fn` (builtin) // look for function in format `mod.fn` or `fn` (builtin)
mut f := ast.Fn{} mut func := ast.Fn{}
mut found := false mut found := false
mut found_in_args := false mut found_in_args := false
// anon fn direct call // anon fn direct call
@ -1977,16 +1977,16 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
call_expr.name = '' call_expr.name = ''
c.expr(call_expr.left) c.expr(call_expr.left)
anon_fn_sym := c.table.get_type_symbol(call_expr.left.typ) anon_fn_sym := c.table.get_type_symbol(call_expr.left.typ)
f = (anon_fn_sym.info as ast.FnType).func func = (anon_fn_sym.info as ast.FnType).func
found = true found = true
} }
// try prefix with current module as it would have never gotten prefixed // try prefix with current module as it would have never gotten prefixed
if !found && !fn_name.contains('.') && call_expr.mod != 'builtin' { if !found && !fn_name.contains('.') && call_expr.mod != 'builtin' {
name_prefixed := '${call_expr.mod}.$fn_name' name_prefixed := '${call_expr.mod}.$fn_name'
if f1 := c.table.find_fn(name_prefixed) { if f := c.table.find_fn(name_prefixed) {
call_expr.name = name_prefixed call_expr.name = name_prefixed
found = true found = true
f = f1 func = f
c.table.fns[name_prefixed].usages++ c.table.fns[name_prefixed].usages++
} }
} }
@ -2018,21 +2018,21 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
} }
// already prefixed (mod.fn) or C/builtin/main // already prefixed (mod.fn) or C/builtin/main
if !found { if !found {
if f1 := c.table.find_fn(fn_name) { if f := c.table.find_fn(fn_name) {
found = true found = true
f = f1 func = f
c.table.fns[fn_name].usages++ c.table.fns[fn_name].usages++
} }
} }
if c.pref.is_script && !found { if c.pref.is_script && !found {
os_name := 'os.$fn_name' os_name := 'os.$fn_name'
if f1 := c.table.find_fn(os_name) { if f := c.table.find_fn(os_name) {
if f1.generic_names.len == call_expr.generic_types.len { if f.generic_names.len == call_expr.generic_types.len {
c.table.fn_gen_types[os_name] = c.table.fn_gen_types['${call_expr.mod}.$call_expr.name'] c.table.fn_gen_types[os_name] = c.table.fn_gen_types['${call_expr.mod}.$call_expr.name']
} }
call_expr.name = os_name call_expr.name = os_name
found = true found = true
f = f1 func = f
c.table.fns[os_name].usages++ c.table.fns[os_name].usages++
} }
} }
@ -2043,7 +2043,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
vts := c.table.get_type_symbol(v.typ) vts := c.table.get_type_symbol(v.typ)
if vts.kind == .function { if vts.kind == .function {
info := vts.info as ast.FnType info := vts.info as ast.FnType
f = info.func func = info.func
found = true found = true
found_in_args = true found_in_args = true
} }
@ -2060,44 +2060,47 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
call_expr.pos) call_expr.pos)
} }
} }
if !f.is_pub && f.language == .v && f.name.len > 0 && f.mod.len > 0 && f.mod != c.mod { if !func.is_pub && func.language == .v && func.name.len > 0 && func.mod.len > 0
c.error('function `$f.name` is private', call_expr.pos) && func.mod != c.mod {
c.error('function `$func.name` is private', call_expr.pos)
} }
if !c.cur_fn.is_deprecated && f.is_deprecated { if !c.cur_fn.is_deprecated && func.is_deprecated {
c.deprecate_fnmethod('function', f.name, f, call_expr) c.deprecate_fnmethod('function', func.name, func, call_expr)
} }
if f.is_unsafe && !c.inside_unsafe if func.is_unsafe && !c.inside_unsafe
&& (f.language != .c || (f.name[2] in [`m`, `s`] && f.mod == 'builtin')) { && (func.language != .c || (func.name[2] in [`m`, `s`] && func.mod == 'builtin')) {
// builtin C.m*, C.s* only - temp // builtin C.m*, C.s* only - temp
c.warn('function `$f.name` must be called from an `unsafe` block', call_expr.pos) c.warn('function `$func.name` must be called from an `unsafe` block', call_expr.pos)
} }
call_expr.is_keep_alive = f.is_keep_alive call_expr.is_keep_alive = func.is_keep_alive
if f.mod != 'builtin' && f.language == .v && f.no_body && !c.pref.translated && !f.is_unsafe { if func.mod != 'builtin' && func.language == .v && func.no_body && !c.pref.translated
&& !func.is_unsafe {
c.error('cannot call a function that does not have a body', call_expr.pos) c.error('cannot call a function that does not have a body', call_expr.pos)
} }
for generic_type in call_expr.generic_types { for generic_type in call_expr.generic_types {
c.ensure_type_exists(generic_type, call_expr.generic_list_pos) or {} c.ensure_type_exists(generic_type, call_expr.generic_list_pos) or {}
} }
if f.generic_names.len > 0 && f.return_type.has_flag(.generic) { if func.generic_names.len > 0 && func.return_type.has_flag(.generic) {
c.check_return_generics_struct(f.return_type, mut call_expr, generic_types) c.check_return_generics_struct(func.return_type, mut call_expr, generic_types)
} else { } else {
call_expr.return_type = f.return_type call_expr.return_type = func.return_type
} }
if f.return_type == ast.void_type && f.ctdefine.len > 0 && f.ctdefine !in c.pref.compile_defines { if func.return_type == ast.void_type && func.ctdefine.len > 0
&& func.ctdefine !in c.pref.compile_defines {
call_expr.should_be_skipped = true call_expr.should_be_skipped = true
} }
// dont check number of args for JS functions since arguments are not required // dont check number of args for JS functions since arguments are not required
if call_expr.language != .js { if call_expr.language != .js {
min_required_args := if f.is_variadic { f.params.len - 1 } else { f.params.len } min_required_args := if func.is_variadic { func.params.len - 1 } else { func.params.len }
if call_expr.args.len < min_required_args { if call_expr.args.len < min_required_args {
c.error('expected $min_required_args arguments, but got $call_expr.args.len', c.error('expected $min_required_args arguments, but got $call_expr.args.len',
call_expr.pos) call_expr.pos)
} else if !f.is_variadic && call_expr.args.len > f.params.len { } else if !func.is_variadic && call_expr.args.len > func.params.len {
unexpected_arguments := call_expr.args[min_required_args..] unexpected_arguments := call_expr.args[min_required_args..]
unexpected_arguments_pos := unexpected_arguments[0].pos.extend(unexpected_arguments.last().pos) unexpected_arguments_pos := unexpected_arguments[0].pos.extend(unexpected_arguments.last().pos)
c.error('expected $min_required_args arguments, but got $call_expr.args.len', c.error('expected $min_required_args arguments, but got $call_expr.args.len',
unexpected_arguments_pos) unexpected_arguments_pos)
return f.return_type return func.return_type
} }
} }
// println / eprintln / panic can print anything // println / eprintln / panic can print anything
@ -2123,7 +2126,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
prhas_str, prexpects_ptr, prnr_args := prtyp_sym.str_method_info() prhas_str, prexpects_ptr, prnr_args := prtyp_sym.str_method_info()
eprintln('>>> println hack typ: ${prtyp} | sym.name: ${prtyp_sym.name} | is_ptr: $prtyp_is_ptr | has_str: $prhas_str | expects_ptr: $prexpects_ptr | nr_args: $prnr_args | expr: ${prexpr.str()} ') eprintln('>>> println hack typ: ${prtyp} | sym.name: ${prtyp_sym.name} | is_ptr: $prtyp_is_ptr | has_str: $prhas_str | expects_ptr: $prexpects_ptr | nr_args: $prnr_args | expr: ${prexpr.str()} ')
*/ */
return f.return_type return func.return_type
} }
// `return error(err)` -> `return err` // `return error(err)` -> `return err`
if fn_name == 'error' { if fn_name == 'error' {
@ -2135,19 +2138,19 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
} }
// TODO: typ optimize.. this node can get processed more than once // TODO: typ optimize.. this node can get processed more than once
if call_expr.expected_arg_types.len == 0 { if call_expr.expected_arg_types.len == 0 {
for param in f.params { for param in func.params {
call_expr.expected_arg_types << param.typ call_expr.expected_arg_types << param.typ
} }
} }
for i, call_arg in call_expr.args { for i, call_arg in call_expr.args {
param := if f.is_variadic && i >= f.params.len - 1 { param := if func.is_variadic && i >= func.params.len - 1 {
f.params[f.params.len - 1] func.params[func.params.len - 1]
} else { } else {
f.params[i] func.params[i]
} }
if f.is_variadic && call_arg.expr is ast.ArrayDecompose { if func.is_variadic && call_arg.expr is ast.ArrayDecompose {
if i > f.params.len - 1 { if i > func.params.len - 1 {
c.error('too many arguments in call to `$f.name`', call_expr.pos) c.error('too many arguments in call to `$func.name`', call_expr.pos)
} }
} }
c.expected_type = param.typ c.expected_type = param.typ
@ -2155,7 +2158,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
call_expr.args[i].typ = typ call_expr.args[i].typ = typ
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
arg_typ_sym := c.table.get_type_symbol(param.typ) arg_typ_sym := c.table.get_type_symbol(param.typ)
if f.is_variadic && typ.has_flag(.variadic) && call_expr.args.len - 1 > i { if func.is_variadic && typ.has_flag(.variadic) && call_expr.args.len - 1 > i {
c.error('when forwarding a variadic variable, it must be the final argument', c.error('when forwarding a variadic variable, it must be the final argument',
call_arg.pos) call_arg.pos)
} }
@ -2164,7 +2167,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
c.error('function with `shared` arguments cannot be called inside `lock`/`rlock` block', c.error('function with `shared` arguments cannot be called inside `lock`/`rlock` block',
call_arg.pos) call_arg.pos)
} }
if call_arg.is_mut && f.language == .v { if call_arg.is_mut && func.language == .v {
to_lock, pos := c.fail_if_immutable(call_arg.expr) to_lock, pos := c.fail_if_immutable(call_arg.expr)
if !param.is_mut { if !param.is_mut {
tok := call_arg.share.str() tok := call_arg.share.str()
@ -2203,10 +2206,10 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
if typ_sym.kind == .void && arg_typ_sym.kind == .string { if typ_sym.kind == .void && arg_typ_sym.kind == .string {
continue continue
} }
if f.generic_names.len > 0 { if func.generic_names.len > 0 {
if param.typ.has_flag(.generic) if param.typ.has_flag(.generic)
&& f.generic_names.len == call_expr.generic_types.len { && func.generic_names.len == call_expr.generic_types.len {
if unwrap_typ := c.table.resolve_generic_by_names(param.typ, f.generic_names, if unwrap_typ := c.table.resolve_generic_by_names(param.typ, func.generic_names,
call_expr.generic_types) call_expr.generic_types)
{ {
if (unwrap_typ.idx() == typ.idx()) if (unwrap_typ.idx() == typ.idx())
@ -2228,7 +2231,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos) c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos)
} }
// Warn about automatic (de)referencing, which will be removed soon. // Warn about automatic (de)referencing, which will be removed soon.
if f.language != .c && !c.inside_unsafe && typ.nr_muls() != param.typ.nr_muls() if func.language != .c && !c.inside_unsafe && typ.nr_muls() != param.typ.nr_muls()
&& !(call_arg.is_mut && param.is_mut) && !(!call_arg.is_mut && !param.is_mut) && !(call_arg.is_mut && param.is_mut) && !(!call_arg.is_mut && !param.is_mut)
&& param.typ !in [ast.byteptr_type, ast.charptr_type, ast.voidptr_type] { && param.typ !in [ast.byteptr_type, ast.charptr_type, ast.voidptr_type] {
// sym := c.table.get_type_symbol(typ) // sym := c.table.get_type_symbol(typ)
@ -2236,28 +2239,30 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
call_arg.pos) call_arg.pos)
} }
} }
if f.generic_names.len != call_expr.generic_types.len { if func.generic_names.len != call_expr.generic_types.len {
// no type arguments given in call, attempt implicit instantiation // no type arguments given in call, attempt implicit instantiation
c.infer_fn_types(f, mut call_expr) c.infer_fn_types(func, mut call_expr)
} }
if call_expr.generic_types.len > 0 && f.return_type != 0 { if call_expr.generic_types.len > 0 && func.return_type != 0 {
if typ := c.table.resolve_generic_by_names(f.return_type, f.generic_names, call_expr.generic_types) { if typ := c.table.resolve_generic_by_names(func.return_type, func.generic_names,
call_expr.generic_types)
{
call_expr.return_type = typ call_expr.return_type = typ
return typ return typ
} }
} }
if call_expr.generic_types.len > 0 && f.generic_names.len == 0 { if call_expr.generic_types.len > 0 && func.generic_names.len == 0 {
c.error('a non generic function called like a generic one', call_expr.generic_list_pos) c.error('a non generic function called like a generic one', call_expr.generic_list_pos)
} }
if call_expr.generic_types.len > f.generic_names.len { if call_expr.generic_types.len > func.generic_names.len {
c.error('too many generic parameters got $call_expr.generic_types.len, expected $f.generic_names.len', c.error('too many generic parameters got $call_expr.generic_types.len, expected $func.generic_names.len',
call_expr.generic_list_pos) call_expr.generic_list_pos)
} }
if f.generic_names.len > 0 { if func.generic_names.len > 0 {
return call_expr.return_type return call_expr.return_type
} }
return f.return_type return func.return_type
} }
fn (mut c Checker) deprecate_fnmethod(kind string, name string, the_fn ast.Fn, call_expr ast.CallExpr) { fn (mut c Checker) deprecate_fnmethod(kind string, name string, the_fn ast.Fn, call_expr ast.CallExpr) {