From c19b13e1651808a9d4947761ef4b2535cde934bf Mon Sep 17 00:00:00 2001 From: shove Date: Fri, 1 Dec 2023 05:26:21 +0800 Subject: [PATCH] ast: fix generic structs with multiple levels of generic embedding (#20042) --- vlib/v/ast/table.v | 14 +++++++++++++ ...enerics_with_embed_generics_structs_test.v | 21 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 4c8b30e786..31ad11baf1 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1936,6 +1936,7 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr fields = ts.info.fields.clone() for i in 0 .. fields.len { if fields[i].typ.has_flag(.generic) { + orig_type := fields[i].typ sym := t.sym(fields[i].typ) if sym.kind == .struct_ && fields[i].typ.idx() != typ.idx() { fields[i].typ = t.unwrap_generic_type(fields[i].typ, t_generic_names, @@ -1947,6 +1948,19 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr fields[i].typ = t_typ } } + // Update type in `info.embeds`, if it's embed + if fields[i].name.len > 1 && fields[i].name[0].is_capital() { + mut parent_sym := t.sym(typ) + mut parent_info := parent_sym.info + if mut parent_info is Struct { + for mut embed in parent_info.embeds { + if embed == orig_type { + embed = fields[i].typ.set_flag(.generic) + break + } + } + } + } } } // update concrete types diff --git a/vlib/v/tests/generics_with_embed_generics_structs_test.v b/vlib/v/tests/generics_with_embed_generics_structs_test.v index 88353f94a4..28c6312c02 100644 --- a/vlib/v/tests/generics_with_embed_generics_structs_test.v +++ b/vlib/v/tests/generics_with_embed_generics_structs_test.v @@ -2,11 +2,28 @@ struct Foo[T] { field T } -struct MainStruct[T] { +struct Bar[T] { + Foo[T] +} + +struct Baz[T] { + Bar[T] +} + +struct OneLevelEmbed[T] { Foo[T] } fn test_main() { - m := MainStruct[int]{} + m := OneLevelEmbed[int]{} + assert m.field == 0 +} + +struct MultiLevelEmbed[T] { + Baz[T] +} + +fn test_multi_level() { + m := MultiLevelEmbed[int]{} assert m.field == 0 }