From 7815621b7ae2e0cb338a306b8e38d0ff8e2491a7 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 11 Mar 2026 11:50:20 +0300 Subject: [PATCH] cgen: cannot use interface b as interface a, although interface b embeds interface a (fixes #18864) --- vlib/v/gen/c/cgen.v | 22 +++++++++++- ...ace_embedding_to_base_interface_arg_test.v | 36 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/interfaces/interface_embedding_to_base_interface_arg_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index e019b9e91..42f882b00 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3311,6 +3311,26 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ g.expr(expr) return } + if got_sym.info is ast.Interface && exp_sym.info is ast.Interface + && got_type.idx() != expected_type.idx() && !expected_type.has_flag(.result) { + g.write('I_${got_sym.cname}_as_I_${exp_sym.cname}(') + if got_type.is_ptr() { + g.write('*') + } + g.expr(expr) + g.write(')') + mut info := got_sym.info as ast.Interface + lock info.conversions { + if expected_type !in info.conversions { + left_variants := g.table.iface_types[got_sym.name] + right_variants := g.table.iface_types[exp_sym.name] + info.conversions[expected_type] = left_variants.filter(it in right_variants) + } + } + mut got_interface_sym := g.table.sym(got_type) + got_interface_sym.info = info + return + } if got_sym.info !is ast.Interface && exp_sym.info is ast.Interface && got_type.idx() != expected_type.idx() && !expected_type.has_flag(.result) { if expr is ast.StructInit && !got_type.is_ptr() { @@ -8898,7 +8918,7 @@ return ${cast_shared_struct_str}; pmessage := 'builtin__string__plus(builtin__string__plus(_S("`as_cast`: cannot convert "), v_typeof_interface_${interface_name}(x._typ)), _S(" to ${util.strip_main_name(vsym.name)}"))' if g.pref.is_debug { // TODO: actually return a valid position here - conversion_functions.write_string2('\tbuiltin__panic_debug(1, builtin__tos3("builtin.v"), builtin__tos3("builtin"), builtin__tos3("__as_cast"), ', + conversion_functions.write_string2('\tbuiltin__panic_debug(1, _S("builtin.v"), _S("builtin"), _S("__as_cast"), ', pmessage) conversion_functions.writeln(');') } else { diff --git a/vlib/v/tests/interfaces/interface_embedding_to_base_interface_arg_test.v b/vlib/v/tests/interfaces/interface_embedding_to_base_interface_arg_test.v new file mode 100644 index 000000000..677276c75 --- /dev/null +++ b/vlib/v/tests/interfaces/interface_embedding_to_base_interface_arg_test.v @@ -0,0 +1,36 @@ +interface Reader { + read(p []u8) !int +} + +interface Writer { + write(p []u8) !int +} + +interface ReaderWriter { + Reader + Writer +} + +struct Thing {} + +fn (t Thing) read(p []u8) !int { + return p.len +} + +fn (t Thing) write(p []u8) !int { + return p.len +} + +fn read_at_least(r Reader, buf []u8, min int) !int { + _ = min + return r.read(buf) +} + +fn use_reader_writer(rw ReaderWriter) !int { + return read_at_least(rw, [u8(1), 2], 1) +} + +fn test_interface_embedding_allows_passing_embed_to_base_interface_arg() { + got := use_reader_writer(Thing{}) or { panic(err) } + assert got == 2 +} -- 2.39.5