From 031d77523ddbe69a43bb988d34b41577d8c07d33 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 23 Apr 2026 21:07:24 +0300 Subject: [PATCH] cgen: fix V panic: as cast: cannot cast `v.ast.FnType` to `v.ast.Struct` (fixes #26944) --- vlib/v/gen/c/struct.v | 67 +++++++++++++------ .../tests/structs/struct_embed_fn_type_test.v | 6 ++ 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index 47a11a65c..e46b0c72d 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -289,34 +289,57 @@ fn (mut g Gen) struct_init(node ast.StructInit) { embed_sym := g.table.sym(embed) embed_name := embed_sym.embed_name() if embed_name !in inited_fields { - embed_info := if embed_sym.info is ast.Struct { - embed_sym.info + mut embed_info := ast.Struct{} + mut has_embed_struct_info := false + if embed_sym.info is ast.Struct { + embed_info = embed_sym.info + has_embed_struct_info = true } else { - g.table.final_sym(embed).info as ast.Struct - } - embed_field_names := embed_info.fields.map(it.name) - fields_to_embed := init_fields_to_embed.filter(it.name !in used_embed_fields - && it.name in embed_field_names) - used_embed_fields << fields_to_embed.map(it.name) - default_init := ast.StructInit{ - ...node - typ: embed - is_update_embed: true - init_fields: init_fields_to_embed + final_embed_sym := g.table.final_sym(embed) + if final_embed_sym.info is ast.Struct { + embed_info = final_embed_sym.info + has_embed_struct_info = true + } } - inside_cast_in_heap := g.inside_cast_in_heap - g.inside_cast_in_heap = 0 // prevent use of pointers in child structs + if has_embed_struct_info { + embed_field_names := embed_info.fields.map(it.name) + fields_to_embed := init_fields_to_embed.filter( + it.name !in used_embed_fields && it.name in embed_field_names) + used_embed_fields << fields_to_embed.map(it.name) + default_init := ast.StructInit{ + ...node + typ: embed + is_update_embed: true + init_fields: init_fields_to_embed + } + inside_cast_in_heap := g.inside_cast_in_heap + g.inside_cast_in_heap = 0 // prevent use of pointers in child structs - g.write('.${embed_name} = ') - g.struct_init(default_init) + g.write('.${embed_name} = ') + g.struct_init(default_init) - g.inside_cast_in_heap = inside_cast_in_heap // restore value for further struct inits - if is_multiline { - g.writeln(',') + g.inside_cast_in_heap = inside_cast_in_heap // restore value for further struct inits + if is_multiline { + g.writeln(',') + } else { + g.write(',') + } + initialized = true } else { - g.write(',') + // Embedded fn/interface/alias fields do not have child fields to recurse into. + if g.zero_struct_field(ast.StructField{ + name: embed_name + typ: embed + }) + { + if is_multiline { + g.writeln(',') + } else { + g.write(',') + } + initialized = true + } } - initialized = true } } g.is_shared = old_is_shared2 diff --git a/vlib/v/tests/structs/struct_embed_fn_type_test.v b/vlib/v/tests/structs/struct_embed_fn_type_test.v index 4bca7712c..324768ac6 100644 --- a/vlib/v/tests/structs/struct_embed_fn_type_test.v +++ b/vlib/v/tests/structs/struct_embed_fn_type_test.v @@ -72,3 +72,9 @@ fn test_embed_named_fn_type_promotes_methods() { assert one == 'one' assert more == 'more' } + +fn test_embed_named_fn_type_zero_init() { + mut cmd := CommandSet{} + cmd.CommandFn = run_command + assert cmd.one() == 'one' +} -- 2.39.5