diff --git a/vlib/v/gen/c/match.v b/vlib/v/gen/c/match.v index 1b458831e8..4104d31a45 100644 --- a/vlib/v/gen/c/match.v +++ b/vlib/v/gen/c/match.v @@ -81,7 +81,7 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) { '' } cond_var = g.new_tmp_var() - g.write('${g.typ(node.cond_type)} /*A*/ ${cond_var} = ') + g.write('${g.typ(node.cond_type)} ${cond_var} = ') g.expr(node.cond) g.writeln(';') g.set_current_pos_as_last_stmt_pos() @@ -419,6 +419,8 @@ fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var str node_cond_type_unsigned := node.cond_type in [ast.u16_type, ast.u32_type, ast.u64_type] type_sym := g.table.final_sym(node.cond_type) use_ternary := is_expr && tmp_var == '' + mut reset_if := false + mut has_goto := false for j, branch in node.branches { is_last := j == node.branches.len - 1 if branch.is_else || (use_ternary && is_last) { @@ -439,7 +441,11 @@ fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var str } else { g.writeln('') g.write_v_source_line_info(branch) - g.write('else ') + if !reset_if { + g.write('else ') + } else { + reset_if = false + } } } if use_ternary { @@ -451,6 +457,7 @@ fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var str g.write_v_source_line_info(branch) g.write('if (') } + reset_if = branch.exprs.any(g.match_must_reset_if(it)) for i, expr in branch.exprs { if i > 0 { g.write(' || ') @@ -532,7 +539,33 @@ fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var str g.stmts_with_tmp_var(branch.stmts, tmp_var) g.expected_cast_type = 0 if g.inside_ternary == 0 && node.branches.len >= 1 { - g.write('}') + if reset_if { + has_goto = true + g.writeln('\tgoto end_block_${node.pos.line_nr};') + g.writeln('}') + g.set_current_pos_as_last_stmt_pos() + } else { + g.write('}') + } + } + } + if has_goto { + g.writeln('end_block_${node.pos.line_nr}: {}') + g.set_current_pos_as_last_stmt_pos() + } +} + +// match_must_reset_if checks if codegen must break the if-elseif sequence in another if expr +fn (mut g Gen) match_must_reset_if(node ast.Expr) bool { + return match node { + ast.CallExpr { + node.or_block.kind != .absent + } + ast.InfixExpr { + g.match_must_reset_if(node.left) || g.match_must_reset_if(node.right) + } + else { + false } } } diff --git a/vlib/v/tests/match_expr_result_test.v b/vlib/v/tests/match_expr_result_test.v new file mode 100644 index 0000000000..d504e32944 --- /dev/null +++ b/vlib/v/tests/match_expr_result_test.v @@ -0,0 +1,23 @@ +fn try(this string) !bool { + return true +} + +fn test_case1() { + a, b := match true { + try('foo')! { 'a', 'b' } + try('bar')! { 'c', 'd' } + else { 'e', 'f' } + } + assert a == 'a' + assert b == 'b' +} + +fn test_case2() { + a, b := match true { + try('foo')! && try('foo') or { false } { 'a', 'b' } + try('bar') or { false } { 'c', 'd' } + else { 'e', 'f' } + } + assert a == 'a' + assert b == 'b' +}