diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 8fc72b9589..1037198a02 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1191,7 +1191,11 @@ pub fn (mut t Table) find_or_register_multi_return(mr_typs []Type) int { for i, mr_typ in mr_typs { mr_type_sym := t.sym(mktyp(mr_typ)) ref, cref := if mr_typ.is_ptr() { '&', 'ref_' } else { '', '' } + name += if mr_typ.has_flag(.option) { '?' } else { '' } + name += if mr_typ.has_flag(.result) { '!' } else { '' } name += '${ref}${mr_type_sym.name}' + cname += if mr_typ.has_flag(.option) { '_option' } else { '' } + cname += if mr_typ.has_flag(.result) { '_result' } else { '' } cname += '_${cref}${mr_type_sym.cname}' if i < mr_typs.len - 1 { name += ', ' diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index f0edf4054a..f1d4ad3fce 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -652,7 +652,12 @@ fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Typ // multi return // TODO Handle in if_expr mr_var_name := 'mr_${node.pos.pos}' - mr_styp := g.typ(return_type.clear_flag(.option).clear_flag(.result)) + mut is_option := return_type.has_flag(.option) + mut mr_styp := g.typ(return_type.clear_flag(.result)) + if node.right[0] is ast.CallExpr && (node.right[0] as ast.CallExpr).or_block.kind != .absent { + is_option = false + mr_styp = g.typ(return_type.clear_flag(.option).clear_flag(.result)) + } g.write('${mr_styp} ${mr_var_name} = ') g.expr(node.right[0]) g.writeln(';') @@ -682,12 +687,16 @@ fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Typ 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 { 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/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 7ddc4c0c8e..c1308b3750 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4563,6 +4563,7 @@ fn (mut g Gen) return_stmt(node ast.Return) { ret_typ := g.typ(g.unwrap_generic(fn_ret_type)) mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0 || g.cur_lock.lockeds.len > 0 + || (fn_return_is_multi && node.exprs.len >= 1 && fn_return_is_option) // handle promoting none/error/function returning _option' if fn_return_is_option { option_none := node.exprs[0] is ast.None @@ -4586,6 +4587,17 @@ fn (mut g Gen) return_stmt(node ast.Return) { g.gen_option_error(fn_ret_type, node.exprs[0]) g.writeln(';') if use_tmp_var { + // handle options when returning `none` for `?(int, ?int)` + if fn_return_is_multi && node.exprs.len >= 1 { + mr_info := sym.info as ast.MultiReturn + for i in 0 .. mr_info.types.len { + if mr_info.types[i].has_flag(.option) { + g.write('(*(${g.base_type(fn_ret_type)}*)${tmpvar}.data).arg${i} = ') + g.gen_option_error(mr_info.types[i], ast.None{}) + g.writeln(';') + } + } + } g.write_defer_stmts_when_needed() g.writeln('return ${tmpvar};') } @@ -4631,8 +4643,7 @@ fn (mut g Gen) return_stmt(node ast.Return) { g.writeln('return ${tmpvar};') return } - typ_sym := g.table.sym(g.fn_decl.return_type) - mr_info := typ_sym.info as ast.MultiReturn + mr_info := sym.info as ast.MultiReturn mut styp := '' if fn_return_is_option { g.writeln('${ret_typ} ${tmpvar};') @@ -4699,10 +4710,11 @@ fn (mut g Gen) return_stmt(node ast.Return) { } else { g.expr(expr) } - arg_idx++ + if i < node.exprs.len - 1 { g.write(', ') } + arg_idx++ } g.write('}') if fn_return_is_option { diff --git a/vlib/v/tests/option_multi_return_test.v b/vlib/v/tests/option_multi_return_test.v index 89cc8db689..0c31a2fa73 100644 --- a/vlib/v/tests/option_multi_return_test.v +++ b/vlib/v/tests/option_multi_return_test.v @@ -1,10 +1,61 @@ +struct MmapRangeLocal {} + +fn addr2range() ?(&MmapRangeLocal, ?u64, u64) { + return none +} + +fn foo(val ?int) (?int, ?int) { + return val, none +} + +fn test_multi_return() { + a, b := foo(100) + assert a == 100 + assert b == none +} + fn tuple() ?(int, int) { return 1, 2 } -fn test_option_multi_return() { - println(tuple()?) - a, b := tuple()? +fn tuple2() ?(string, int) { + return '', 2 +} + +fn tuple3() ?(?int, ?int) { + return none, none +} + +fn tuple4() ?(?int, ?int) { + return none +} + +fn test_tuple_1() { + a, b := tuple() assert a == 1 assert b == 2 } + +fn test_tuple_2() { + a, b := tuple2() + assert a == '' + assert b == 2 +} + +fn test_tuple_3() { + a, b := tuple3() + assert a == none + assert b == none +} + +fn test_tuple_4() { + a, b := tuple4() + assert a == none + assert b == none +} + +fn test_none_ret() { + _, b, c := addr2range() + assert b == none + assert c == 0 +}