mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: fix option unwrap on assignment (#17551)
This commit is contained in:
parent
ae6a48c0e3
commit
e253256c30
@ -1119,8 +1119,9 @@ fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_ret
|
||||
c.expected_or_type = ret_type.clear_flag(.option).clear_flag(.result)
|
||||
last_stmt_typ := c.expr(stmt.expr)
|
||||
|
||||
if ret_type.has_flag(.option) && last_stmt_typ.has_flag(.option) {
|
||||
if stmt.expr in [ast.Ident, ast.SelectorExpr, ast.CallExpr] {
|
||||
if ret_type.has_flag(.option)
|
||||
&& (last_stmt_typ.has_flag(.option) || last_stmt_typ == ast.none_type) {
|
||||
if stmt.expr in [ast.Ident, ast.SelectorExpr, ast.CallExpr, ast.None] {
|
||||
expected_type_name := c.table.type_to_str(ret_type.clear_flag(.option).clear_flag(.result))
|
||||
got_type_name := c.table.type_to_str(last_stmt_typ)
|
||||
c.error('`or` block must provide a value of type `${expected_type_name}`, not `${got_type_name}`',
|
||||
|
7
vlib/v/checker/tests/wrong_option_unwrap_err.out
Normal file
7
vlib/v/checker/tests/wrong_option_unwrap_err.out
Normal file
@ -0,0 +1,7 @@
|
||||
vlib/v/checker/tests/wrong_option_unwrap_err.vv:3:14: error: `or` block must provide a value of type `string`, not `none`
|
||||
1 | fn main() {
|
||||
2 | a := ?string('c')
|
||||
3 | b := a or { none }
|
||||
| ~~~~
|
||||
4 | println(b)
|
||||
5 | }
|
5
vlib/v/checker/tests/wrong_option_unwrap_err.vv
Normal file
5
vlib/v/checker/tests/wrong_option_unwrap_err.vv
Normal file
@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
a := ?string('c')
|
||||
b := a or { none }
|
||||
println(b)
|
||||
}
|
@ -10,8 +10,8 @@ import v.token
|
||||
fn (mut g Gen) expr_with_opt_or_block(expr ast.Expr, expr_typ ast.Type, var_expr ast.Expr, ret_typ ast.Type) {
|
||||
gen_or := expr is ast.Ident && (expr as ast.Ident).or_expr.kind != .absent
|
||||
if gen_or {
|
||||
old_inside_opt_data := g.inside_opt_data
|
||||
g.inside_opt_data = true
|
||||
old_inside_opt_or_res := g.inside_opt_or_res
|
||||
g.inside_opt_or_res = true
|
||||
g.expr_with_cast(expr, expr_typ, ret_typ)
|
||||
g.writeln(';')
|
||||
g.writeln('if (${expr}.state != 0) {')
|
||||
@ -40,7 +40,7 @@ fn (mut g Gen) expr_with_opt_or_block(expr ast.Expr, expr_typ ast.Type, var_expr
|
||||
}
|
||||
}
|
||||
g.writeln('}')
|
||||
g.inside_opt_data = old_inside_opt_data
|
||||
g.inside_opt_or_res = old_inside_opt_or_res
|
||||
} else {
|
||||
g.expr_with_opt(expr, expr_typ, ret_typ)
|
||||
}
|
||||
|
@ -4093,7 +4093,7 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||
if node.obj is ast.Var {
|
||||
if !g.is_assign_lhs && node.obj.is_comptime_field {
|
||||
if g.comptime_for_field_type.has_flag(.option) {
|
||||
if (g.inside_opt_or_res && node.or_expr.kind == .absent) || g.left_is_opt {
|
||||
if (g.inside_opt_or_res || g.left_is_opt) && node.or_expr.kind == .absent {
|
||||
g.write('${name}')
|
||||
} else {
|
||||
g.write('/*opt*/')
|
||||
@ -4103,7 +4103,8 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||
} else {
|
||||
g.write('${name}')
|
||||
}
|
||||
if node.or_expr.kind != .absent {
|
||||
if node.or_expr.kind != .absent && !(g.inside_opt_or_res && g.inside_assign
|
||||
&& !g.is_assign_lhs) {
|
||||
stmt_str := g.go_before_stmt(0).trim_space()
|
||||
g.empty_line = true
|
||||
g.or_block(name, node.or_expr, g.comptime_for_field_type)
|
||||
@ -4117,14 +4118,15 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||
// `x = new_opt()` => `x = new_opt()` (g.right_is_opt == true)
|
||||
// `println(x)` => `println(*(int*)x.data)`
|
||||
if node.info.is_option && !(g.is_assign_lhs && g.right_is_opt) {
|
||||
if (g.inside_opt_or_res && node.or_expr.kind == .absent) || g.left_is_opt {
|
||||
if (g.inside_opt_or_res || g.left_is_opt) && node.or_expr.kind == .absent {
|
||||
g.write('${name}')
|
||||
} else {
|
||||
g.write('/*opt*/')
|
||||
styp := g.base_type(node.info.typ)
|
||||
g.write('(*(${styp}*)${name}.data)')
|
||||
}
|
||||
if node.or_expr.kind != .absent && !(g.inside_assign && !g.is_assign_lhs) {
|
||||
if node.or_expr.kind != .absent && !(g.inside_opt_or_res && g.inside_assign
|
||||
&& !g.is_assign_lhs) {
|
||||
stmt_str := g.go_before_stmt(0).trim_space()
|
||||
g.empty_line = true
|
||||
g.or_block(name, node.or_expr, node.info.typ)
|
||||
|
15
vlib/v/tests/option_unwrap_assign_test.v
Normal file
15
vlib/v/tests/option_unwrap_assign_test.v
Normal file
@ -0,0 +1,15 @@
|
||||
struct Foo {
|
||||
mut:
|
||||
x string
|
||||
y ?string
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
a := ?string(none)
|
||||
mut foo := Foo{}
|
||||
foo.x = a or { 'test' }
|
||||
foo.y = a or { 'test' }
|
||||
|
||||
assert foo.x == 'test'
|
||||
assert foo.y? == 'test'
|
||||
}
|
Loading…
Reference in New Issue
Block a user