From a6764e3cc3a092f55e0cedd72b731488b1f280fc Mon Sep 17 00:00:00 2001 From: yuyi Date: Fri, 7 May 2021 01:24:08 +0800 Subject: [PATCH] table: fix generics struct with anon fn fields (#10024) --- vlib/v/ast/table.v | 61 ++++++++++++------- .../generics_struct_anon_fn_fields_test.v | 14 +++++ 2 files changed, 54 insertions(+), 21 deletions(-) create mode 100644 vlib/v/tests/generics_struct_anon_fn_fields_test.v diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index e230be06b4..1b364ea526 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -63,30 +63,29 @@ pub fn (t &Table) panic(message string) { pub struct Fn { pub: - return_type Type - is_variadic bool - language Language - generic_names []string - is_pub bool - is_deprecated bool // `[deprecated] fn abc(){}` - is_unsafe bool // `[unsafe] fn abc(){}` - is_placeholder bool - is_main bool // `fn main(){}` - is_test bool // `fn test_abc(){}` - is_conditional bool // `[if abc]fn(){}` - is_keep_alive bool // passed memory must not be freed (by GC) before function returns - no_body bool // a pure declaration like `fn abc(x int)`; used in .vh files, C./JS. fns. - mod string - ctdefine string // compile time define. "myflag", when [if myflag] tag - attrs []Attr - // + is_variadic bool + language Language + generic_names []string + is_pub bool + is_deprecated bool // `[deprecated] fn abc(){}` + is_unsafe bool // `[unsafe] fn abc(){}` + is_placeholder bool + is_main bool // `fn main(){}` + is_test bool // `fn test_abc(){}` + is_conditional bool // `[if abc]fn(){}` + is_keep_alive bool // passed memory must not be freed (by GC) before function returns + no_body bool // a pure declaration like `fn abc(x int)`; used in .vh files, C./JS. fns. + mod string + ctdefine string // compile time define. "myflag", when [if myflag] tag + attrs []Attr pos token.Position return_type_pos token.Position pub mut: - name string - params []Param - source_fn voidptr // set in the checker, while processing fn declarations - usages int + return_type Type + name string + params []Param + source_fn voidptr // set in the checker, while processing fn declarations + usages int } fn (f &Fn) method_equals(o &Fn) bool { @@ -1108,6 +1107,26 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name } return new_type(idx).derive(generic_type).clear_flag(.generic) } + } else if mut sym.info is FnType { + mut func := sym.info.func + if func.return_type.has_flag(.generic) { + if typ := t.resolve_generic_to_concrete(func.return_type, generic_names, concrete_types, + is_inst) + { + func.return_type = typ + } + } + for mut param in func.params { + if param.typ.has_flag(.generic) { + if typ := t.resolve_generic_to_concrete(param.typ, generic_names, concrete_types, + is_inst) + { + param.typ = typ + } + } + } + idx := t.find_or_register_fn_type('', func, true, false) + return new_type(idx).derive(generic_type).clear_flag(.generic) } return none } diff --git a/vlib/v/tests/generics_struct_anon_fn_fields_test.v b/vlib/v/tests/generics_struct_anon_fn_fields_test.v new file mode 100644 index 0000000000..a20e1630cc --- /dev/null +++ b/vlib/v/tests/generics_struct_anon_fn_fields_test.v @@ -0,0 +1,14 @@ +struct Scope { + before fn () T + specs []fn (T) T + after fn (T) +} + +fn test_generics_struct_anon_fn_fields() { + s := Scope{} + println(s) + ts := '$s' + assert ts.contains('before: fn () u32') + assert ts.contains('specs: []') + assert ts.contains('after: fn (u32)') +}