cgen: fix variadics called with 0 vargs
parent
f2c9592b86
commit
9c6ac7cb71
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue