diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index 2b4bc04515..cb597bd43d 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -41,6 +41,7 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { mut ret_type := ast.void_type mut nbranches_with_return := 0 mut nbranches_without_return := 0 + mut must_be_option := false for mut branch in node.branches { if node.is_expr { c.stmts_ending_with_expression(mut branch.stmts, c.expected_or_type) @@ -77,6 +78,7 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { c.expr(mut stmt.expr) }) unwrapped_expected_type := c.unwrap_generic(node.expected_type) + must_be_option = must_be_option || expr_type == ast.none_type stmt.typ = expr_type if first_iteration { if unwrapped_expected_type.has_option_or_result() @@ -127,6 +129,9 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { } } } + if must_be_option && ret_type == ast.none_type && expr_type != ret_type { + ret_type = expr_type.set_flag(.option) + } if stmt.typ != ast.error_type && !is_noreturn_callexpr(stmt.expr) { ret_sym := c.table.sym(ret_type) stmt_sym := c.table.sym(stmt.typ) @@ -249,7 +254,7 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { c.error('invalid match expression, must supply at least one value other than `none`', node.pos) } - node.return_type = ret_type + node.return_type = if must_be_option { ret_type.set_flag(.option) } else { ret_type } cond_var := c.get_base_name(&node.cond) if cond_var != '' { mut cond_is_auto_heap := false @@ -268,7 +273,7 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { } } } - return ret_type + return node.return_type } fn (mut c Checker) check_match_branch_last_stmt(last_stmt ast.ExprStmt, ret_type ast.Type, expr_type ast.Type) { @@ -285,8 +290,10 @@ fn (mut c Checker) check_match_branch_last_stmt(last_stmt ast.ExprStmt, ret_type return } } - c.error('return type mismatch, it should be `${ret_sym.name}`, but it is instead `${c.table.type_to_str(expr_type)}`', - last_stmt.pos) + if expr_type != ast.none_type && ret_type != ast.none_type { + c.error('return type mismatch, it should be `${ret_sym.name}`, but it is instead `${c.table.type_to_str(expr_type)}`', + last_stmt.pos) + } } } else if expr_type == ast.void_type && ret_type.idx() == ast.void_type_idx && ret_type.has_option_or_result() { diff --git a/vlib/v/tests/options/option_match_none_test.v b/vlib/v/tests/options/option_match_none_test.v new file mode 100644 index 0000000000..26cd315821 --- /dev/null +++ b/vlib/v/tests/options/option_match_none_test.v @@ -0,0 +1,21 @@ +fn test_main() { + a := match 1 { + 0 { none } + else { 1 } + } + assert '${a}' == 'Option(1)' + + b := match 2 { + 0 { none } + 2 { none } + else { 1 } + } + assert '${b}' == 'Option(none)' + + c := match 2 { + 0 { 1 } + 2 { 2 } + else { none } + } + assert '${c}' == 'Option(2)' +}