checker, cgen: fix match expr returning optional with error (fix #12556) (#12645)

pull/12664/head weekly.2021.48
yuyi 2021-12-02 18:22:48 +08:00 committed by GitHub
parent 7d0a36dd08
commit 66a67de8c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 7 deletions

View File

@ -6265,14 +6265,14 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
} }
expr_type := c.expr(stmt.expr) expr_type := c.expr(stmt.expr)
if first_iteration { if first_iteration {
if node.is_expr && !node.expected_type.has_flag(.optional) if node.is_expr && (node.expected_type.has_flag(.optional)
&& c.table.get_type_symbol(node.expected_type).kind == .sum_type { || c.table.type_kind(node.expected_type) == .sum_type) {
ret_type = node.expected_type ret_type = node.expected_type
} else { } else {
ret_type = expr_type ret_type = expr_type
} }
stmt.typ = 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) if !c.check_types(ret_type, expr_type)
&& !c.check_types(expr_type, ret_type) { && !c.check_types(expr_type, ret_type) {
ret_sym := c.table.get_type_symbol(ret_type) ret_sym := c.table.get_type_symbol(ret_type)

View File

@ -104,6 +104,7 @@ mut:
inside_map_index bool inside_map_index bool
inside_opt_data bool inside_opt_data bool
inside_if_optional bool inside_if_optional bool
inside_match_optional bool
loop_depth int loop_depth int
ternary_names map[string]string ternary_names map[string]string
ternary_level_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 { for i, stmt in stmts {
if i == stmts.len - 1 && tmp_var != '' { if i == stmts.len - 1 && tmp_var != '' {
// Handle if expressions, set the value of the last expression to the temp 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.set_current_pos_as_last_stmt_pos()
g.skip_stmt_pos = true g.skip_stmt_pos = true
if stmt is ast.ExprStmt { if stmt is ast.ExprStmt {
@ -1412,7 +1413,7 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) {
} }
} else { } else {
g.stmt(stmt) 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(';') g.writeln(';')
} }
} }
@ -1624,8 +1625,8 @@ fn (mut g Gen) stmt(node ast.Stmt) {
// if af { // if af {
// g.autofree_call_postgen() // g.autofree_call_postgen()
// } // }
if g.inside_ternary == 0 && !g.inside_if_optional && !node.is_expr if g.inside_ternary == 0 && !g.inside_if_optional && !g.inside_match_optional
&& node.expr !is ast.IfExpr { && !node.is_expr && node.expr !is ast.IfExpr {
g.writeln(';') 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 { if g.table.type_kind(node.return_type) == .sum_type {
return true return true
} }
if node.return_type.has_flag(.optional) {
return true
}
if sym.kind == .multi_return { if sym.kind == .multi_return {
return false return false
} }
@ -4418,6 +4422,13 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
if is_expr && !need_tmp_var { if is_expr && !need_tmp_var {
g.inside_ternary++ 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, if node.cond in [ast.Ident, ast.SelectorExpr, ast.IntegerLiteral, ast.StringLiteral,
ast.FloatLiteral] { ast.FloatLiteral] {
cond_var = g.expr_string(node.cond) cond_var = g.expr_string(node.cond)

View File

@ -34,3 +34,17 @@ fn test_match_expr_returning_optional() {
println(ret2) println(ret2)
assert ret2 == Any(1) 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'
}