1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen: fix match with option type (#17713)

This commit is contained in:
Felipe Pena 2023-03-21 06:38:30 -03:00 committed by GitHub
parent 54a1b66b94
commit 326e43385b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 2 deletions

View File

@ -29,6 +29,7 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
c.ensure_type_exists(node.cond_type, node.pos) or { return ast.void_type }
c.check_expr_opt_call(node.cond, cond_type)
cond_type_sym := c.table.sym(cond_type)
cond_is_option := cond_type.has_flag(.option)
node.is_sum_type = cond_type_sym.kind in [.interface_, .sum_type]
c.match_exprs(mut node, cond_type_sym)
c.expected_type = cond_type
@ -58,6 +59,10 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
c.expected_type = node.expected_type
}
expr_type := c.expr(stmt.expr)
if !branch.is_else && cond_is_option && branch.exprs[0] !is ast.None {
c.error('`match` expression with Option type only checks against `none`, to match its value you must unwrap it first `var?`',
branch.pos)
}
stmt.typ = expr_type
if first_iteration {
if node.is_expr && (node.expected_type.has_flag(.option)

View File

@ -1,7 +1,21 @@
vlib/v/checker/tests/match_cond_with_parenthesis_err.vv:14:15: error: unnecessary `()` in `match` condition, use `match expr {` instead of `match (expr) {`.
12 |
12 |
13 | fn bar() bool {
14 | return match (foo()) {
| ~~~~~~~
15 | .a { true }
16 | .b, .c { false }
vlib/v/checker/tests/match_cond_with_parenthesis_err.vv:15:3: error: `match` expression with Option type only checks against `none`, to match its value you must unwrap it first `var?`
13 | fn bar() bool {
14 | return match (foo()) {
15 | .a { true }
| ~~
16 | .b, .c { false }
17 | }
vlib/v/checker/tests/match_cond_with_parenthesis_err.vv:16:3: error: `match` expression with Option type only checks against `none`, to match its value you must unwrap it first `var?`
14 | return match (foo()) {
15 | .a { true }
16 | .b, .c { false }
| ~~~~~~
17 | }
18 | }

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/option_with_match_err.vv:4:3: error: `match` expression with Option type only checks against `none`, to match its value you must unwrap it first `var?`
2 | mut a := ?int(12)
3 | match a {
4 | 12 { println(a) }
| ~~
5 | else { println('else') }
6 | }

View File

@ -0,0 +1,7 @@
fn main() {
mut a := ?int(12)
match a {
12 { println(a) }
else { println('else') }
}
}

View File

@ -65,7 +65,9 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
g.inside_match_result = true
}
}
if node.cond in [ast.Ident, ast.IntegerLiteral, ast.StringLiteral, ast.FloatLiteral]
if (node.cond in [ast.Ident, ast.IntegerLiteral, ast.StringLiteral, ast.FloatLiteral]
&& (node.cond !is ast.Ident || (node.cond is ast.Ident
&& (node.cond as ast.Ident).or_expr.kind == .absent)))
|| (node.cond is ast.SelectorExpr
&& (node.cond as ast.SelectorExpr).or_block.kind == .absent
&& ((node.cond as ast.SelectorExpr).expr !is ast.CallExpr
@ -437,6 +439,14 @@ fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var str
if i > 0 {
g.write(' || ')
}
if expr is ast.None {
old_left_is_opt := g.left_is_opt
g.left_is_opt = true
g.expr(node.cond)
g.left_is_opt = old_left_is_opt
g.write('.state == 2')
continue
}
match type_sym.kind {
.array {
ptr_typ := g.equality_fn(node.cond_type)
@ -478,6 +488,12 @@ fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var str
g.write('${cond_var} <= ')
g.expr(expr.high)
g.write(')')
} else if expr is ast.None {
old_left_is_opt := g.left_is_opt
g.left_is_opt = true
g.expr(node.cond)
g.left_is_opt = old_left_is_opt
g.write('.state == 2')
} else {
g.write('${cond_var} == (')
g.expr(expr)

View File

@ -0,0 +1,66 @@
fn test_simple_match_expr() {
mut a := ?int(12)
match a? {
12 {
println(a)
}
else {
println('else')
assert false
}
}
match a {
none {
println('none')
assert false
}
else {
println('else')
}
}
a = none
match a {
none {
println('none')
}
else {
println('else')
assert false
}
}
mut b := ?string('aaa')
match b? {
'aaa' {
println(b)
}
else {
println('else')
assert false
}
}
match b {
none {
println('none')
assert false
}
else {
println('else')
}
}
b = none
match b {
none {
println('none')
}
else {
println('else')
assert false
}
}
}