From 1da7965794bfbf4a3b4e8c9dc114bf0f4257f40a Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 3 Dec 2024 16:10:11 +0800 Subject: [PATCH] parser, checker: fix generic fn returning generic closure (related #23047) (#23055) --- vlib/v/checker/return.v | 5 ----- ...generics_fn_return_generic_closure_err.out | 6 ++++++ .../generics_fn_return_generic_closure_err.vv | 16 +++++++++++++++ vlib/v/parser/fn.v | 6 +++++- .../generics/generics_return_closure_test.v | 20 ++++++++++++++----- 5 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 vlib/v/checker/tests/generics_fn_return_generic_closure_err.out create mode 100644 vlib/v/checker/tests/generics_fn_return_generic_closure_err.vv diff --git a/vlib/v/checker/return.v b/vlib/v/checker/return.v index 805f20f91..e970f72dc 100644 --- a/vlib/v/checker/return.v +++ b/vlib/v/checker/return.v @@ -267,11 +267,6 @@ fn (mut c Checker) return_stmt(mut node ast.Return) { if c.inside_lambda && exp_type.has_flag(.generic) { continue } - // ignore return closure - if node.exprs[expr_idxs[i]] is ast.AnonFn - && node.exprs[expr_idxs[i]].inherited_vars.len > 0 { - continue - } c.error('cannot use `${got_type_name}` as ${c.error_type_name(exp_type)} in return argument', pos) } diff --git a/vlib/v/checker/tests/generics_fn_return_generic_closure_err.out b/vlib/v/checker/tests/generics_fn_return_generic_closure_err.out new file mode 100644 index 000000000..568c1f6f0 --- /dev/null +++ b/vlib/v/checker/tests/generics_fn_return_generic_closure_err.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/generics_fn_return_generic_closure_err.vv:2:9: error: cannot use `fn (f64) []f64` as type `fn ([]f64) []f64` in return argument + 1 | fn vectorize[T](op fn (T) T) fn ([]T) []T { + 2 | return fn [op] [T](values T) []T { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 3 | mut result := []T{} + 4 | return result diff --git a/vlib/v/checker/tests/generics_fn_return_generic_closure_err.vv b/vlib/v/checker/tests/generics_fn_return_generic_closure_err.vv new file mode 100644 index 000000000..5c321b72c --- /dev/null +++ b/vlib/v/checker/tests/generics_fn_return_generic_closure_err.vv @@ -0,0 +1,16 @@ +fn vectorize[T](op fn (T) T) fn ([]T) []T { + return fn [op] [T](values T) []T { + mut result := []T{} + return result + } +} + +fn add_one(x f64) f64 { + return x + 1 +} + +fn main() { + vadd := vectorize[f64](add_one) + v := [1.0, 2, 3, 4] + println(vadd(v)) +} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 146291971..6cf6d0a7b 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -889,7 +889,11 @@ fn (mut p Parser) anon_fn() ast.AnonFn { p.cur_fn_name = keep_fn_name func.name = name idx := p.table.find_or_register_fn_type(func, true, false) - typ := ast.new_type(idx) + typ := if generic_names.len > 0 { + ast.new_type(idx).set_flag(.generic) + } else { + ast.new_type(idx) + } p.inside_defer = old_inside_defer // name := p.table.get_type_name(typ) return ast.AnonFn{ diff --git a/vlib/v/tests/generics/generics_return_closure_test.v b/vlib/v/tests/generics/generics_return_closure_test.v index 07a2f2791..1e6d2e1d7 100644 --- a/vlib/v/tests/generics/generics_return_closure_test.v +++ b/vlib/v/tests/generics/generics_return_closure_test.v @@ -8,12 +8,22 @@ fn vectorize[T](op fn (T) T) fn ([]T) []T { } } -fn add_one(x f64) f64 { +fn add_one1(x f64) f64 { return x + 1 } -fn test_return_generic_closure() { - vadd := vectorize[f64](add_one) - v := [1.0, 2, 3, 4] - assert vadd(v) == [2.0, 3, 4, 5] +fn add_one2(x int) int { + return x + 1 +} + +fn test_generic_return_generic_closure() { + vadd1 := vectorize[f64](add_one1) + v1 := [1.0, 2, 3, 4] + println(vadd1(v1)) + assert vadd1(v1) == [2.0, 3, 4, 5] + + vadd2 := vectorize[int](add_one2) + v2 := [1, 2, 3, 4] + println(vadd2(v2)) + assert vadd2(v2) == [2, 3, 4, 5] } -- 2.39.5