Skip to content

Commit

Permalink
checker, cgen: fix fixed array return on assigning, arg pass and dump…
Browse files Browse the repository at this point in the history
…ing (#18216)
  • Loading branch information
felipensp committed May 25, 2023
1 parent f1c647c commit 64a4a33
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 6 deletions.
11 changes: 9 additions & 2 deletions vlib/v/checker/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,24 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
&& node.left[i] in [ast.Ident, ast.SelectorExpr] && !node.left[i].is_blank_ident() {
c.expected_type = c.expr(node.left[i])
}
right_type := c.expr(right)
mut right_type := c.expr(right)
if right in [ast.CallExpr, ast.IfExpr, ast.LockExpr, ast.MatchExpr, ast.DumpExpr] {
c.fail_if_unreadable(right, right_type, 'right-hand side of assignment')
}
right_type_sym := c.table.sym(right_type)
// fixed array returns an struct, but when assigning it must be the array type
if right_type_sym.kind == .array_fixed
&& (right_type_sym.info as ast.ArrayFixed).is_fn_ret {
info := right_type_sym.info as ast.ArrayFixed
right_type = c.table.find_or_register_array_fixed(info.elem_type, info.size,
info.size_expr, false)
}
if i == 0 {
right_type0 = right_type
node.right_types = [
c.check_expr_opt_call(right, right_type0),
]
}
right_type_sym := c.table.sym(right_type)
if right_type_sym.kind == .multi_return {
if node.right.len > 1 {
c.error('cannot use multi-value ${right_type_sym.name} in single-value context',
Expand Down
3 changes: 2 additions & 1 deletion vlib/v/gen/c/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
right_sym := g.table.sym(unwrapped_val_type)
unaliased_right_sym := g.table.final_sym(unwrapped_val_type)
is_fixed_array_var := unaliased_right_sym.kind == .array_fixed && val !is ast.ArrayInit
&& (val in [ast.Ident, ast.IndexExpr, ast.CallExpr, ast.SelectorExpr]
&& (val in [ast.Ident, ast.IndexExpr, ast.CallExpr, ast.SelectorExpr, ast.DumpExpr]
|| (val is ast.CastExpr && (val as ast.CastExpr).expr !is ast.ArrayInit)
|| (val is ast.UnsafeExpr && (val as ast.UnsafeExpr).expr is ast.Ident))
&& !g.pref.translated
Expand Down Expand Up @@ -631,6 +631,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
&& (val as ast.CallExpr).or_block.kind == .propagate_option)
&& ((right_sym.info is ast.ArrayFixed
&& (right_sym.info as ast.ArrayFixed).is_fn_ret)
|| (val is ast.DumpExpr && right_sym.info is ast.ArrayFixed)
|| (val is ast.CallExpr
&& g.table.sym(g.unwrap_generic((val as ast.CallExpr).return_type)).kind == .array_fixed))
typ_str := g.typ(val_type).trim('*')
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -2441,6 +2441,9 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
}
// no cast
g.expr(expr)
if expr is ast.CallExpr && exp_sym.kind == .array_fixed {
g.write('.ret_arr')
}
}

fn write_octal_escape(mut b strings.Builder, c u8) {
Expand Down
20 changes: 17 additions & 3 deletions vlib/v/gen/c/dumpexpr.v
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ fn (mut g Gen) dump_expr_definitions() {
to_string_fn_name := g.get_str_fn(typ.clear_flags(.shared_f, .result))
mut ptr_asterisk := if is_ptr { '*'.repeat(typ.nr_muls()) } else { '' }
mut str_dumparg_type := ''
mut str_dumparg_ret_type := ''
if dump_sym.kind == .none_ {
str_dumparg_type = 'IError' + ptr_asterisk
} else {
Expand All @@ -103,11 +104,17 @@ fn (mut g Gen) dump_expr_definitions() {
str_tdef := g.out.after(tdef_pos)
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 {
// fixed array returned from function
str_dumparg_ret_type = '_v_' + str_dumparg_type
} else {
str_dumparg_ret_type = str_dumparg_type
}
dump_fn_name := '_v_dump_expr_${name}' +
(if is_ptr { '_ptr'.repeat(typ.nr_muls()) } else { '' })
dump_fn_defs.writeln('${str_dumparg_type} ${dump_fn_name}(string fpath, int line, string sexpr, ${str_dumparg_type} dump_arg);')
if g.writeln_fn_header('${str_dumparg_type} ${dump_fn_name}(string fpath, int line, string sexpr, ${str_dumparg_type} dump_arg)', mut
dump_fn_defs.writeln('${str_dumparg_ret_type} ${dump_fn_name}(string fpath, int line, string sexpr, ${str_dumparg_type} dump_arg);')
if g.writeln_fn_header('${str_dumparg_ret_type} ${dump_fn_name}(string fpath, int line, string sexpr, ${str_dumparg_type} dump_arg)', mut
dump_fns)
{
continue
Expand Down Expand Up @@ -157,7 +164,14 @@ 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)
dump_fns.writeln('\treturn dump_arg;')
if !typ.has_flag(.option) && dump_sym.kind == .array_fixed {
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}));')
dump_fns.writeln('\treturn ${tmp_var};')
} else {
dump_fns.writeln('\treturn dump_arg;')
}
dump_fns.writeln('}')
}
for tdef, _ in dump_typedefs {
Expand Down
25 changes: 25 additions & 0 deletions vlib/v/tests/fn_fixed_array_ret_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,28 @@ fn test_inline() {
mut a := [1, 2, 3, 4]!
assert four(a)[1] == 2
}

fn f() [4]int {
return [1, 2, 3, 4]!
}

fn test_simple_ret() {
zzz := f()
dump(zzz)
dump(zzz[0])
}

fn g(a [4]int) {
}

fn test_arg_fixed() {
zzz := f()
g(zzz)
g(f())
}

fn test_dump_ret() {
zzz := f()
a := dump(zzz)
b := dump(zzz[0])
}

0 comments on commit 64a4a33

Please sign in to comment.