From 7a0d92e15341ef79aea10e64d8012e2d085829dc Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 11 Mar 2026 12:41:44 +0300 Subject: [PATCH] json2: features required for complete generic json implementation (fixes #25218) --- vlib/v/gen/c/cgen.v | 18 +++++++++--- .../sumtype_alias_init_by_variant_test.v | 29 +++++++++++++++++++ vlib/x/json2/decode_sumtype.v | 28 +++++------------- vlib/x/json2/tests/json_sumtype_test.v | 27 ++++++++--------- 4 files changed, 64 insertions(+), 38 deletions(-) create mode 100644 vlib/v/tests/sumtype_alias_init_by_variant_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 49f91ec47..a6451bf5c 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6236,14 +6236,24 @@ fn (mut g Gen) cast_expr(node ast.CastExpr) { g.expr_with_opt(node.expr, expr_type, sym.info.parent_type) } else { g.write('(${cast_label}') - expr_typ := ast.mktyp(node.expr_type) + is_comptime_variant_expr := node.expr is ast.Ident + && g.comptime.is_comptime_variant_var(node.expr) + mut expr_typ := ast.mktyp(expr_type) + if is_comptime_variant_expr { + expr_typ = g.type_resolver.get_ct_type_or_default('${g.comptime.comptime_for_variant_var}.typ', + ast.void_type) + } alias_to_sumtype := sym.info is ast.Alias && g.table.sumtype_has_variant(sym.info.parent_type, expr_typ, false) if alias_to_sumtype { expr_styp := g.styp(expr_typ) - g.write('{._${g.table.sym(expr_typ).cname}=builtin__memdup(ADDR(${expr_styp}, ') - g.expr(node.expr) - g.write('), sizeof(${expr_styp})),._typ=${u32(expr_typ)}})') + g.write('{._${g.table.sym(expr_typ).cname}=builtin__memdup(ADDR(${expr_styp}, (') + if is_comptime_variant_expr { + g.write(g.type_default(expr_typ)) + } else { + g.expr(node.expr) + } + g.write(')), sizeof(${expr_styp})),._typ=${u32(expr_typ)}})') } else { old_inside_assign_fn_var := g.inside_assign_fn_var g.inside_assign_fn_var = final_expr_sym.kind == .function diff --git a/vlib/v/tests/sumtype_alias_init_by_variant_test.v b/vlib/v/tests/sumtype_alias_init_by_variant_test.v new file mode 100644 index 000000000..09a9d9be3 --- /dev/null +++ b/vlib/v/tests/sumtype_alias_init_by_variant_test.v @@ -0,0 +1,29 @@ +type Sum = int | string +type SumAlias = Sum + +fn get_alias[T](val T, type_name string) T { + $if T is $alias && T.unaliased_typ is $sumtype { + $for v in val.variants { + if type_name == typeof(v.typ).name { + return T(v) + } + } + } + return T{} +} + +fn test_sumtype_alias_init_by_variant_name() { + a_int := get_alias(SumAlias(Sum(10)), 'int') + if a_int is int { + assert a_int == 0 + } else { + assert false + } + + a_str := get_alias(SumAlias('foo'), 'string') + if a_str is string { + assert a_str == '' + } else { + assert false + } +} diff --git a/vlib/x/json2/decode_sumtype.v b/vlib/x/json2/decode_sumtype.v index fd624e333..eabfed674 100644 --- a/vlib/x/json2/decode_sumtype.v +++ b/vlib/x/json2/decode_sumtype.v @@ -7,7 +7,7 @@ fn copy_type[T](_t T) T { } fn (mut decoder Decoder) get_decoded_sumtype_workaround[T](initialized_sumtype T) !T { - $if initialized_sumtype is $sumtype { + $if initialized_sumtype is $sumtype || (T is $alias && T.unaliased_typ is $sumtype) { $for v in initialized_sumtype.variants { if initialized_sumtype is v { $if initialized_sumtype !is $option { @@ -106,7 +106,7 @@ fn (mut decoder Decoder) check_array_type_valid[T](arr []T, current_node &Node[V } fn (mut decoder Decoder) get_array_type_workaround[T](initialized_sumtype T) bool { - $if initialized_sumtype is $sumtype { + $if initialized_sumtype is $sumtype || (T is $alias && T.unaliased_typ is $sumtype) { $for v in initialized_sumtype.variants { if initialized_sumtype is v { $if initialized_sumtype is $array { @@ -133,7 +133,7 @@ fn (mut decoder Decoder) check_map_empty_valid[T](m T) bool { } fn (mut decoder Decoder) get_map_type_workaround[T](initialized_sumtype T) bool { - $if initialized_sumtype is $sumtype { + $if initialized_sumtype is $sumtype || (T is $alias && T.unaliased_typ is $sumtype) { $for v in initialized_sumtype.variants { if initialized_sumtype is v { $if initialized_sumtype is $map { @@ -210,7 +210,7 @@ fn (mut decoder Decoder) check_struct_type_valid[T](s T, current_node &Node[Valu } fn (mut decoder Decoder) get_struct_type_workaround[T](initialized_sumtype T) bool { - $if initialized_sumtype is $sumtype { + $if initialized_sumtype is $sumtype || (T is $alias && T.unaliased_typ is $sumtype) { $for v in initialized_sumtype.variants { if initialized_sumtype is v { $if initialized_sumtype is $struct { @@ -328,23 +328,9 @@ fn (mut decoder Decoder) init_sumtype_by_value_kind[T](mut val T, value_info Val } fn (mut decoder Decoder) decode_sumtype[T](mut val T) ! { - $if T is $alias { - $if T.unaliased_typ is Any { - mut unaliased_val := Any{} - value_info := decoder.current_node.value + value_info := decoder.current_node.value - decoder.init_sumtype_by_value_kind(mut unaliased_val, value_info)! + decoder.init_sumtype_by_value_kind(mut val, value_info)! - unaliased_val = decoder.get_decoded_sumtype_workaround(unaliased_val)! - val = T(unaliased_val) - } $else { - decoder.decode_error('Type aliased sumtypes not supported.')! - } - } $else { - value_info := decoder.current_node.value - - decoder.init_sumtype_by_value_kind(mut val, value_info)! - - val = decoder.get_decoded_sumtype_workaround(val)! - } + val = decoder.get_decoded_sumtype_workaround(val)! } diff --git a/vlib/x/json2/tests/json_sumtype_test.v b/vlib/x/json2/tests/json_sumtype_test.v index ecf433ab2..e1e7f4c0a 100644 --- a/vlib/x/json2/tests/json_sumtype_test.v +++ b/vlib/x/json2/tests/json_sumtype_test.v @@ -43,6 +43,10 @@ type StructLists = Cat | []Cat | map[string]Dog type SumAlias = Sum +struct AliasWrap { + val SumAlias +} + struct Empty1 { a ?string @[omitempty] } @@ -163,18 +167,15 @@ fn test_sum_type_options_fail() { } } -// to be implemented -fn test_sum_type_alias_fail() { - if x := json.decode[SumAlias]('99') { - assert false - } - if x := json.decode[SumAlias]('true') { - assert false - } - if x := json.decode[SumAlias]('["hi", "bye"]') { - assert false - } - if x := json.decode[SumAlias]('[0, 1]') { - assert false +fn test_sum_type_alias() { + assert json.decode[SumAlias]('99')! == SumAlias(99) + assert json.decode[SumAlias]('"hi"')! == SumAlias('hi') + assert json.decode[SumAlias]('true')! == SumAlias(true) + assert json.decode[SumAlias]('["hi", "bye"]')! == SumAlias(['hi', 'bye']) + + assert json.decode[AliasWrap]('{"val": 99}')! == AliasWrap{ + val: SumAlias(99) } + assert json.decode[[]SumAlias]('[99, "hi", true, ["bye"]]')! == [SumAlias(99), SumAlias('hi'), + SumAlias(true), SumAlias(['bye'])] } -- 2.39.5