diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 1a8b70bbb2..5f4a1e73db 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -171,17 +171,18 @@ pub: pub struct CallExpr { pub: -// tok token.Token - pos token.Position +// tok token.Token + pos token.Position mut: -// func Expr - name string - args []CallArg - is_c bool - muts []bool - or_block OrExpr +// func Expr + name string + args []CallArg + exp_arg_types []table.Type + is_c bool + muts []bool + or_block OrExpr // has_or_block bool - return_type table.Type + return_type table.Type } pub struct MethodCallExpr { @@ -193,6 +194,7 @@ pub: args []CallArg or_block OrExpr mut: + exp_arg_types []table.Type expr_type table.Type // type of `user` receiver_type table.Type // User return_type table.Type @@ -200,11 +202,10 @@ mut: pub struct CallArg { pub: - is_mut bool - expr Expr + is_mut bool + expr Expr mut: - typ table.Type - expected_type table.Type + typ table.Type } pub struct Return { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index fff400da8c..eea3da99e3 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -232,8 +232,9 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { } return f.return_type } - if call_expr.args.len < f.args.len { - c.error('too few arguments in call to `$fn_name`', call_expr.pos) + min_required_args := if f.is_variadic { f.args.len - 1 } else { f.args.len } + if call_expr.args.len < min_required_args { + c.error('too few arguments in call to `$fn_name` ($call_expr.args.len instead of $min_required_args)', call_expr.pos) } else if !f.is_variadic && call_expr.args.len > f.args.len { c.error('too many arguments in call to `$fn_name` ($call_expr.args.len instead of $f.args.len)', call_expr.pos) @@ -244,12 +245,17 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { call_expr.args[0].typ = c.expr(call_expr.args[0].expr) return f.return_type } + // TODO: typ optimize.. this node can get processed more than once + if call_expr.exp_arg_types.len == 0 { + for arg in f.args { + call_expr.exp_arg_types << arg.typ + } + } for i, call_arg in call_expr.args { arg := if f.is_variadic && i >= f.args.len - 1 { f.args[f.args.len - 1] } else { f.args[i] } c.expected_type = arg.typ typ := c.expr(call_arg.expr) call_expr.args[i].typ = typ - call_expr.args[i].expected_type = arg.typ typ_sym := c.table.get_type_symbol(typ) arg_typ_sym := c.table.get_type_symbol(arg.typ) if !c.table.check(typ, arg.typ) { @@ -320,9 +326,14 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) // } for i, arg in method_call_expr.args { c.expected_type = method.args[i + 1].typ - method_call_expr.args[i].expected_type = c.expected_type method_call_expr.args[i].typ = c.expr(arg.expr) } + // TODO: typ optimize.. this node can get processed more than once + if method_call_expr.exp_arg_types.len == 0 { + for i in 1 .. method.args.len { + method_call_expr.exp_arg_types << method.args[i].typ + } + } method_call_expr.receiver_type = method.args[0].typ method_call_expr.return_type = method.return_type return method.return_type diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 184b8ba0e7..3fef5aaa51 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1021,7 +1021,7 @@ fn (g mut Gen) expr(node ast.Expr) { } */ // /////// - g.call_args(it.args) + g.call_args(it.args, it.exp_arg_types) g.write(')') } ast.None { @@ -1729,55 +1729,60 @@ fn (g mut Gen) assoc(node ast.Assoc) { } } -fn (g mut Gen) call_args(args []ast.CallArg) { - for i, arg in args { - if table.type_is_variadic(arg.expected_type) { - struct_name := 'varg_' + g.typ(arg.expected_type).replace('*', '_ptr') - len := args.len - i - varg_type_str := int(arg.expected_type).str() - if len > g.variadic_args[varg_type_str] { - g.variadic_args[varg_type_str] = len - } - g.write('($struct_name){.len=$len,.args={') - for j in i .. args.len { - g.ref_or_deref_arg(args[j], args[j].expr, false) - // g.expr(args[j].expr) - if j < args.len - 1 { - g.write(', ') - } - } - g.write('}}') +fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) { + is_variadic := expected_types.len > 0 && table.type_is_variadic(expected_types[expected_types.len - 1]) + mut arg_no := 0 + for arg in args { + if is_variadic && arg_no == expected_types.len - 1 { break } // some c fn definitions dont have args (cfns.v) or are not updated in checker - if arg.expected_type != 0 { - g.ref_or_deref_arg(arg, arg.expr, true) - // g.expr_with_cast(arg.expr, arg.typ, arg.expected_type) + // when these are fixed we wont beed this check + if arg_no < expected_types.len { + g.ref_or_deref_arg(arg, expected_types[arg_no]) } else { g.expr(arg.expr) } - if i != args.len - 1 { + if arg_no < args.len - 1 || is_variadic { g.write(', ') } + arg_no++ + } + if is_variadic { + varg_type := expected_types[expected_types.len - 1] + struct_name := 'varg_' + g.typ(varg_type).replace('*', '_ptr') + len := args.len - arg_no + varg_type_str := int(varg_type).str() + if len > g.variadic_args[varg_type_str] { + g.variadic_args[varg_type_str] = len + } + g.write('($struct_name){.len=$len,.args={') + for j in arg_no .. args.len { + g.ref_or_deref_arg(args[j], varg_type) + if j < args.len - 1 { + g.write(', ') + } + } + g.write('}}') } } [inline] -fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expr ast.Expr, with_cast bool) { - arg_is_ptr := table.type_is_ptr(arg.expected_type) || table.type_idx(arg.expected_type) in table.pointer_type_idxs +fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) { + arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs expr_is_ptr := table.type_is_ptr(arg.typ) || table.type_idx(arg.typ) in table.pointer_type_idxs if arg.is_mut && !arg_is_ptr { g.write('&/*mut*/') } else if arg_is_ptr && !expr_is_ptr { if arg.is_mut { - sym := g.table.get_type_symbol(arg.expected_type) + sym := g.table.get_type_symbol(arg.typ) if sym.kind == .array { // Special case for mutable arrays. We can't `&` function // results, have to use `(array[]){ expr }[0]` hack. g.write('&/*111*/(array[]){') - g.expr(expr) + g.expr(arg.expr) g.write('}[0]') return } @@ -1788,12 +1793,7 @@ fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expr ast.Expr, with_cast bool) // Dereference a pointer if a value is required g.write('*/*d*/') } - if with_cast { - g.expr_with_cast(arg.expr, arg.typ, arg.expected_type) - } - else { - g.expr(arg.expr) - } + g.expr_with_cast(arg.expr, arg.typ, expected_type) } fn verror(s string) { @@ -2102,7 +2102,7 @@ fn (g mut Gen) call_expr(it ast.CallExpr) { } else { g.write('${name}(') - g.call_args(it.args) + g.call_args(it.args, it.exp_arg_types) g.write(')') } if it.or_block.stmts.len > 0 {