checker: minor cleanup in fn_call (#9681)
parent
5a1a1b7c12
commit
b0b3c51658
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue