1
0
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:
Felipe Pena 2023-06-04 13:10:22 -03:00 committed by GitHub
parent 9dcd95ee34
commit 8d2a0ffe37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 116 additions and 13 deletions

View File

@ -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 {

View File

@ -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 {

View File

@ -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)
}
}

View 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?
}