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:
parent
54a1b66b94
commit
326e43385b
@ -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)
|
||||
|
@ -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 | }
|
||||
|
7
vlib/v/checker/tests/option_with_match_err.out
Normal file
7
vlib/v/checker/tests/option_with_match_err.out
Normal 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 | }
|
7
vlib/v/checker/tests/option_with_match_err.vv
Normal file
7
vlib/v/checker/tests/option_with_match_err.vv
Normal file
@ -0,0 +1,7 @@
|
||||
fn main() {
|
||||
mut a := ?int(12)
|
||||
match a {
|
||||
12 { println(a) }
|
||||
else { println('else') }
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
66
vlib/v/tests/option_match_test.v
Normal file
66
vlib/v/tests/option_match_test.v
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user