From 77e45946f2a197462d5c7f7f7237ac2915bdfa9c Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Wed, 11 Dec 2024 11:07:39 -0300 Subject: [PATCH] cgen: fix different option alias type as fn arg (fix #23086) (#23131) --- vlib/v/gen/c/assign.v | 57 ++++++++++++++----- vlib/v/gen/c/fn.v | 6 +- .../options/option_diff_alias_arg_test.v | 18 ++++++ 3 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 vlib/v/tests/options/option_diff_alias_arg_test.v diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index f05fbc719..de19911bf 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -54,6 +54,38 @@ fn (mut g Gen) expr_with_opt_or_block(expr ast.Expr, expr_typ ast.Type, var_expr } } +// expr_opt_with_alias handles conversion from different option alias type name +fn (mut g Gen) expr_opt_with_alias(expr ast.Expr, expr_typ ast.Type, ret_typ ast.Type, tmp_var string) string { + styp := g.base_type(ret_typ) + + line := g.go_before_last_stmt().trim_space() + g.empty_line = true + + ret_var := g.new_tmp_var() + ret_styp := g.styp(ret_typ).replace('*', '_ptr') + g.writeln('${ret_styp} ${ret_var} = {0};') + + g.write('_option_clone((${option_name}*)') + has_addr := expr !in [ast.Ident, ast.SelectorExpr] + if has_addr { + expr_styp := g.styp(expr_typ).replace('*', '_ptr') + g.write('ADDR(${expr_styp}, ') + } else { + g.write('&') + } + g.expr(expr) + if has_addr { + g.write(')') + } + g.writeln(', (${option_name}*)&${ret_var}, sizeof(${styp}));') + g.write(line) + if g.inside_return { + g.write(' ') + } + g.write(ret_var) + return ret_var +} + // expr_opt_with_cast is used in cast expr when converting compatible option types // e.g. ?int(?u8(0)) fn (mut g Gen) expr_opt_with_cast(expr ast.Expr, expr_typ ast.Type, ret_typ ast.Type) string { @@ -64,22 +96,17 @@ fn (mut g Gen) expr_opt_with_cast(expr ast.Expr, expr_typ ast.Type, ret_typ ast. if expr_typ.idx() == ret_typ.idx() && g.table.sym(expr_typ).kind != .alias { return g.expr_with_opt(expr, expr_typ, ret_typ) } else { - past := g.past_tmp_var_new() - defer { - g.past_tmp_var_done(past) - } - styp := g.base_type(ret_typ) - decl_styp := g.styp(ret_typ).replace('*', '_ptr') - g.writeln('${decl_styp} ${past.tmp_var};') - is_none := expr is ast.CastExpr && expr.expr is ast.None if expr is ast.CallExpr && expr.return_type.has_flag(.option) { - tmp_var := g.new_tmp_var() - ret_styp := g.styp(expr.return_type).replace('*', '_ptr') - g.write('${ret_styp} ${tmp_var} = ') - g.expr(expr) - g.writeln(';') - g.writeln('_option_clone(&${tmp_var}, (${option_name}*)(&${past.tmp_var}), sizeof(${styp}));') + return g.expr_opt_with_alias(expr, expr_typ, ret_typ, '') } else { + past := g.past_tmp_var_new() + defer { + g.past_tmp_var_done(past) + } + styp := g.base_type(ret_typ) + decl_styp := g.styp(ret_typ).replace('*', '_ptr') + g.writeln('${decl_styp} ${past.tmp_var};') + is_none := expr is ast.CastExpr && expr.expr is ast.None if is_none { g.write('_option_none(&(${styp}[]) {') } else { @@ -96,8 +123,8 @@ fn (mut g Gen) expr_opt_with_cast(expr ast.Expr, expr_typ ast.Type, ret_typ ast. g.inside_opt_or_res = old_inside_opt_or_res } g.writeln(' }, (${option_name}*)(&${past.tmp_var}), sizeof(${styp}));') + return past.tmp_var } - return past.tmp_var } } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index ad41726ba..92ee090eb 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -2946,7 +2946,11 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as g.write('->val') return } else if expected_type.has_flag(.option) { - g.expr_with_opt(arg.expr, arg_typ, expected_type) + if arg_sym.info is ast.Alias && expected_type != arg_typ { + g.expr_opt_with_alias(arg.expr, arg_typ, expected_type, '') + } else { + g.expr_with_opt(arg.expr, arg_typ, expected_type) + } return } else if arg.expr is ast.ArrayInit { if arg.expr.is_fixed { diff --git a/vlib/v/tests/options/option_diff_alias_arg_test.v b/vlib/v/tests/options/option_diff_alias_arg_test.v new file mode 100644 index 000000000..fc17c6ab1 --- /dev/null +++ b/vlib/v/tests/options/option_diff_alias_arg_test.v @@ -0,0 +1,18 @@ +import time + +struct Foo[T] { +pub: + value ?T +} + +fn t(x ?i64) i64 { + return x or { -1 } +} + +fn test_main() { + bar := Foo[time.Duration]{ + value: time.Duration(0) + } + + assert t(bar.value) == 0 +} -- 2.39.5