cgen: fix reassignment of optionals

pull/4823/head
Alexander Medvednikov 2020-05-10 17:40:24 +02:00
parent 1722171adc
commit a2d120b583
3 changed files with 57 additions and 12 deletions

View File

@ -20,7 +20,7 @@ pub mut:
url string url string
user_agent string user_agent string
verbose bool verbose bool
mut: //mut:
user_ptr voidptr user_ptr voidptr
ws_func voidptr ws_func voidptr
} }

View File

@ -1371,7 +1371,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
tmp_opt := if gen_or { g.new_tmp_var() } else { '' } tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
if gen_or { if gen_or {
rstyp := g.typ(return_type) rstyp := g.typ(return_type)
g.write('$rstyp $tmp_opt =') g.write('/*q*/ $rstyp $tmp_opt = ')
} }
g.is_assign_rhs = true g.is_assign_rhs = true
if ast.expr_is_blank_ident(node.left) { if ast.expr_is_blank_ident(node.left) {
@ -1406,6 +1406,9 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
} }
} else { } else {
g.assign_op = node.op g.assign_op = node.op
if !gen_or {
// Don't need to generate `var = ` in `or {}` expressions, since we are doing
// `Option_X tmp = ...; var = *(X*)tmp.data;`
g.expr(node.left) g.expr(node.left)
// arr[i] = val => `array_set(arr, i, val)`, not `array_get(arr, i) = val` // arr[i] = val => `array_set(arr, i, val)`, not `array_get(arr, i) = val`
if !g.is_array_set && !str_add { if !g.is_array_set && !str_add {
@ -1413,6 +1416,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
} else if str_add { } else if str_add {
g.write(', ') g.write(', ')
} }
}
g.is_assign_lhs = false g.is_assign_lhs = false
// right_sym := g.table.get_type_symbol(node.right_type) // right_sym := g.table.get_type_symbol(node.right_type)
// left_sym := g.table.get_type_symbol(node.left_type) // left_sym := g.table.get_type_symbol(node.left_type)
@ -1436,7 +1440,22 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
g.right_is_opt = false g.right_is_opt = false
} }
if gen_or { if gen_or {
// g.write('/*777 $tmp_opt*/')
g.or_block(tmp_opt, or_stmts, return_type) g.or_block(tmp_opt, or_stmts, return_type)
unwrapped_type_str := g.typ(return_type.set_flag(.unset))
ident := node.left as ast.Ident
if ident.info is ast.IdentVar {
ident_var := ident.info as ast.IdentVar
if ident_var.is_optional {
// var is already an optional, just copy the value
// `var = tmp;`
g.write('\n$ident.name = $tmp_opt')
} else {
// var = *(X*)tmp.data;`
g.write('\n$ident.name = *($unwrapped_type_str*)${tmp_opt}.data')
}
}
// g.expr(node.left)
} }
g.is_assign_rhs = false g.is_assign_rhs = false
} }

View File

@ -84,6 +84,25 @@ fn test_q() {
// assert foo_ok()? == true // assert foo_ok()? == true
} }
fn test_reassignment() {
mut x2 := foo_ok() or {
assert false
return
}
assert x2 == 777
x2 = 100
assert x2 == 100
x2 += 1
assert x2 == 101
///
mut x3 := 0
x3 = foo_ok() or {
assert false
return
}
assert x3 == 777
}
struct Person { struct Person {
mut: mut:
name string name string
@ -111,7 +130,7 @@ fn test_field_or() {
'default' 'default'
} }
assert mytitle == 'default' assert mytitle == 'default'
*/ */
} }
struct Thing { struct Thing {
@ -126,7 +145,7 @@ fn test_opt_field() {
t.opt = 5 t.opt = 5
val := t.opt or { return } val := t.opt or { return }
assert val == 5 assert val == 5
*/ */
} }
fn opt_ptr(a &int) ?&int { fn opt_ptr(a &int) ?&int {
@ -137,6 +156,13 @@ fn opt_ptr(a &int) ?&int {
} }
fn test_opt_ptr() { fn test_opt_ptr() {
if true {
}
//
else{
}
a := 3 a := 3
mut r := opt_ptr(&a) or { mut r := opt_ptr(&a) or {
&int(0) &int(0)