diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 34c985ae78..6bb60cbb39 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1156,7 +1156,7 @@ pub fn (mut t Table) find_or_register_multi_return(mr_typs []Type) int { mut name := '(' mut cname := 'multi_return' for i, mr_typ in mr_typs { - mr_type_sym := t.sym(mr_typ) + mr_type_sym := t.sym(mktyp(mr_typ)) ref, cref := if mr_typ.is_ptr() { '&', 'ref_' } else { '', '' } name += '$ref$mr_type_sym.name' cname += '_$cref$mr_type_sym.cname' diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 4f5fd0feac..c8ef5617df 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -248,6 +248,20 @@ pub fn (mut c Checker) check_basic(got ast.Type, expected ast.Type) bool { return true } got_sym, exp_sym := c.table.sym(got), c.table.sym(expected) + // multi return + if exp_sym.kind == .multi_return && got_sym.kind == .multi_return { + exp_types := exp_sym.mr_info().types + got_types := got_sym.mr_info().types.map(ast.mktyp(it)) + if exp_types.len != got_types.len { + return false + } + for i in 0 .. exp_types.len { + if !c.check_types(got_types[i], exp_types[i]) { + return false + } + } + return true + } // array/map as argument if got_sym.kind in [.array, .map, .array_fixed] && exp_sym.kind == got_sym.kind { if c.table.type_to_str(got) == c.table.type_to_str(expected).trim('&') { diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index 608abd5c9e..bc2613e10a 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -217,16 +217,6 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { if is_noreturn_callexpr(last_expr.expr) { continue } - node_sym := c.table.sym(node.typ) - last_sym := c.table.sym(last_expr.typ) - if node_sym.kind == .multi_return && last_sym.kind == .multi_return { - node_types := node_sym.mr_info().types - last_types := last_sym.mr_info().types.map(ast.mktyp(it)) - if node_types == last_types { - continue - } - } - c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`', node.pos) } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 3fa4d7a5c0..e0e6bf8cbb 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -195,6 +195,7 @@ mut: referenced_fns shared map[string]bool // functions that have been referenced nr_closures int expected_cast_type ast.Type // for match expr of sumtypes + or_expr_return_type ast.Type // or { 0, 1 } return type anon_fn bool tests_inited bool has_main bool @@ -3864,6 +3865,8 @@ fn (mut g Gen) concat_expr(node ast.ConcatExpr) { mut styp := g.typ(node.return_type) if g.inside_return { styp = g.typ(g.fn_decl.return_type) + } else if g.inside_or_block { + styp = g.typ(g.or_expr_return_type) } sym := g.table.sym(node.return_type) is_multi := sym.kind == .multi_return @@ -4933,6 +4936,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty g.writeln('if (${cvar_name}.state != 0) { /*or block*/ ') } if or_block.kind == .block { + g.or_expr_return_type = return_type.clear_flag(.optional) if g.inside_or_block { g.writeln('\terr = ${cvar_name}.err;') } else { @@ -4970,6 +4974,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty g.writeln(';') } } + g.or_expr_return_type = ast.void_type } else if or_block.kind == .propagate { if g.file.mod.name == 'main' && (isnil(g.fn_decl) || g.fn_decl.is_main) { // In main(), an `opt()?` call is sugar for `opt() or { panic(err) }` diff --git a/vlib/v/tests/multiret_in_or_expr_test.v b/vlib/v/tests/multiret_in_or_expr_test.v new file mode 100644 index 0000000000..de6c660764 --- /dev/null +++ b/vlib/v/tests/multiret_in_or_expr_test.v @@ -0,0 +1,31 @@ +fn multi_return1() ?(int, int) { + return 1, 2 +} + +fn multi_return2() ?(i64, i64) { + return 11, 22 +} + +fn multi_return3() ?(int, i64) { + return 11, 22 +} + +fn test_multi_return_in_or_expr() { + a1, b1 := multi_return1() or { 0, -1 } + + println('$a1, $b1') + assert a1 == 1 + assert b1 == 2 + + a2, b2 := multi_return2() or { 0, -1 } + + println('$a2, $b2') + assert a2 == 11 + assert b2 == 22 + + a3, b3 := multi_return3() or { 0, -1 } + + println('$a3, $b3') + assert a3 == 11 + assert b3 == 22 +}