From 2874e7cac0c36e36d5a498d978c4694d77d17896 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Tue, 23 Jan 2024 12:29:32 -0300 Subject: [PATCH] cgen: fix interface generic smartcast (#20609) --- vlib/v/gen/c/cgen.v | 6 ++-- vlib/v/tests/generic_smartcast_test.v | 46 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 vlib/v/tests/generic_smartcast_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 3aa3b87baa6a68..726c117867274c 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4649,7 +4649,7 @@ fn (mut g Gen) ident(node ast.Ident) { g.write('(*(') } if node.obj.smartcasts.len > 0 { - obj_sym := g.table.sym(node.obj.typ) + obj_sym := g.table.sym(g.unwrap_generic(node.obj.typ)) if !prevent_sum_type_unwrapping_once { for _, typ in node.obj.smartcasts { is_option_unwrap := is_option && typ == node.obj.typ.clear_flag(.option) @@ -4665,7 +4665,9 @@ fn (mut g Gen) ident(node ast.Ident) { g.write('*') } } else if (g.inside_interface_deref && g.table.is_interface_var(node.obj)) - || node.obj.ct_type_var == .smartcast { + || node.obj.ct_type_var == .smartcast + || (obj_sym.kind == .interface_ + && g.table.type_kind(node.obj.typ) == .any) { g.write('*') } else if is_option { g.write('*(${g.base_type(node.obj.typ)}*)') diff --git a/vlib/v/tests/generic_smartcast_test.v b/vlib/v/tests/generic_smartcast_test.v new file mode 100644 index 00000000000000..02c9e8d23c86c4 --- /dev/null +++ b/vlib/v/tests/generic_smartcast_test.v @@ -0,0 +1,46 @@ +fn cast_interface[T, U](u U) T { + $if U is $interface { + if u is T { + return u + } else { + panic('expected t to be ${typeof[T]().name}, got ${typeof[U]().name}') + } + } $else { + $compile_error('not an interface') + } +} + +interface Foo { + f() +} + +struct Bar {} + +fn (bar Bar) f() {} + +struct Baz {} + +fn (baz Baz) f() {} + +fn (_ Bar) g() int { + return 0 +} + +fn (_ Baz) g() int { + return 1 +} + +fn f(foo Foo) int { + if foo is Bar { + return cast_interface[Bar, Foo](foo).g() + } + if foo is Baz { + return cast_interface[Baz, Foo](foo).g() + } + return -1 +} + +fn test_main() { + assert f(Bar{}) == 0 + assert f(Baz{}) == 1 +}