From 14b7ce0f0435b499095f12a1f0f5c79750426c25 Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 13 May 2021 17:26:13 +0800 Subject: [PATCH] checker: fix generics fn return generics fn type (fix #10085) (#10088) --- vlib/v/ast/types.v | 2 +- vlib/v/checker/check_types.v | 9 +++ ...generics_fn_return_generics_fn_type_test.v | 60 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/generics_with_generics_fn_return_generics_fn_type_test.v diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 70d056d561..9df8e27580 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -426,7 +426,7 @@ pub mut: } pub struct FnType { -pub: +pub mut: is_anon bool has_decl bool func Fn diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 010efc8b62..a4657b60e6 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -508,6 +508,15 @@ pub fn (mut c Checker) infer_fn_generic_types(f ast.Fn, mut call_expr ast.CallEx if param.typ.has_flag(.generic) && param_type_sym.name == gt_name { to_set = c.table.mktyp(arg.typ) + mut sym := c.table.get_type_symbol(arg.typ) + if mut sym.info is ast.FnType { + if !sym.info.is_anon { + sym.info.func.name = '' + idx := c.table.find_or_register_fn_type(c.mod, sym.info.func, + true, false) + to_set = ast.new_type(idx).derive(arg.typ) + } + } if arg.expr.is_auto_deref_var() { to_set = to_set.deref() } diff --git a/vlib/v/tests/generics_with_generics_fn_return_generics_fn_type_test.v b/vlib/v/tests/generics_with_generics_fn_return_generics_fn_type_test.v new file mode 100644 index 0000000000..d69f06fc50 --- /dev/null +++ b/vlib/v/tests/generics_with_generics_fn_return_generics_fn_type_test.v @@ -0,0 +1,60 @@ +fn neg(a int) int { + return -a +} + +fn normal_v1(func fn (int) int) fn (int) int { + assert typeof(func).name == typeof(neg).name + return func +} + +fn normal_v2(func fn (int) int) fn (int) int { + f := func + assert typeof(f).name == typeof(neg).name + return f +} + +fn generic_v1(func T) T { + assert T.name == typeof(neg).name + assert typeof(func).name == typeof(neg).name + return func +} + +fn generic_v2(func T) T { + assert T.name == typeof(neg).name + f := func + assert typeof(f).name == typeof(neg).name + return f +} + +fn mixed_v1(func T) fn (int) int { + assert T.name == typeof(neg).name + assert typeof(func).name == typeof(neg).name + return func +} + +fn mixed_v2(func T) fn (int) int { + assert T.name == typeof(neg).name + f := func + assert typeof(f).name == typeof(neg).name + return f +} + +fn test_generics_with_generics_fn_return_type() { + mut f := neg + assert f(1) == -1 + + f = normal_v1(neg) + assert f(2) == -2 + f = normal_v2(neg) + assert f(3) == -3 + + f = generic_v1(neg) + assert f(4) == -4 + f = generic_v2(neg) + assert f(5) == -5 + + f = mixed_v1(neg) + assert f(6) == -6 + f = mixed_v2(neg) + assert f(7) == -7 +}