From fe9d884d9061b20372408e887b4f2b80a233b7c5 Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Sat, 2 Nov 2019 03:14:16 +1100 Subject: [PATCH] parser: fix forwarding vargs & multiple call varg len fix --- vlib/compiler/fn.v | 32 ++++++++++++++++++-------- vlib/compiler/tests/fn_variadic_test.v | 18 +++++++++++++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index 3864a5e94a..515888225a 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -813,8 +813,8 @@ fn (p mut Parser) fn_args(f mut Fn) { f.is_variadic = true t := p.get_type() // register varg struct, incase function is never called - if p.first_pass() && !f.is_generic { - p.fn_register_vargs_stuct(f, t, []string) + if p.first_pass() && !f.is_generic && !f.is_c{ + p.register_vargs_stuct(t, 0) } typ = '...$t' } else { @@ -1205,21 +1205,25 @@ fn (p mut Parser) replace_type_params(f &Fn, ti TypeInst) []string { return r } -fn (p mut Parser) fn_register_vargs_stuct(f &Fn, typ string, values []string) string { - vargs_struct := '_V_FnVargs_$f.name' +fn (p mut Parser) register_vargs_stuct(typ string, len int) string { + vargs_struct := '_V_FnVargs_$typ' varg_type := Type{ cat: TypeCategory.struct_, name: vargs_struct, mod: p.mod } + mut varg_len := len if !p.table.known_type(vargs_struct) { p.table.register_type2(varg_type) p.cgen.typedefs << 'typedef struct $vargs_struct $vargs_struct;\n' } else { + ex_typ := p.table.find_type(vargs_struct) + ex_len := ex_typ.fields[1].name[5..ex_typ.fields[1].name.len-1].int() + if ex_len > varg_len { varg_len = ex_len } p.table.rewrite_type(varg_type) } p.table.add_field(vargs_struct, 'len', 'int', false, '', .public) - p.table.add_field(vargs_struct, 'args[$values.len]', typ, false, '', .public) + p.table.add_field(vargs_struct, 'args[$varg_len]', typ, false, '', .public) return vargs_struct } @@ -1238,6 +1242,10 @@ fn (p mut Parser) fn_call_vargs(f Fn) (string, []string) { p.cgen.start_tmp() mut varg_type := p.bool_expression() varg_value := p.cgen.end_tmp() + if varg_type.starts_with('...') && + (values.len > 0 || p.tok == .comma) { + p.error('You cannot pass additional vargs when forwarding vargs to another function/method') + } if !f.is_generic { p.check_types(last_arg.typ, varg_type) } else { @@ -1246,7 +1254,6 @@ fn (p mut Parser) fn_call_vargs(f Fn) (string, []string) { p.check_types(varg_type, t) } } - varg_def_type = varg_type } ref_deref := if last_arg.typ.ends_with('*') && !varg_type.ends_with('*') { '&' } else if !last_arg.typ.ends_with('*') && varg_type.ends_with('*') { '*' } @@ -1263,12 +1270,17 @@ fn (p mut Parser) fn_call_vargs(f Fn) (string, []string) { if !f.is_method && f.args.len > 1 { p.cgen.gen(',') } - return varg_def_type, values + return types[0], values } fn (p mut Parser) fn_gen_caller_vargs(f &Fn, varg_type string, values []string) { - vargs_struct := p.fn_register_vargs_stuct(f, varg_type, values) - p.cgen.gen('&($vargs_struct){.len=$values.len,.args={'+values.join(',')+'}}') + is_varg := varg_type.starts_with('...') + if is_varg { // forwarding varg + p.cgen.gen('${values[0]}') + } else { + vargs_struct := p.register_vargs_stuct(varg_type, values.len) + p.cgen.gen('&($vargs_struct){.len=$values.len,.args={'+values.join(',')+'}}') + } } fn (p mut Parser) register_multi_return_stuct(types []string) string { @@ -1450,7 +1462,7 @@ fn (f &Fn) str_args(table &Table) string { } } else if arg.typ.starts_with('...') { - s += '_V_FnVargs_$f.name *$arg.name' + s += '_V_FnVargs_${arg.typ[3..]} *$arg.name' } else { // s += '$arg.typ $arg.name' diff --git a/vlib/compiler/tests/fn_variadic_test.v b/vlib/compiler/tests/fn_variadic_test.v index 60089d4e93..4c0c68552e 100644 --- a/vlib/compiler/tests/fn_variadic_test.v +++ b/vlib/compiler/tests/fn_variadic_test.v @@ -2,6 +2,7 @@ struct VaTestGroup { name string } +// basic fn variadic_test(name string, groups ...VaTestGroup) { assert groups.len == 2 assert groups[0].name == 'users' @@ -14,6 +15,7 @@ fn test_fn_variadic() { variadic_test('joe', group1, group2) } +// generic fn variadic_test_generic(a int, b ...T) T { b1 := b[0] b2 := b[1] @@ -23,3 +25,19 @@ fn variadic_test_generic(a int, b ...T) T { fn test_fn_variadic_generic() { assert variadic_test_generic(111, 'hello', 'v') == '111 hello v' } + +// forwarding +fn variadic_forward_a(a ...string) string { + return variadic_forward_b(a) +} + +fn variadic_forward_b(a ...string) string { + a0 := a[0] + a1 := a[1] + a2 := a[2] + return '$a0$a1$a2' +} + +fn test_fn_variadic_forward() { + assert variadic_forward_a('a', 'b', 'c') == 'abc' +}