cgen: fix variadics called with 0 vargs
parent
f2c9592b86
commit
9c6ac7cb71
|
@ -171,17 +171,18 @@ pub:
|
||||||
|
|
||||||
pub struct CallExpr {
|
pub struct CallExpr {
|
||||||
pub:
|
pub:
|
||||||
// tok token.Token
|
// tok token.Token
|
||||||
pos token.Position
|
pos token.Position
|
||||||
mut:
|
mut:
|
||||||
// func Expr
|
// func Expr
|
||||||
name string
|
name string
|
||||||
args []CallArg
|
args []CallArg
|
||||||
is_c bool
|
exp_arg_types []table.Type
|
||||||
muts []bool
|
is_c bool
|
||||||
or_block OrExpr
|
muts []bool
|
||||||
|
or_block OrExpr
|
||||||
// has_or_block bool
|
// has_or_block bool
|
||||||
return_type table.Type
|
return_type table.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MethodCallExpr {
|
pub struct MethodCallExpr {
|
||||||
|
@ -193,6 +194,7 @@ pub:
|
||||||
args []CallArg
|
args []CallArg
|
||||||
or_block OrExpr
|
or_block OrExpr
|
||||||
mut:
|
mut:
|
||||||
|
exp_arg_types []table.Type
|
||||||
expr_type table.Type // type of `user`
|
expr_type table.Type // type of `user`
|
||||||
receiver_type table.Type // User
|
receiver_type table.Type // User
|
||||||
return_type table.Type
|
return_type table.Type
|
||||||
|
@ -200,11 +202,10 @@ mut:
|
||||||
|
|
||||||
pub struct CallArg {
|
pub struct CallArg {
|
||||||
pub:
|
pub:
|
||||||
is_mut bool
|
is_mut bool
|
||||||
expr Expr
|
expr Expr
|
||||||
mut:
|
mut:
|
||||||
typ table.Type
|
typ table.Type
|
||||||
expected_type table.Type
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Return {
|
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
|
return f.return_type
|
||||||
}
|
}
|
||||||
if call_expr.args.len < f.args.len {
|
min_required_args := if f.is_variadic { f.args.len - 1 } else { f.args.len }
|
||||||
c.error('too few arguments in call to `$fn_name`', call_expr.pos)
|
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 {
|
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)
|
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)
|
call_expr.args[0].typ = c.expr(call_expr.args[0].expr)
|
||||||
return f.return_type
|
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 {
|
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] }
|
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
|
c.expected_type = arg.typ
|
||||||
typ := c.expr(call_arg.expr)
|
typ := c.expr(call_arg.expr)
|
||||||
call_expr.args[i].typ = typ
|
call_expr.args[i].typ = typ
|
||||||
call_expr.args[i].expected_type = arg.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(arg.typ)
|
arg_typ_sym := c.table.get_type_symbol(arg.typ)
|
||||||
if !c.table.check(typ, 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 {
|
for i, arg in method_call_expr.args {
|
||||||
c.expected_type = method.args[i + 1].typ
|
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)
|
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.receiver_type = method.args[0].typ
|
||||||
method_call_expr.return_type = method.return_type
|
method_call_expr.return_type = method.return_type
|
||||||
return 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(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
ast.None {
|
ast.None {
|
||||||
|
@ -1729,55 +1729,60 @@ fn (g mut Gen) assoc(node ast.Assoc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) call_args(args []ast.CallArg) {
|
fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
|
||||||
for i, arg in args {
|
is_variadic := expected_types.len > 0 && table.type_is_variadic(expected_types[expected_types.len - 1])
|
||||||
if table.type_is_variadic(arg.expected_type) {
|
mut arg_no := 0
|
||||||
struct_name := 'varg_' + g.typ(arg.expected_type).replace('*', '_ptr')
|
for arg in args {
|
||||||
len := args.len - i
|
if is_variadic && arg_no == expected_types.len - 1 {
|
||||||
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('}}')
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// some c fn definitions dont have args (cfns.v) or are not updated in checker
|
// some c fn definitions dont have args (cfns.v) or are not updated in checker
|
||||||
if arg.expected_type != 0 {
|
// when these are fixed we wont beed this check
|
||||||
g.ref_or_deref_arg(arg, arg.expr, true)
|
if arg_no < expected_types.len {
|
||||||
// g.expr_with_cast(arg.expr, arg.typ, arg.expected_type)
|
g.ref_or_deref_arg(arg, expected_types[arg_no])
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
g.expr(arg.expr)
|
g.expr(arg.expr)
|
||||||
}
|
}
|
||||||
if i != args.len - 1 {
|
if arg_no < args.len - 1 || is_variadic {
|
||||||
g.write(', ')
|
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]
|
[inline]
|
||||||
fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expr ast.Expr, with_cast bool) {
|
fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
|
||||||
arg_is_ptr := table.type_is_ptr(arg.expected_type) || table.type_idx(arg.expected_type) in table.pointer_type_idxs
|
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
|
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 {
|
if arg.is_mut && !arg_is_ptr {
|
||||||
g.write('&/*mut*/')
|
g.write('&/*mut*/')
|
||||||
}
|
}
|
||||||
else if arg_is_ptr && !expr_is_ptr {
|
else if arg_is_ptr && !expr_is_ptr {
|
||||||
if arg.is_mut {
|
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 {
|
if sym.kind == .array {
|
||||||
// Special case for mutable arrays. We can't `&` function
|
// Special case for mutable arrays. We can't `&` function
|
||||||
// results, have to use `(array[]){ expr }[0]` hack.
|
// results, have to use `(array[]){ expr }[0]` hack.
|
||||||
g.write('&/*111*/(array[]){')
|
g.write('&/*111*/(array[]){')
|
||||||
g.expr(expr)
|
g.expr(arg.expr)
|
||||||
g.write('}[0]')
|
g.write('}[0]')
|
||||||
return
|
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
|
// Dereference a pointer if a value is required
|
||||||
g.write('*/*d*/')
|
g.write('*/*d*/')
|
||||||
}
|
}
|
||||||
if with_cast {
|
g.expr_with_cast(arg.expr, arg.typ, expected_type)
|
||||||
g.expr_with_cast(arg.expr, arg.typ, arg.expected_type)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.expr(arg.expr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verror(s string) {
|
fn verror(s string) {
|
||||||
|
@ -2102,7 +2102,7 @@ fn (g mut Gen) call_expr(it ast.CallExpr) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
g.write('${name}(')
|
g.write('${name}(')
|
||||||
g.call_args(it.args)
|
g.call_args(it.args, it.exp_arg_types)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
if it.or_block.stmts.len > 0 {
|
if it.or_block.stmts.len > 0 {
|
||||||
|
|
Loading…
Reference in New Issue