From 413ffbfc3b90c198bf0f6874a9ea78ba1a374ca7 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Thu, 13 Jul 2023 05:58:49 -0300 Subject: [PATCH] v: allow alias as fixed array on return (#18817) --- vlib/v/ast/types.v | 24 ++++++++++++++ vlib/v/checker/fn.v | 12 +++++-- vlib/v/checker/return.v | 7 ++-- vlib/v/checker/tests/return_fixed_array.out | 7 ---- vlib/v/checker/tests/return_fixed_array.vv | 13 -------- vlib/v/gen/c/assign.v | 19 +++++++++-- vlib/v/gen/c/cgen.v | 4 ++- vlib/v/gen/c/dumpexpr.v | 33 ++++++++++++++----- vlib/v/gen/c/fn.v | 10 +++++- vlib/v/parser/parse_type.v | 16 ++++++++- vlib/v/parser/parser.v | 1 + .../return_aliases_of_fixed_array_test.v} | 6 +++- vlib/v/tests/return_fixed_array_test.v | 25 ++++++++++++++ 13 files changed, 138 insertions(+), 39 deletions(-) delete mode 100644 vlib/v/checker/tests/return_fixed_array.out delete mode 100644 vlib/v/checker/tests/return_fixed_array.vv rename vlib/v/{checker/tests/return_aliases_of_fixed_array.vv => tests/return_aliases_of_fixed_array_test.v} (64%) create mode 100644 vlib/v/tests/return_fixed_array_test.v diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index b067d0104e..7e00250f8e 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -887,6 +887,30 @@ pub fn (t &TypeSymbol) is_heap() bool { } } +pub fn (t &ArrayFixed) is_compatible(t2 ArrayFixed) bool { + return t.size == t2.size && t.elem_type == t2.elem_type +} + +pub fn (t &TypeSymbol) is_array_fixed() bool { + if t.info is ArrayFixed { + return true + } else if t.info is Alias { + return global_table.final_sym(t.info.parent_type).is_array_fixed() + } else { + return false + } +} + +pub fn (t &TypeSymbol) is_array_fixed_ret() bool { + if t.info is ArrayFixed { + return t.info.is_fn_ret + } else if t.info is Alias { + return global_table.final_sym(t.info.parent_type).is_array_fixed_ret() + } else { + return false + } +} + pub fn (mut t Table) register_builtin_type_symbols() { // reserve index 0 so nothing can go there // save index check, 0 will mean not found diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 7a97ae05d9..1c1c729d32 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -129,8 +129,6 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { node.return_type_pos) } } - } else if c.table.sym(node.return_type).kind == .alias && return_sym.kind == .array_fixed { - c.error('fixed array cannot be returned by function using alias', node.return_type_pos) } // Ensure each generic type of the parameter was declared in the function's definition if node.return_type.has_flag(.generic) { @@ -1521,6 +1519,16 @@ fn (mut c Checker) cast_fixed_array_ret(typ ast.Type, sym ast.TypeSymbol) ast.Ty return typ } +// cast_to_fixed_array_ret casts a ArrayFixed type created to do not return to a returning one +fn (mut c Checker) cast_to_fixed_array_ret(typ ast.Type, sym ast.TypeSymbol) ast.Type { + if sym.kind == .array_fixed && !(sym.info as ast.ArrayFixed).is_fn_ret { + info := sym.info as ast.ArrayFixed + return c.table.find_or_register_array_fixed(info.elem_type, info.size, info.size_expr, + true) + } + return typ +} + fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { left_type := c.expr(mut node.left) if left_type == ast.void_type { diff --git a/vlib/v/checker/return.v b/vlib/v/checker/return.v index 9e589d59f5..fb9a19f213 100644 --- a/vlib/v/checker/return.v +++ b/vlib/v/checker/return.v @@ -208,8 +208,11 @@ fn (mut c Checker) return_stmt(mut node ast.Return) { } continue } - if exp_type_sym.kind == .array_fixed && got_type_sym.kind == .array_fixed { - if (exp_type_sym.info as ast.ArrayFixed).size == (got_type_sym.info as ast.ArrayFixed).size && (exp_type_sym.info as ast.ArrayFixed).elem_type == (got_type_sym.info as ast.ArrayFixed).elem_type { + exp_final_sym := c.table.final_sym(exp_type) + got_final_sym := c.table.final_sym(got_type) + if exp_final_sym.kind == .array_fixed && got_final_sym.kind == .array_fixed { + got_arr_sym := c.table.sym(c.cast_to_fixed_array_ret(got_type, got_final_sym)) + if (exp_final_sym.info as ast.ArrayFixed).is_compatible(got_arr_sym.info as ast.ArrayFixed) { continue } } diff --git a/vlib/v/checker/tests/return_fixed_array.out b/vlib/v/checker/tests/return_fixed_array.out deleted file mode 100644 index 508868f028..0000000000 --- a/vlib/v/checker/tests/return_fixed_array.out +++ /dev/null @@ -1,7 +0,0 @@ -vlib/v/checker/tests/return_fixed_array.vv:11:25: error: fixed array cannot be returned by function using alias - 9 | } - 10 | - 11 | fn return_fixed_array() Abc { - | ~~~ - 12 | return [1, 2, 3]! - 13 | } diff --git a/vlib/v/checker/tests/return_fixed_array.vv b/vlib/v/checker/tests/return_fixed_array.vv deleted file mode 100644 index 66ec010d24..0000000000 --- a/vlib/v/checker/tests/return_fixed_array.vv +++ /dev/null @@ -1,13 +0,0 @@ -type Abc = [3]int - -fn return_fixed_array() [3]int { - return [1, 2, 3]! -} - -fn return_fixed_array_in_multi_return() ([3]int, [3]int) { - return [1, 2, 3]!, [4, 5, 6]! -} - -fn return_fixed_array() Abc { - return [1, 2, 3]! -} \ No newline at end of file diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 78d8f26bf0..80b6845a2a 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -578,9 +578,22 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } } if !is_used_var_styp { - if !val_type.has_flag(.option) && left_sym.info is ast.ArrayFixed - && left_sym.info.is_fn_ret { - g.write('${styp[3..]} ') + if !val_type.has_flag(.option) && left_sym.is_array_fixed() { + if left_sym.kind == .alias { + parent_sym := g.table.final_sym((left_sym.info as ast.Alias).parent_type) + styp = g.typ((left_sym.info as ast.Alias).parent_type) + if !parent_sym.is_array_fixed_ret() { + g.write('${styp} ') + } else { + g.write('${styp[3..]} ') + } + } else { + if !left_sym.is_array_fixed_ret() { + g.write('${styp} ') + } else { + g.write('${styp[3..]} ') + } + } } else { g.write('${styp} ') } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index c0dac59a0d..5f4fcab6d5 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4760,7 +4760,7 @@ fn (mut g Gen) return_stmt(node ast.Return) { fn_return_is_multi := sym.kind == .multi_return fn_return_is_option := fn_ret_type.has_flag(.option) fn_return_is_result := fn_ret_type.has_flag(.result) - fn_return_is_fixed_array := sym.kind == .array_fixed && !fn_ret_type.has_flag(.option) + fn_return_is_fixed_array := sym.is_array_fixed() && !fn_ret_type.has_flag(.option) mut has_semicolon := false if node.exprs.len == 0 { @@ -4782,6 +4782,8 @@ fn (mut g Gen) return_stmt(node ast.Return) { mut ret_typ := g.typ(g.unwrap_generic(fn_ret_type)) if fn_ret_type.has_flag(.generic) && fn_return_is_fixed_array { ret_typ = '_v_${ret_typ}' + } else if sym.kind == .alias && fn_return_is_fixed_array { + ret_typ = '_v_' + g.typ((sym.info as ast.Alias).parent_type) } mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0 || g.cur_lock.lockeds.len > 0 diff --git a/vlib/v/gen/c/dumpexpr.v b/vlib/v/gen/c/dumpexpr.v index 61a8071143..0dee88265d 100644 --- a/vlib/v/gen/c/dumpexpr.v +++ b/vlib/v/gen/c/dumpexpr.v @@ -100,6 +100,7 @@ fn (mut g Gen) dump_expr_definitions() { } str_dumparg_type += g.cc_type(dump_type, true) + ptr_asterisk } + mut is_fixed_arr_ret := false if dump_sym.kind == .function { fninfo := dump_sym.info as ast.FnType str_dumparg_type = 'DumpFNType_${name}' @@ -109,14 +110,30 @@ fn (mut g Gen) dump_expr_definitions() { g.go_back(str_tdef.len) dump_typedefs['typedef ${str_tdef};'] = true str_dumparg_ret_type = str_dumparg_type - } else if !typ.has_flag(.option) && dump_sym.kind == .array_fixed { - if (dump_sym.info as ast.ArrayFixed).is_fn_ret { - str_dumparg_ret_type = str_dumparg_type - str_dumparg_type = str_dumparg_type.trim_string_left('_v_') - } else { - // fixed array returned from function - str_dumparg_ret_type = '_v_' + str_dumparg_type + } else if !typ.has_flag(.option) && dump_sym.is_array_fixed() { + match dump_sym.kind { + .array_fixed { + if (dump_sym.info as ast.ArrayFixed).is_fn_ret { + str_dumparg_ret_type = str_dumparg_type + str_dumparg_type = str_dumparg_type.trim_string_left('_v_') + } else { + // fixed array returned from function + str_dumparg_ret_type = '_v_' + str_dumparg_type + } + } + .alias { + parent_sym := g.table.sym((dump_sym.info as ast.Alias).parent_type) + if parent_sym.kind == .array_fixed { + str_dumparg_ret_type = + if (parent_sym.info as ast.ArrayFixed).is_fn_ret { '' } else { '_v_' } + + g.cc_type((dump_sym.info as ast.Alias).parent_type, true) + str_dumparg_type = str_dumparg_ret_type.trim_string_left('_v_') + is_fixed_arr_ret = true + } + } + else {} } + is_fixed_arr_ret = true } else { str_dumparg_ret_type = str_dumparg_type } @@ -173,7 +190,7 @@ fn (mut g Gen) dump_expr_definitions() { dump_fns.writeln('\tstrings__Builder_write_string(&sb, value);') dump_fns.writeln("\tstrings__Builder_write_rune(&sb, '\\n');") surrounder.builder_write_afters(mut dump_fns) - if !typ.has_flag(.option) && dump_sym.kind == .array_fixed { + if is_fixed_arr_ret { tmp_var := g.new_tmp_var() dump_fns.writeln('\t${str_dumparg_ret_type} ${tmp_var} = {0};') dump_fns.writeln('\tmemcpy(${tmp_var}.ret_arr, dump_arg, sizeof(${str_dumparg_type}));') diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 846566e112..bd0bb9065a 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -225,8 +225,16 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) { mut name := g.c_fn_name(node) mut type_name := g.typ(g.unwrap_generic(node.return_type)) - if node.return_type.has_flag(.generic) && g.table.sym(node.return_type).kind == .array_fixed { + ret_sym := g.table.sym(node.return_type) + if node.return_type.has_flag(.generic) && ret_sym.kind == .array_fixed { type_name = '_v_${type_name}' + } else if ret_sym.kind == .alias && !node.return_type.has_flag(.option) { + unalias_typ := g.table.unaliased_type(node.return_type) + unalias_sym := g.table.sym(unalias_typ) + if unalias_sym.kind == .array_fixed { + type_name = if !(unalias_sym.info as ast.ArrayFixed).is_fn_ret { '_v_' } else { '' } + + g.typ(unalias_typ) + } } if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') && !node.is_main diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index 305817e6a3..b343c08588 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -64,6 +64,10 @@ fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Typ } } p.check(.rsbr) + p.fixed_array_dim++ + defer { + p.fixed_array_dim-- + } elem_type := p.parse_type() if elem_type.idx() == 0 { // error is handled by parse_type @@ -73,7 +77,7 @@ fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Typ p.error_with_pos('fixed size cannot be zero or negative', size_expr.pos()) } idx := p.table.find_or_register_array_fixed(elem_type, fixed_size, size_expr, - !is_option && p.inside_fn_return) + p.fixed_array_dim == 1 && !is_option && p.inside_fn_return) if elem_type.has_flag(.generic) { return ast.new_type(idx).set_flag(.generic) } @@ -705,6 +709,16 @@ fn (mut p Parser) find_type_or_add_placeholder(name string, language ast.Languag typ = ast.new_type(idx) } } + ast.Alias { + if p.inside_fn_return { + parent_sym := p.table.sym(sym.info.parent_type) + if parent_sym.kind == .array_fixed { + info := parent_sym.array_fixed_info() + typ = p.table.find_or_register_array_fixed(info.elem_type, info.size, + info.size_expr, p.inside_fn_return) + } + } + } else {} } return typ diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index ec37d71e22..c30a302bb7 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -65,6 +65,7 @@ mut: inside_map_init bool inside_orm bool inside_chan_decl bool + fixed_array_dim int // fixed array dim parsing level or_is_handled bool // ignore `or` in this expression builtin_mod bool // are we in the `builtin` module? mod string // current module name diff --git a/vlib/v/checker/tests/return_aliases_of_fixed_array.vv b/vlib/v/tests/return_aliases_of_fixed_array_test.v similarity index 64% rename from vlib/v/checker/tests/return_aliases_of_fixed_array.vv rename to vlib/v/tests/return_aliases_of_fixed_array_test.v index 2fe644e92d..2adc4da90d 100644 --- a/vlib/v/checker/tests/return_aliases_of_fixed_array.vv +++ b/vlib/v/tests/return_aliases_of_fixed_array_test.v @@ -1,10 +1,13 @@ type Mat = [2][2]int -fn main() { +fn test_main() { a := Mat([[1, 2]!, [3, 4]!]!) println(a.foo()) + z := a.foo() + assert z == [[1, 2]!, [3, 4]!]! } +// vfmt off fn (v Mat) foo() Mat { return v } @@ -12,3 +15,4 @@ fn (v Mat) foo() Mat { fn bar() Mat { return Mat([[1, 2]!, [3, 4]!]!) } +// vfmt on diff --git a/vlib/v/tests/return_fixed_array_test.v b/vlib/v/tests/return_fixed_array_test.v new file mode 100644 index 0000000000..a84eedae8d --- /dev/null +++ b/vlib/v/tests/return_fixed_array_test.v @@ -0,0 +1,25 @@ +type Abc = [3]int + +fn return_fixed_array() [3]int { + return [1, 2, 3]! +} + +fn return_fixed_array_in_multi_return() ([3]int, [3]int) { + return [1, 2, 3]!, [4, 5, 6]! +} + +// vfmt off +fn return_fixed_array_with_alias() Abc { + return [1, 2, 3]! +} +// vfmt on + +fn test_with_alias() { + a := return_fixed_array_with_alias() + assert a == [1, 2, 3]! +} + +fn test_without_alias() { + a := return_fixed_array() + assert a == [1, 2, 3]! +}