Skip to content

Commit

Permalink
cgen: fix nested option selector unwrapping (fix #23500) (#23497)
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp authored Jan 17, 2025
1 parent c98295b commit 496451e
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
16 changes: 13 additions & 3 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -3995,21 +3995,27 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
// check first if field is sum type because scope searching is expensive
scope := g.file.scope.innermost(node.pos.pos)
if field := scope.find_struct_field(node.expr.str(), node.expr_type, node.field_name) {
nested_unwrap := is_option && field.smartcasts.len > 1
is_option_unwrap = is_option && field.smartcasts.len > 0
&& field.typ.clear_flag(.option) == field.smartcasts.last()
if field.orig_type.is_ptr() {
sum_type_dot = '->'
}
if nested_unwrap && field_sym.kind == .sum_type {
g.write('*(')
}
for i, typ in field.smartcasts {
if i == 0 && is_option_unwrap {
if i == 0 && (is_option_unwrap || nested_unwrap) {
deref := if g.inside_selector {
'*'.repeat(field.smartcasts.last().nr_muls() + 1)
} else {
'*'
}
g.write('(${deref}(${g.styp(typ)}*)')
}
g.write('(')
if i == 0 || !nested_unwrap {
g.write('(')
}
if field_sym.kind == .sum_type && !is_option {
g.write('*')
}
Expand All @@ -4029,7 +4035,11 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
agg_sym := g.table.sym(cast_sym.info.types[g.aggregate_type_idx])
sum_type_deref_field += '_${agg_sym.cname}'
} else {
sum_type_deref_field += '_${cast_sym.cname}'
if i == 0 && nested_unwrap {
sum_type_deref_field += 'data)'
} else {
sum_type_deref_field += '_${cast_sym.cname}'
}
}
}
}
Expand Down
22 changes: 22 additions & 0 deletions vlib/v/tests/options/option_nested_selector_unwrap_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
type Foo = string | int | f32

struct Bar {
log ?Foo
}

fn Bar.init(log ?Foo) {
mut bar := Bar{
log: log
}
if bar.log != none {
if bar.log is string {
assert bar.log == 'foobar'
return
}
}
assert false
}

fn test_main() {
Bar.init('foobar')
}

0 comments on commit 496451e

Please sign in to comment.