From e8d98e10adf3749e80ed48f8a6b88854d9b5bc0f Mon Sep 17 00:00:00 2001 From: Krchi <997054144@qq.com> Date: Thu, 25 Dec 2025 18:22:05 +0800 Subject: [PATCH] cgen: clean code in return stmt (fix #25968) (#26118) --- vlib/v/gen/c/cgen.v | 87 ++++++++----------- .../gen/c/testdata/autofree_toml.c.must_have | 2 +- ...ed_array_return_fn_propagate_result_test.v | 33 +++++++ 3 files changed, 70 insertions(+), 52 deletions(-) create mode 100644 vlib/v/tests/fns/fn_return_result_fixed_array_return_fn_propagate_result_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 71d2adafb..65ee1276d 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2359,10 +2359,16 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T panic('cgen: parameter `ret_typ` of function `expr_with_tmp_var()` must be an Option or Result') } + assign_op := g.assign_op + defer { + g.assign_op = assign_op + } + g.assign_op = .unknown stmt_str := g.go_before_last_stmt().trim_space() mut styp := g.base_type(ret_typ) g.empty_line = true final_expr_sym := g.table.final_sym(expr_typ) + mut expected_type := ret_typ if final_expr_sym.kind == .none { g.write('${g.styp(ret_typ)} ${tmp_var} = ') @@ -2435,11 +2441,6 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T && (expr.right as ast.StructInit).init_fields.len == 0 { g.write('builtin___option_none(&(${styp}[]) { ') } else if final_expr_sym.kind == .array_fixed { - assign_op := g.assign_op - defer(fn) { - g.assign_op = assign_op - } - g.assign_op = .unknown expr_is_fixed_array_var = true info := final_expr_sym.array_fixed_info() mut no_cast := false @@ -2486,10 +2487,29 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T } } } else { - g.write('builtin___result_ok(&(${styp}[]) { ') + if final_expr_sym.kind == .array_fixed { + expr_is_fixed_array_var = true + info := final_expr_sym.array_fixed_info() + mut no_cast := false + if expr in [ast.CastExpr, ast.CallExpr, ast.Ident, ast.SelectorExpr] { + no_cast = true + } + elem_sym := g.table.sym(info.elem_type) + if elem_sym.kind == .struct { + expr_is_fixed_array_var = false + g.write('builtin___result_ok(&(${styp}[]) { ') + } else if no_cast { + g.write('builtin___result_ok(') + } else { + g.write('builtin___result_ok((${g.styp(final_expr_sym.idx)})') + } + } else { + g.write('builtin___result_ok(&(${styp}[]) { ') + expected_type = ret_typ.clear_flag(.result) + } } if !already_generated { - g.expr_with_cast(expr, expr_typ, ret_typ) + g.expr_with_cast(expr, expr_typ, expected_type) } if fn_option_clone { @@ -2504,7 +2524,11 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T g.writeln(' }, (${option_name}*)(&${tmp_var}), sizeof(${styp}));') } } else { - g.writeln(' }, (${result_name}*)(&${tmp_var}), sizeof(${styp}));') + if expr_is_fixed_array_var { + g.writeln(', (${result_name}*)(&${tmp_var}), sizeof(${styp}));') + } else { + g.writeln(' }, (${result_name}*)(&${tmp_var}), sizeof(${styp}));') + } } g.set_current_pos_as_last_stmt_pos() } @@ -6444,17 +6468,6 @@ fn (mut g Gen) return_stmt(node ast.Return) { type0.has_flag(.option) } } - if fn_return_is_option && !expr_type_is_opt && return_sym.name != option_name { - g.expr_with_tmp_var(expr0, type0, fn_ret_type, tmpvar, false) - g.writeln('') - g.write_defer_stmts_when_needed(node.scope, true, node.pos) - if g.is_autofree { - g.detect_used_var_on_return(expr0) - } - g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true) - g.writeln('return ${tmpvar};') - return - } expr_type_is_result := match expr0 { ast.CallExpr { expr0.return_type.has_flag(.result) && expr0.or_block.kind == .absent @@ -6463,38 +6476,10 @@ fn (mut g Gen) return_stmt(node ast.Return) { type0.has_flag(.result) } } - if fn_return_is_result && !expr_type_is_result && return_sym.name != result_name { - g.writeln('${ret_typ} ${tmpvar} = {0};') - if fn_return_is_fixed_array && expr0 !is ast.ArrayInit - && g.table.final_sym(type0).kind == .array_fixed { - styp := g.styp(fn_ret_type.clear_option_and_result()) - g.write('memcpy(${tmpvar}.data, ') - if expr0 in [ast.CallExpr, ast.StructInit] { - g.expr_with_opt(expr0, type0, fn_ret_type) - g.write('.data') - } else { - g.expr(expr0) - } - g.writeln(', sizeof(${styp}));') - } else { - styp := g.base_type(fn_ret_type) - g.write('builtin___result_ok(&(${styp}[]) { ') - if !fn_ret_type.is_ptr() && type0.is_ptr() { - if !((expr0 is ast.Ident && !g.is_amp) || sym.kind == .interface) { - g.write('*') - } - } - if fn_ret_type.has_flag(.option) { - g.expr_with_opt(expr0, type0, fn_ret_type.clear_flag(.result)) - } else if return_sym.kind == .array_fixed && expr0 !is ast.ArrayInit { - info := return_sym.info as ast.ArrayFixed - g.fixed_array_var_init(g.expr_string(expr0), expr0.is_auto_deref_var(), - info.elem_type, info.size) - } else { - g.expr_with_cast(expr0, type0, fn_ret_type.clear_flag(.result)) - } - g.writeln(' }, (${result_name}*)(&${tmpvar}), sizeof(${styp}));') - } + if (fn_return_is_option && !expr_type_is_opt && return_sym.name != option_name) + || (fn_return_is_result && !expr_type_is_result && return_sym.name != result_name) { + g.expr_with_tmp_var(expr0, type0, fn_ret_type, tmpvar, false) + g.writeln('') g.write_defer_stmts_when_needed(node.scope, true, node.pos) if g.is_autofree { g.detect_used_var_on_return(expr0) diff --git a/vlib/v/gen/c/testdata/autofree_toml.c.must_have b/vlib/v/gen/c/testdata/autofree_toml.c.must_have index 15ce0a8b8..4894be520 100644 --- a/vlib/v/gen/c/testdata/autofree_toml.c.must_have +++ b/vlib/v/gen/c/testdata/autofree_toml.c.must_have @@ -1,5 +1,5 @@ _result_toml__scanner__Scanner_ptr toml__scanner__new_scanner(toml__scanner__Config config) { - _result_toml__scanner__Scanner_ptr _t3 = {0}; + _result_toml__scanner__Scanner_ptr _t3; builtin___result_ok(&(toml__scanner__Scanner*[]) { s }, (_result*)(&_t3), sizeof(toml__scanner__Scanner*)); return _t3; } diff --git a/vlib/v/tests/fns/fn_return_result_fixed_array_return_fn_propagate_result_test.v b/vlib/v/tests/fns/fn_return_result_fixed_array_return_fn_propagate_result_test.v new file mode 100644 index 000000000..5211bcf90 --- /dev/null +++ b/vlib/v/tests/fns/fn_return_result_fixed_array_return_fn_propagate_result_test.v @@ -0,0 +1,33 @@ +import strconv + +pub fn valid_triangle(a u8, b u8, c u8) ![3]u8 { + if int(a) + int(b) <= int(c) { + return error('Invalid: a + b <= c') + } + if int(b) + int(c) <= int(a) { + return error('Invalid: b + c <= a') + } + if int(c) + int(a) <= int(b) { + return error('Invalid: c + a <= b') + } + return [a, b, c]! +} + +pub fn triangle_from_string(sides string) ![3]u8 { + s := sides.split(',') + if s.len != 3 { + return error('Invalid: number of sides') + } + a := strconv.atou8(s[0])! + b := strconv.atou8(s[1])! + c := strconv.atou8(s[2])! + // warning: don't append `!` to next call + // will confuse with fixed and return `garbage`. + return valid_triangle(a, b, c)! +} + +fn test_main() { + assert triangle_from_string('3,4,5')![0] == 3 + assert triangle_from_string('3,4,5')![1] == 4 + assert triangle_from_string('3,4,5')![2] == 5 +} -- 2.39.5