From 66a67de8c092f7715c7feabf51460b5246c4995a Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 2 Dec 2021 18:22:48 +0800 Subject: [PATCH] checker, cgen: fix match expr returning optional with error (fix #12556) (#12645) --- vlib/v/checker/checker.v | 6 +++--- vlib/v/gen/c/cgen.v | 19 +++++++++++++++---- .../match_expr_returning_optional_test.v | 14 ++++++++++++++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 3cfef671ff..4893f279b7 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -6265,14 +6265,14 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { } expr_type := c.expr(stmt.expr) if first_iteration { - if node.is_expr && !node.expected_type.has_flag(.optional) - && c.table.get_type_symbol(node.expected_type).kind == .sum_type { + if node.is_expr && (node.expected_type.has_flag(.optional) + || c.table.type_kind(node.expected_type) == .sum_type) { ret_type = node.expected_type } else { ret_type = expr_type } stmt.typ = expr_type - } else if node.is_expr && ret_type != expr_type { + } else if node.is_expr && ret_type.idx() != expr_type.idx() { if !c.check_types(ret_type, expr_type) && !c.check_types(expr_type, ret_type) { ret_sym := c.table.get_type_symbol(ret_type) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 2e1819c8fd..acdecba6f7 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -104,6 +104,7 @@ mut: inside_map_index bool inside_opt_data bool inside_if_optional bool + inside_match_optional bool loop_depth int ternary_names map[string]string ternary_level_names map[string][]string @@ -1372,7 +1373,7 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) { for i, stmt in stmts { if i == stmts.len - 1 && tmp_var != '' { // Handle if expressions, set the value of the last expression to the temp var. - if g.inside_if_optional { + if g.inside_if_optional || g.inside_match_optional { g.set_current_pos_as_last_stmt_pos() g.skip_stmt_pos = true if stmt is ast.ExprStmt { @@ -1412,7 +1413,7 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) { } } else { g.stmt(stmt) - if g.inside_if_optional && stmt is ast.ExprStmt { + if (g.inside_if_optional || g.inside_match_optional) && stmt is ast.ExprStmt { g.writeln(';') } } @@ -1624,8 +1625,8 @@ fn (mut g Gen) stmt(node ast.Stmt) { // if af { // g.autofree_call_postgen() // } - if g.inside_ternary == 0 && !g.inside_if_optional && !node.is_expr - && node.expr !is ast.IfExpr { + if g.inside_ternary == 0 && !g.inside_if_optional && !g.inside_match_optional + && !node.is_expr && node.expr !is ast.IfExpr { g.writeln(';') } } @@ -4377,6 +4378,9 @@ fn (mut g Gen) need_tmp_var_in_match(node ast.MatchExpr) bool { if g.table.type_kind(node.return_type) == .sum_type { return true } + if node.return_type.has_flag(.optional) { + return true + } if sym.kind == .multi_return { return false } @@ -4418,6 +4422,13 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) { if is_expr && !need_tmp_var { g.inside_ternary++ } + if is_expr && node.return_type.has_flag(.optional) { + old := g.inside_match_optional + defer { + g.inside_match_optional = old + } + g.inside_match_optional = true + } if node.cond in [ast.Ident, ast.SelectorExpr, ast.IntegerLiteral, ast.StringLiteral, ast.FloatLiteral] { cond_var = g.expr_string(node.cond) diff --git a/vlib/v/tests/match_expr_returning_optional_test.v b/vlib/v/tests/match_expr_returning_optional_test.v index 5156ac932a..708497d730 100644 --- a/vlib/v/tests/match_expr_returning_optional_test.v +++ b/vlib/v/tests/match_expr_returning_optional_test.v @@ -34,3 +34,17 @@ fn test_match_expr_returning_optional() { println(ret2) assert ret2 == Any(1) } + +fn func() ?string { + code := 0 + return match code { + 0 { 'zero' } + else { error('as we are returning an optional') } + } +} + +fn test_match_expr_returning_optional_with_error() { + ret := func() or { 'error' } + println(ret) + assert ret == 'zero' +}