From 7e8723d6033df8467f0eb06ca664e088e66488c2 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Thu, 16 Mar 2023 07:59:49 -0300 Subject: [PATCH] cgen: fix multi return assignment with option (#17676) --- vlib/v/gen/c/assign.v | 46 ++++++++++++++++++++-------- vlib/v/tests/option_multi_ret_test.v | 41 +++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 vlib/v/tests/option_multi_ret_test.v diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index ae6fc02ae6..97f1fa5273 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -174,7 +174,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { if return_type != ast.void_type && return_type != 0 { sym := g.table.sym(return_type) if sym.kind == .multi_return { - g.gen_multi_return_assign(node, return_type) + g.gen_multi_return_assign(node, return_type, sym) return } } @@ -668,7 +668,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } } -fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Type) { +fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Type, return_sym ast.TypeSymbol) { // multi return // TODO Handle in if_expr mr_var_name := 'mr_${node.pos.pos}' @@ -681,6 +681,7 @@ fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Typ g.write('${mr_styp} ${mr_var_name} = ') g.expr(node.right[0]) g.writeln(';') + mr_types := (return_sym.info as ast.MultiReturn).types for i, lx in node.left { mut is_auto_heap := false mut ident := ast.Ident{ @@ -702,23 +703,42 @@ fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Typ if lx.is_auto_deref_var() { g.write('*') } - g.expr(lx) noscan := if is_auto_heap { g.check_noscan(return_type) } else { '' } - if g.is_arraymap_set { - if is_auto_heap { - g.writeln('HEAP${noscan}(${styp}, ${mr_var_name}.arg${i}) });') + if node.left_types[i].has_flag(.option) { + base_typ := g.base_type(node.left_types[i]) + tmp_var := if is_auto_heap { + 'HEAP${noscan}(${styp}, ${mr_var_name}.arg${i})' } else if is_option { - g.writeln('(*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i} });') + '(*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i}' } else { - g.writeln('${mr_var_name}.arg${i} });') + '${mr_var_name}.arg${i}' + } + if mr_types[i].has_flag(.option) { + g.expr(lx) + g.write(' = ${tmp_var};') + } else { + g.write('_option_ok(&(${base_typ}[]) { ${tmp_var} }, (${option_name}*)(&') + g.expr(lx) + g.writeln('), sizeof(${base_typ}));') } } else { - if is_auto_heap { - g.writeln(' = HEAP${noscan}(${styp}, ${mr_var_name}.arg${i});') - } else if is_option { - g.writeln(' = (*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i};') + g.expr(lx) + if g.is_arraymap_set { + if is_auto_heap { + g.writeln('HEAP${noscan}(${styp}, ${mr_var_name}.arg${i}) });') + } else if is_option { + g.writeln('(*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i} });') + } else { + g.writeln('${mr_var_name}.arg${i} });') + } } else { - g.writeln(' = ${mr_var_name}.arg${i};') + if is_auto_heap { + g.writeln(' = HEAP${noscan}(${styp}, ${mr_var_name}.arg${i});') + } else if is_option { + g.writeln(' = (*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i};') + } else { + g.writeln(' = ${mr_var_name}.arg${i};') + } } } } diff --git a/vlib/v/tests/option_multi_ret_test.v b/vlib/v/tests/option_multi_ret_test.v new file mode 100644 index 0000000000..5961538b67 --- /dev/null +++ b/vlib/v/tests/option_multi_ret_test.v @@ -0,0 +1,41 @@ +struct Test { +mut: + a ?int + b ?string + c ?[]int +} + +fn mr_1() (?int, string, []int) { + return 456, 'foo', [1] +} + +fn mr_2() (?int, string, []int) { + return none, 'zoo', [99] +} + +fn mr_3() ([]?int, ?int) { + return [?int(456)], none +} + +fn test_mr_first_option() { + mut t := Test{} + t.a, t.b, t.c = mr_1() + assert t.a? == 456 + assert t.b? == 'foo' + assert t.c? == [1] +} + +fn test_mr_first_option_none() { + mut t := Test{} + t.a, t.b, t.c = mr_2() + assert t.a == none + assert t.b? == 'zoo' + assert t.c? == [99] +} + +fn test_mr_first_option_array() { + a, b := mr_3() + t := a[0] + assert t? == 456 + assert b == none +}