From b29982205a0410b4e3d30f6e5b82851ceb2071d9 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 15 Apr 2026 15:48:08 +0300 Subject: [PATCH] cgen: fix c error when building gui library (fixes #26861) --- vlib/v/gen/c/cgen.v | 28 +++++++++++-- ...ption_autoheap_selector_none_unwrap_test.v | 42 +++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 vlib/v/tests/options/option_autoheap_selector_none_unwrap_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 6068aaaa5..4b5b0bb69 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6255,10 +6255,32 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { } mut expr_is_auto_heap := node.expr is ast.Ident && g.resolved_ident_is_auto_heap(node.expr) mut expr_is_unwrapped_autoheap_option := false + mut expr_autoheap_option_type := ast.Type(0) if expr_is_auto_heap { expr_ident := node.expr as ast.Ident - if expr_ident.obj is ast.Var && expr_ident.obj.typ.has_flag(.option) - && !lhs_expr_type.has_flag(.option) { + if node.expr_type.has_flag(.option) { + expr_autoheap_option_type = node.expr_type + } + if expr_ident.obj is ast.Var { + if expr_ident.obj.orig_type.has_flag(.option) { + expr_autoheap_option_type = expr_ident.obj.orig_type + } else if expr_ident.obj.typ.has_flag(.option) { + expr_autoheap_option_type = expr_ident.obj.typ + } + } + if expr_autoheap_option_type == 0 && selector_scope != unsafe { nil } { + if scope_var := selector_scope.find_var(expr_ident.name) { + if scope_var.orig_type.has_flag(.option) { + expr_autoheap_option_type = scope_var.orig_type + } else if scope_var.typ.has_flag(.option) { + expr_autoheap_option_type = scope_var.typ + } + } + } + // Autoheap option locals can have their runtime type smartcast down to the + // unwrapped struct before selector codegen runs. Preserve the original + // option source type so selector receivers still unwrap through `->data`. + if expr_autoheap_option_type.has_flag(.option) && !lhs_expr_type.has_flag(.option) { expr_is_unwrapped_autoheap_option = true expr_is_auto_heap = false } @@ -6301,7 +6323,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { } else { g.get_ternary_name(c_name(expr_ident.name)) } - g.unwrap_option_type(expr_ident.obj.typ, expr_name, true) + g.unwrap_option_type(expr_autoheap_option_type, expr_name, true) } else if expr_is_auto_heap { expr_ident := node.expr as ast.Ident if expr_ident.obj is ast.Var && expr_ident.obj.is_inherited { diff --git a/vlib/v/tests/options/option_autoheap_selector_none_unwrap_test.v b/vlib/v/tests/options/option_autoheap_selector_none_unwrap_test.v new file mode 100644 index 000000000..ea7485b3f --- /dev/null +++ b/vlib/v/tests/options/option_autoheap_selector_none_unwrap_test.v @@ -0,0 +1,42 @@ +struct Padding { + top f32 + bottom f32 +} + +fn (p Padding) height() f32 { + return p.top + p.bottom +} + +struct Shape { + height f32 + padding Padding +} + +@[heap] +struct Layout { + shape &Shape +} + +fn find_layout(layout &Layout) ?Layout { + return *layout +} + +fn test_autoheap_option_selector_none_unwrap() { + shape := &Shape{ + height: 7 + padding: Padding{ + top: 1 + bottom: 2 + } + } + layout := &Layout{ + shape: shape + } + layout_scroll := find_layout(layout) + if layout_scroll != none { + layout_scroll_height := layout_scroll.shape.height - layout_scroll.shape.padding.height() + assert layout_scroll_height == 4 + } else { + assert false + } +} -- 2.39.5