From 0c19f209b6301458f57d8ef1b42deb4a72624c30 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 19 Jun 2026 23:23:22 +0300 Subject: [PATCH] cgen: fix `as`/`is` on option-type sumtype variant using wrong union member (#27478) (#27499) --- vlib/v/gen/c/cgen.v | 10 +++++-- .../option_sumtype_option_variant_test.v | 29 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 8dd1838be..420dc2aac 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -13757,7 +13757,11 @@ fn (mut g Gen) as_cast(node ast.AsCast) { matching_variants := g.matching_sumtype_variant_types(expr_type_without_option, unwrapped_node_typ) index_exprs := g.type_idx_exprs_for_types(matching_variants) - payload_sym := g.table.sym(g.as_cast_payload_type(unwrapped_node_typ, matching_variants)) + payload_type := g.as_cast_payload_type(unwrapped_node_typ, matching_variants) + payload_sym := g.table.sym(payload_type) + // Use the variant member name, which for an option-type variant + // (e.g. `type Foo = ?Bar | Baz`) is `_option_`, not `_`. + payload_member := g.get_sumtype_variant_name(payload_type, payload_sym) sidx := g.type_sidx(unwrapped_node_typ) if as_cast_operand_needs_tmp_eval(node.expr) { tmp_var := g.expr_to_ctemp_before_stmt(node.expr, node.expr_type).name @@ -13766,7 +13770,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) { } else { tmp_var } - obj_expr := '(${expr_str})${dot}_${payload_sym.cname}' + obj_expr := '(${expr_str})${dot}_${payload_member}' tag_expr := '(${expr_str})${dot}_typ' g.write_as_cast_call_start(styp, sym) g.write_as_cast_call(obj_expr, tag_expr, sidx, index_exprs) @@ -13776,7 +13780,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) { } else { g.expr_string(node.expr) } - obj_expr := '(${expr_str})${dot}_${payload_sym.cname}' + obj_expr := '(${expr_str})${dot}_${payload_member}' tag_expr := '(${expr_str})${dot}_typ' g.write_as_cast_call_start(styp, sym) g.write_as_cast_call(obj_expr, tag_expr, sidx, index_exprs) diff --git a/vlib/v/tests/options/option_sumtype_option_variant_test.v b/vlib/v/tests/options/option_sumtype_option_variant_test.v index 549bd83b0..5ceffa7f9 100644 --- a/vlib/v/tests/options/option_sumtype_option_variant_test.v +++ b/vlib/v/tests/options/option_sumtype_option_variant_test.v @@ -10,3 +10,32 @@ fn test_main() { d := ?Any('baz') assert d?.str() == "Any('baz')" } + +struct Bar { + i int +} + +struct Baz {} + +type Foo = ?Bar | Baz + +// `as`/`is` on an option-type sumtype variant must reference the correct +// union member (`_option_...`), not the plain one. See vlang/v#27478. +fn test_as_is_option_variant() { + f := Foo(?Bar(Bar{ + i: 5 + })) + assert f is ?Bar + got := f as ?Bar + assert got != none + assert got?.i == 5 + + n := Foo(?Bar(none)) + assert n is ?Bar + got2 := n as ?Bar + assert got2 == none + + b := Foo(Baz{}) + assert b is Baz + assert b !is ?Bar +} -- 2.39.5