mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: fix option handling with auto heap variable (#18336)
This commit is contained in:
parent
9dcd95ee34
commit
8d2a0ffe37
@ -962,6 +962,17 @@ pub mut:
|
||||
concrete_types []Type
|
||||
}
|
||||
|
||||
pub fn (i &Ident) is_auto_heap() bool {
|
||||
match i.obj {
|
||||
Var {
|
||||
return i.obj.is_auto_heap
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (i &Ident) is_mut() bool {
|
||||
match i.obj {
|
||||
Var {
|
||||
|
@ -14,7 +14,12 @@ fn (mut g Gen) expr_with_opt_or_block(expr ast.Expr, expr_typ ast.Type, var_expr
|
||||
g.inside_opt_or_res = true
|
||||
g.expr_with_cast(expr, expr_typ, ret_typ)
|
||||
g.writeln(';')
|
||||
g.writeln('if (${expr}.state != 0) {')
|
||||
expr_var := if expr is ast.Ident && (expr as ast.Ident).is_auto_heap() {
|
||||
'(*${expr.name})'
|
||||
} else {
|
||||
'${expr}'
|
||||
}
|
||||
g.writeln('if (${expr_var}.state != 0) { // assign')
|
||||
if expr is ast.Ident && (expr as ast.Ident).or_expr.kind == .propagate_option {
|
||||
g.writeln('\tpanic_option_not_set(_SLIT("none"));')
|
||||
} else {
|
||||
@ -623,6 +628,9 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
g.inside_opt_or_res = old_inside_opt_or_res
|
||||
}
|
||||
g.inside_opt_or_res = true
|
||||
if is_auto_heap && var_type.has_flag(.option) {
|
||||
g.write('&')
|
||||
}
|
||||
tmp_var := g.new_tmp_var()
|
||||
g.expr_with_tmp_var(val, val_type, var_type, tmp_var)
|
||||
} else if is_fixed_array_var {
|
||||
@ -688,6 +696,14 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// var = &auto_heap_var
|
||||
old_is_auto_heap := g.is_option_auto_heap
|
||||
g.is_option_auto_heap = val_type.has_flag(.option) && val is ast.PrefixExpr
|
||||
&& (val as ast.PrefixExpr).right is ast.Ident
|
||||
&& ((val as ast.PrefixExpr).right as ast.Ident).is_auto_heap()
|
||||
defer {
|
||||
g.is_option_auto_heap = old_is_auto_heap
|
||||
}
|
||||
if var_type.has_flag(.option) || gen_or {
|
||||
g.expr_with_opt_or_block(val, val_type, left, var_type)
|
||||
} else if node.has_cross_var {
|
||||
|
@ -103,7 +103,8 @@ mut:
|
||||
is_json_fn bool // inside json.encode()
|
||||
is_js_call bool // for handling a special type arg #1 `json.decode(User, ...)`
|
||||
is_fn_index_call bool
|
||||
is_cc_msvc bool // g.pref.ccompiler == 'msvc'
|
||||
is_cc_msvc bool // g.pref.ccompiler == 'msvc'
|
||||
is_option_auto_heap bool
|
||||
vlines_path string // set to the proper path for generating #line directives
|
||||
options_pos_forward int // insertion point to forward
|
||||
options_forward []string // to forward
|
||||
@ -3342,10 +3343,16 @@ fn (mut g Gen) expr(node_ ast.Expr) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !(g.is_amp && node.right.is_auto_deref_var()) {
|
||||
if g.is_option_auto_heap {
|
||||
g.write('(${g.base_type(node.right_type)}*)')
|
||||
}
|
||||
if !g.is_option_auto_heap && !(g.is_amp && node.right.is_auto_deref_var()) {
|
||||
g.write(node.op.str())
|
||||
}
|
||||
g.expr(node.right)
|
||||
if g.is_option_auto_heap {
|
||||
g.write('.data')
|
||||
}
|
||||
}
|
||||
g.is_amp = false
|
||||
}
|
||||
@ -3560,8 +3567,10 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||
}
|
||||
mut sum_type_deref_field := ''
|
||||
mut sum_type_dot := '.'
|
||||
mut field_typ := ast.void_type
|
||||
if f := g.table.find_field_with_embeds(sym, node.field_name) {
|
||||
field_sym := g.table.sym(f.typ)
|
||||
field_typ = f.typ
|
||||
if field_sym.kind in [.sum_type, .interface_] {
|
||||
if !prevent_sum_type_unwrapping_once {
|
||||
// check first if field is sum type because scope searching is expensive
|
||||
@ -3660,6 +3669,11 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||
return
|
||||
}
|
||||
}
|
||||
field_is_opt := node.expr is ast.Ident && (node.expr as ast.Ident).is_auto_heap()
|
||||
&& (node.expr as ast.Ident).or_expr.kind != .absent && field_typ.has_flag(.option)
|
||||
if field_is_opt {
|
||||
g.write('((${g.base_type(field_typ)})')
|
||||
}
|
||||
n_ptr := node.expr_type.nr_muls() - 1
|
||||
if n_ptr > 0 {
|
||||
g.write('(')
|
||||
@ -3669,6 +3683,9 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||
} else {
|
||||
g.expr(node.expr)
|
||||
}
|
||||
if field_is_opt {
|
||||
g.write(')')
|
||||
}
|
||||
if is_opt_or_res {
|
||||
g.write('.data)')
|
||||
}
|
||||
@ -3691,8 +3708,9 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||
}
|
||||
}
|
||||
alias_to_ptr := sym.info is ast.Alias && (sym.info as ast.Alias).parent_type.is_ptr()
|
||||
if (node.expr_type.is_ptr() || sym.kind == .chan || alias_to_ptr)
|
||||
&& node.from_embed_types.len == 0 {
|
||||
if field_is_opt
|
||||
|| ((node.expr_type.is_ptr() || sym.kind == .chan || alias_to_ptr)
|
||||
&& node.from_embed_types.len == 0) {
|
||||
g.write('->')
|
||||
} else {
|
||||
g.write('.')
|
||||
@ -4157,27 +4175,37 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||
g.write('_const_')
|
||||
}
|
||||
}
|
||||
mut is_auto_heap := false
|
||||
mut is_auto_heap := node.is_auto_heap()
|
||||
mut is_option := false
|
||||
if node.info is ast.IdentVar {
|
||||
if node.obj is ast.Var {
|
||||
if !g.is_assign_lhs && node.obj.ct_type_var !in [.generic_param, .no_comptime] {
|
||||
comptime_type := g.get_comptime_var_type(node)
|
||||
if comptime_type.has_flag(.option) {
|
||||
if (g.inside_opt_or_res || g.left_is_opt) && node.or_expr.kind == .absent {
|
||||
g.write('${name}')
|
||||
if !g.is_assign_lhs && is_auto_heap {
|
||||
g.write('(*${name})')
|
||||
} else {
|
||||
g.write(name)
|
||||
}
|
||||
} else {
|
||||
g.write('/*opt*/')
|
||||
styp := g.base_type(comptime_type)
|
||||
g.write('(*(${styp}*)${name}.data)')
|
||||
if is_auto_heap {
|
||||
g.write('(*(${styp}*)${name}->data)')
|
||||
} else {
|
||||
g.write('(*(${styp}*)${name}.data)')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g.write('${name}')
|
||||
g.write(name)
|
||||
}
|
||||
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, comptime_type)
|
||||
var_name := if !g.is_assign_lhs && is_auto_heap { '(*${name})' } else { name }
|
||||
g.or_block(var_name, node.or_expr, comptime_type)
|
||||
g.writeln(stmt_str)
|
||||
}
|
||||
return
|
||||
@ -4189,17 +4217,30 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||
// `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 || g.left_is_opt) && node.or_expr.kind == .absent {
|
||||
g.write('${name}')
|
||||
if !g.is_assign_lhs && is_auto_heap {
|
||||
g.write('(*${name})')
|
||||
} else {
|
||||
g.write(name)
|
||||
}
|
||||
} else {
|
||||
g.write('/*opt*/')
|
||||
styp := g.base_type(node.info.typ)
|
||||
g.write('(*(${styp}*)${name}.data)')
|
||||
if is_auto_heap {
|
||||
g.write('(*(${styp}*)${name}->data)')
|
||||
} else {
|
||||
g.write('(*(${styp}*)${name}.data)')
|
||||
}
|
||||
}
|
||||
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)
|
||||
var_name := if !g.is_assign_lhs && is_auto_heap {
|
||||
'(*${name})'
|
||||
} else {
|
||||
name
|
||||
}
|
||||
g.or_block(var_name, node.or_expr, node.info.typ)
|
||||
g.write(stmt_str)
|
||||
}
|
||||
return
|
||||
@ -4208,6 +4249,7 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||
g.write('${name}.val')
|
||||
return
|
||||
}
|
||||
is_option = node.info.is_option
|
||||
if node.obj is ast.Var {
|
||||
is_auto_heap = node.obj.is_auto_heap
|
||||
&& (!g.is_assign_lhs || g.assign_op != .decl_assign)
|
||||
@ -4280,6 +4322,16 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||
g.write(g.get_ternary_name(name))
|
||||
if is_auto_heap {
|
||||
g.write('))')
|
||||
if is_option {
|
||||
g.write('.data')
|
||||
}
|
||||
}
|
||||
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
|
||||
var_opt := if is_auto_heap { '(*${name})' } else { name }
|
||||
g.or_block(var_opt, node.or_expr, node.obj.typ)
|
||||
g.write(stmt_str)
|
||||
}
|
||||
}
|
||||
|
||||
|
24
vlib/v/tests/option_auto_heap_test.v
Normal file
24
vlib/v/tests/option_auto_heap_test.v
Normal file
@ -0,0 +1,24 @@
|
||||
struct Teste {
|
||||
pub mut:
|
||||
teste ?&Teste
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
mut a := Teste{}
|
||||
a.teste = &a
|
||||
dump(a) // circular
|
||||
|
||||
assert a.teste? == &a
|
||||
|
||||
mut t := ?Teste{}
|
||||
w := dump(t) // Option(none)
|
||||
assert w == none
|
||||
|
||||
mut z := ?Teste{}
|
||||
z = Teste{}
|
||||
z?.teste = &z
|
||||
dump(z) // // circular
|
||||
|
||||
y := z?
|
||||
assert y.teste? == &z?
|
||||
}
|
Loading…
Reference in New Issue
Block a user