checker: fix MatchExpr type inferring, when none is used (fix #23831) (#23833)

This commit is contained in:
Felipe Pena 2025-03-01 18:29:25 -03:00 committed by GitHub
parent f7e062c91a
commit 95f00937bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 4 deletions

View file

@ -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,9 +290,11 @@ fn (mut c Checker) check_match_branch_last_stmt(last_stmt ast.ExprStmt, ret_type
return
}
}
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() {
c.error('`${last_stmt.expr}` used as value', last_stmt.pos)

View file

@ -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)'
}