From a98376025e3582d0e560dbc67f69a88df959f74c Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 11 Mar 2023 06:57:41 -0300 Subject: [PATCH] checker: fix missing re-check of recursive generic function (fix #16962) (#17592) --- vlib/v/checker/fn.v | 15 ++++++++-- vlib/v/tests/generic_struct_test.v | 44 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 vlib/v/tests/generic_struct_test.v diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 47e1a6011c..a3f6954ae4 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1598,18 +1598,27 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { arg_sym := c.table.sym(c.comptime_fields_default_type) if arg_sym.kind == .array && c.table.sym(method.params[param_idx].typ).kind == .array { - c.table.register_fn_concrete_types(method.fkey(), [ + if c.table.register_fn_concrete_types(method.fkey(), [ (arg_sym.info as ast.Array).elem_type, ]) + { + c.need_recheck_generic_fns = true + } } else { - c.table.register_fn_concrete_types(method.fkey(), [ + if c.table.register_fn_concrete_types(method.fkey(), [ c.comptime_fields_default_type, ]) + { + c.need_recheck_generic_fns = true + } } } else if c.inside_for_in_any_cond && method.params[param_idx].typ.has_flag(.generic) { - c.table.register_fn_concrete_types(method.fkey(), [ + if c.table.register_fn_concrete_types(method.fkey(), [ c.for_in_any_val_type, ]) + { + c.need_recheck_generic_fns = true + } } if no_type_promotion { if got_arg_typ != exp_arg_typ { diff --git a/vlib/v/tests/generic_struct_test.v b/vlib/v/tests/generic_struct_test.v new file mode 100644 index 0000000000..d4a93e7794 --- /dev/null +++ b/vlib/v/tests/generic_struct_test.v @@ -0,0 +1,44 @@ +struct Test {} + +fn (t Test) test[T](val T) { + $for f in T.fields { + value := val.$(f.name) + $if f.is_option { + $if f.typ is $Struct { + _ := 1 + t.test(value) + } $else $if f.typ is string { + _ := 2 + } $else $if f.typ is ?string { + _ := 3 + } $else { + _ := 4 + } + } $else { + $if f.typ is $Struct { + t.test(value) + } $else $if f.typ is string { + _ := 5 + } + } + } +} + +struct Bb { + a ?string +} + +struct Cc { + b Bb +} + +struct Aa[T] { + a T +} + +fn test_main() { + a := Aa[Cc]{} + t := Test{} + t.test(a) + assert true +}