From b98ca31e263a4319839543088accd45915290866 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 26 Apr 2025 12:11:31 -0300 Subject: [PATCH] cgen: fix codegen for writing on unwrapped selector (fix #24316) (#24323) --- vlib/v/gen/c/cgen.v | 17 ++++--- vlib/v/tests/options/option_ptr_unwrap_test.v | 1 - .../option_unwrap_selector_write_test.v | 46 +++++++++++++++++++ 3 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 vlib/v/tests/options/option_unwrap_selector_write_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index fe09c02e1..c1b299ed8 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4147,11 +4147,13 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { mut field_typ := ast.void_type mut is_option_unwrap := false is_iface_or_sumtype := sym.kind in [.interface, .sum_type] + mut deref_count := 0 if f := g.table.find_field_with_embeds(sym, node.field_name) { field_sym := g.table.sym(f.typ) field_typ = f.typ if is_iface_or_sumtype { g.write('(*(') + deref_count++ } is_option := field_typ.has_flag(.option) if field_sym.kind in [.sum_type, .interface] || is_option { @@ -4168,6 +4170,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { } if nested_unwrap && field_sym.kind == .sum_type { g.write('*(') + deref_count++ } for i, typ in field.smartcasts { if i == 0 && (is_option_unwrap || nested_unwrap) { @@ -4184,14 +4187,9 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { } else { '*' } - suffix := if g.inside_selector && field.orig_type.has_flag(.option) - && field.orig_type.is_ptr() && g.is_assign_lhs { - '' - } else { - '*' - } - g.inside_selector_deref = suffix == '' && deref.len > 0 - g.write('(${deref}(${g.styp(typ)}${suffix})') + deref_count += deref.len + g.inside_selector_deref = deref_count > typ.nr_muls() + g.write('(${deref}(${g.styp(typ)}*)') } if i == 0 || !nested_unwrap { g.write('(') @@ -4361,7 +4359,8 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { || (((!is_dereferenced && unwrapped_expr_type.is_ptr()) || sym.kind == .chan || alias_to_ptr) && node.from_embed_types.len == 0) || (node.expr.is_as_cast() && g.inside_smartcast) - if !has_embed && left_is_ptr && !(opt_ptr_already_deref && !g.inside_selector) { + || (!opt_ptr_already_deref && unwrapped_expr_type.is_ptr()) + if !has_embed && left_is_ptr { g.write('->') } else { g.write('.') diff --git a/vlib/v/tests/options/option_ptr_unwrap_test.v b/vlib/v/tests/options/option_ptr_unwrap_test.v index 74ff2829e..4e10a054a 100644 --- a/vlib/v/tests/options/option_ptr_unwrap_test.v +++ b/vlib/v/tests/options/option_ptr_unwrap_test.v @@ -1,4 +1,3 @@ -// vtest build: !msvc import time // 41s. diff --git a/vlib/v/tests/options/option_unwrap_selector_write_test.v b/vlib/v/tests/options/option_unwrap_selector_write_test.v new file mode 100644 index 000000000..75ec74b1a --- /dev/null +++ b/vlib/v/tests/options/option_unwrap_selector_write_test.v @@ -0,0 +1,46 @@ +module main + +@[heap] +interface IGameObject { +mut: + name string + parent ?&IGameObject + next ?&IGameObject + child ?&IGameObject + last_child ?&IGameObject + add_child(mut o IGameObject) +} + +@[heap] +struct GameObject implements IGameObject { +mut: + name string + parent ?&IGameObject + next ?&IGameObject + child ?&IGameObject + last_child ?&IGameObject +} + +fn (mut gameobject GameObject) add_child(mut o IGameObject) { + o.parent = gameobject + if gameobject.last_child != none { + gameobject.last_child.next = o + } else { + gameobject.child = o + } + gameobject.last_child = o +} + +fn test_main() { + mut v1 := &GameObject{ + name: 'v1' + } + mut v2 := &GameObject{ + name: 'v2' + } + mut v3 := &GameObject{ + name: 'v3' + } + v1.add_child(mut v2) + v1.add_child(mut v3) +} -- 2.39.5