Skip to content

Commit 6944d54

Browse files
authored
parser, cgen: fix option variable error (fix #17460) (#17479)
1 parent 30c205e commit 6944d54

5 files changed

Lines changed: 34 additions & 3 deletions

File tree

vlib/v/gen/c/assign.v

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,10 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
103103
mut return_type := ast.void_type
104104
is_decl := node.op == .decl_assign
105105
g.assign_op = node.op
106+
g.inside_assign = true
106107
defer {
107108
g.assign_op = .unknown
109+
g.inside_assign = false
108110
}
109111
op := if is_decl { token.Kind.assign } else { node.op }
110112
right_expr := node.right[0]
@@ -597,7 +599,8 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
597599
if val.is_auto_deref_var() {
598600
g.write('*')
599601
}
600-
if var_type.has_flag(.option) || gen_or {
602+
if (var_type.has_flag(.option) && val !in [ast.Ident, ast.SelectorExpr])
603+
|| gen_or {
601604
g.expr_with_opt_or_block(val, val_type, left, var_type)
602605
} else if val is ast.ArrayInit {
603606
g.array_init(val, c_name(ident.name))

vlib/v/gen/c/cgen.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ mut:
120120
inside_ternary int // ?: comma separated statements on a single line
121121
inside_map_postfix bool // inside map++/-- postfix expr
122122
inside_map_infix bool // inside map<</+=/-= infix expr
123+
inside_assign bool
123124
inside_map_index bool
124125
inside_opt_or_res bool
125126
inside_opt_data bool
@@ -4123,7 +4124,7 @@ fn (mut g Gen) ident(node ast.Ident) {
41234124
styp := g.base_type(node.info.typ)
41244125
g.write('(*(${styp}*)${name}.data)')
41254126
}
4126-
if node.or_expr.kind != .absent {
4127+
if node.or_expr.kind != .absent && !(g.inside_assign && !g.is_assign_lhs) {
41274128
stmt_str := g.go_before_stmt(0).trim_space()
41284129
g.empty_line = true
41294130
g.or_block(name, node.or_expr, node.info.typ)

vlib/v/gen/c/if.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
252252
} else if branch.cond is ast.IfGuardExpr {
253253
mut var_name := guard_vars[i]
254254
mut short_opt := false
255+
g.left_is_opt = true
255256
if var_name == '' {
256257
short_opt = true // we don't need a further tmp, so use the one we'll get later
257258
var_name = g.new_tmp_var()

vlib/v/parser/if_match.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
113113
p.check(.decl_assign)
114114
comments << p.eat_comments()
115115
expr := p.expr(0)
116-
if expr !in [ast.CallExpr, ast.IndexExpr, ast.PrefixExpr, ast.SelectorExpr] {
116+
if expr !in [ast.CallExpr, ast.IndexExpr, ast.PrefixExpr, ast.SelectorExpr, ast.Ident] {
117117
p.error_with_pos('if guard condition expression is illegal, it should return an Option',
118118
expr.pos())
119119
}

vlib/v/tests/option_var_2_test.v

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
struct Foo {
2+
name ?string
3+
}
4+
5+
fn test_option_var() {
6+
foo := Foo{}
7+
other := foo.name
8+
9+
println(typeof(other).name)
10+
if name := other {
11+
println('with name: ${name}')
12+
assert false
13+
} else {
14+
println('without name')
15+
assert true
16+
}
17+
18+
mut counter := 0
19+
val := other or {
20+
counter++
21+
'default'
22+
}
23+
24+
assert val == 'default'
25+
assert counter == 1
26+
}

0 commit comments

Comments
 (0)