From 4b6244c9c1dc569ded29b21ee30e94ee8d032618 Mon Sep 17 00:00:00 2001 From: Enzo Date: Tue, 16 Mar 2021 23:18:43 +0100 Subject: [PATCH] gen: fix generic variadic (#9333) --- vlib/v/ast/ast.v | 6 ----- vlib/v/checker/check_types.v | 3 +++ vlib/v/checker/checker.v | 1 - vlib/v/gen/c/fn.v | 45 +++++++++++++++++++----------------- vlib/v/parser/fn.v | 5 +--- vlib/v/table/table.v | 6 ++--- vlib/v/table/types.v | 6 +---- vlib/v/tests/generics_test.v | 42 ++++++++++++++++++++++----------- 8 files changed, 60 insertions(+), 54 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 03eff5149d..c6eb25a02f 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1550,12 +1550,6 @@ pub fn ex2fe(x Expr) table.FExpr { return res } -// experimental ast.Table -pub struct Table { - // pub mut: - // main_fn_decl_node FnDecl -} - // helper for dealing with `m[k1][k2][k3][k3] = value` pub fn (mut lx IndexExpr) recursive_mapset_is_setter(val bool) { lx.is_setter = val diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 1ef7cd17fd..3e36792a12 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -464,6 +464,9 @@ pub fn (mut c Checker) infer_fn_types(f table.Fn, mut call_expr ast.CallExpr) { } } break + } else if param.typ.has_flag(.variadic) { + typ = c.table.mktyp(arg.typ) + break } } if typ == table.void_type { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 5f6d63cd9a..abaf900d95 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1975,7 +1975,6 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { c.warn('`error($arg)` can be shortened to just `$arg`', call_expr.pos) } } - // TODO: typ optimize.. this node can get processed more than once if call_expr.expected_arg_types.len == 0 { for param in f.params { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index b6aa0e5d6b..f308bed210 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -495,7 +495,6 @@ fn (mut g Gen) method_call(node ast.CallExpr) { g.write('${dot}_object') if node.args.len > 0 { g.write(', ') - // g.call_args(node.args, node.expected_arg_types) // , []) g.call_args(node) } g.write(')') @@ -701,7 +700,6 @@ fn (mut g Gen) method_call(node ast.CallExpr) { } */ // /////// - // g.call_args(node.args, node.expected_arg_types) // , []) g.call_args(node) g.write(')') } @@ -740,7 +738,6 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { encode_name := js_enc_name(json_type_str) g.writeln('// json.encode') g.write('cJSON* $json_obj = ${encode_name}(') - // g.call_args(node.args, node.expected_arg_types) // , []) if node.args[0].typ.is_ptr() { g.write('*') } @@ -762,7 +759,6 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { g.write('cJSON* $json_obj = json__json_parse(') // Skip the first argument in json.decode which is a type // its name was already used to generate the function call - // g.call_args(node.args[1..], node.expected_arg_types) // , []) g.is_js_call = true g.call_args(node) g.is_js_call = false @@ -837,7 +833,6 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { if g.pref.is_debug && node.name == 'panic' { paline, pafile, pamod, pafn := g.panic_debug_info(node.pos) g.write('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), ') - // g.call_args(node.args, node.expected_arg_types) // , []) g.call_args(node) g.write(')') } else { @@ -850,7 +845,6 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { if g.is_json_fn { g.write(json_obj) } else { - // g.call_args(node.args, node.expected_arg_types) // , tmp_arg_vars_to_free) g.call_args(node) } g.write(')') @@ -935,17 +929,13 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) { } fn (mut g Gen) autofree_call_postgen(node_pos int) { - /* - if g.strs_to_free.len == 0 { - return - } - */ - /* - g.writeln('\n/* strs_to_free3: $g.nr_vars_to_free */') - if g.nr_vars_to_free <= 0 { - return - } - */ + // if g.strs_to_free.len == 0 { + // return + // } + // g.writeln('\n/* strs_to_free3: $g.nr_vars_to_free */') + // if g.nr_vars_to_free <= 0 { + // return + // } /* for s in g.strs_to_free { g.writeln('string_free(&$s);') @@ -996,8 +986,8 @@ fn (mut g Gen) call_args(node ast.CallExpr) { args := if g.is_js_call { node.args[1..] } else { node.args } expected_types := node.expected_arg_types // only v variadic, C variadic args will be appeneded like normal args - is_variadic := expected_types.len > 0 - && expected_types[expected_types.len - 1].has_flag(.variadic) && node.language == .v + is_variadic := expected_types.len > 0 && expected_types.last().has_flag(.variadic) + && node.language == .v for i, arg in args { if is_variadic && i == expected_types.len - 1 { break @@ -1039,10 +1029,23 @@ fn (mut g Gen) call_args(node ast.CallExpr) { } arg_nr := expected_types.len - 1 if is_variadic { - varg_type := expected_types[expected_types.len - 1] + varg_type := expected_types.last() variadic_count := args.len - arg_nr arr_sym := g.table.get_type_symbol(varg_type) - arr_info := arr_sym.info as table.Array + mut arr_info := arr_sym.info as table.Array + if varg_type.has_flag(.generic) { + if fn_def := g.table.find_fn(node.name) { + varg_type_name := g.table.type_to_str(varg_type) + for i, fn_gen_name in fn_def.generic_names { + if fn_gen_name == varg_type_name { + arr_info.elem_type = node.generic_types[i] + break + } + } + } else { + g.error('unable to find function $node.name', node.pos) + } + } elem_type := g.typ(arr_info.elem_type) if args.len > 0 && args[args.len - 1].expr is ast.ArrayDecompose { g.expr(args[args.len - 1].expr) diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index f430a7edbd..071f61d643 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -320,7 +320,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl { scope: 0 } } - // p.warn('reg method $type_sym.name . $name ()') type_sym_method_idx = type_sym.register_method(table.Fn{ name: name params: params @@ -349,7 +348,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl { if !p.pref.translated && language == .v && name in p.table.fns { p.table.redefined_fns << name } - // p.warn('reg functn $name ()') p.table.register_fn(table.Fn{ name: name params: params @@ -644,7 +642,6 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) { || p.peek_tok.kind == .dot || p.peek_tok.kind == .rpar // TODO copy pasta, merge 2 branches if types_only { - // p.warn('types only') mut arg_no := 1 for p.tok.kind != .rpar { if p.tok.kind == .eof { @@ -789,7 +786,7 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) { } } if is_variadic { - typ = table.new_type(p.table.find_or_register_array(typ)).set_flag(.variadic) + typ = table.new_type(p.table.find_or_register_array(typ)).derive(typ).set_flag(.variadic) } for i, arg_name in arg_names { args << table.Param{ diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 29359646d6..ed73e1889f 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -854,13 +854,13 @@ pub fn (t &Table) mktyp(typ Type) Type { } } -pub fn (mut mytable Table) register_fn_gen_type(fn_name string, types []Type) { - mut a := mytable.fn_gen_types[fn_name] +pub fn (mut t Table) register_fn_gen_type(fn_name string, types []Type) { + mut a := t.fn_gen_types[fn_name] if types in a { return } a << types - mytable.fn_gen_types[fn_name] = a + t.fn_gen_types[fn_name] = a } // TODO: there is a bug when casting sumtype the other way if its pointer diff --git a/vlib/v/table/types.v b/vlib/v/table/types.v index 23650936f1..6055926e51 100644 --- a/vlib/v/table/types.v +++ b/vlib/v/table/types.v @@ -425,11 +425,7 @@ pub enum Kind { } pub fn (t &TypeSymbol) str() string { - if t.kind in [.array, .array_fixed] { - return t.name.replace('array_', '[]') - } else { - return t.name - } + return t.name } [inline] diff --git a/vlib/v/tests/generics_test.v b/vlib/v/tests/generics_test.v index e88fcfb46e..f0870d6be0 100644 --- a/vlib/v/tests/generics_test.v +++ b/vlib/v/tests/generics_test.v @@ -1,20 +1,9 @@ import simplemodule -fn test_todo() { -} - fn simple(p T) T { return p } -fn plus(xxx T, b T) T { - // x := a - // y := b - // ww := ww - // q := xx + 1 - return xxx + b -} - fn test_identity() { assert simple(1) == 1 assert simple(1 + 0) == 1 @@ -27,7 +16,15 @@ fn test_identity() { assert simple(simplemodule.Data{value: 0}).value == 0 } -fn test_plus() { +fn plus(xxx T, b T) T { + // x := a + // y := b + // ww := ww + // q := xx + 1 + return xxx + b +} + +fn test_infix_expr() { a := plus(2, 3) assert a == 5 assert plus(10, 1) == 11 @@ -42,9 +39,26 @@ fn sum(l []T) T { return r } -fn test_foo() { +fn test_array() { b := [1, 2, 3] - assert sum(b) == 6 + assert sum(b) == 6 +} + +fn max(brug string, a ...T) T { + mut max := a[0] + for item in a[1..] { + if max < item { + max = item + } + } + return max +} + +fn test_generic_variadic() { + assert max('krkr', 1, 2, 3, 4) == 4 + a := [f64(1.2), 3.2, 0.1, 2.2] + assert max('krkr', ...a) == 3.2 + assert max('krkr', ...[byte(4), 3, 2, 1]) == 4 } fn create() {