From 5cc591b2b662292a13ff4c01ef8625b42c08936b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Mon, 18 Jan 2021 18:37:45 +0100 Subject: [PATCH] all: support generic `chan` (#8188) --- vlib/v/checker/checker.v | 14 ++++++++++++++ vlib/v/gen/cgen.v | 11 +++++++---- vlib/v/tests/generic_chan_test.v | 22 ++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 vlib/v/tests/generic_chan_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 560e67e413..a2346fa769 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1523,6 +1523,14 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { idx := c.table.find_or_register_array(call_expr.generic_type) return table.new_type(idx) } + } else if return_sym.kind == .chan { + elem_info := return_sym.info as table.Chan + elem_sym := c.table.get_type_symbol(elem_info.elem_type) + if elem_sym.name == 'T' { + idx := c.table.find_or_register_chan(elem_info.elem_type, elem_info.elem_type.nr_muls() > + 0) + return table.new_type(idx) + } } } if call_expr.generic_type.is_full() && !method.is_generic { @@ -1862,6 +1870,12 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { typ := table.new_type(idx) call_expr.return_type = typ return typ + } else if return_sym.kind == .chan && return_sym.name.contains('T') { + idx := c.table.find_or_register_chan(call_expr.generic_type, call_expr.generic_type.nr_muls() > + 0) + typ := table.new_type(idx) + call_expr.return_type = typ + return typ } } if call_expr.generic_type.is_full() && !f.is_generic { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 8c8b7e96c0..2a882880b8 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -681,17 +681,20 @@ typedef struct { if typ.name != 'chan' { g.type_definitions.writeln('typedef chan $typ.cname;') chan_inf := typ.chan_info() - el_stype := g.typ(chan_inf.elem_type) - g.channel_definitions.writeln(' + chan_elem_type := chan_inf.elem_type + if !chan_elem_type.has_flag(.generic) { + el_stype := g.typ(chan_elem_type) + g.channel_definitions.writeln(' static inline $el_stype __${typ.cname}_popval($typ.cname ch) { $el_stype val; sync__Channel_try_pop_priv(ch, &val, false); return val; }') - g.channel_definitions.writeln(' + g.channel_definitions.writeln(' static inline void __${typ.cname}_pushval($typ.cname ch, $el_stype val) { sync__Channel_try_push_priv(ch, &val, false); }') + } } } .map { @@ -712,7 +715,7 @@ pub fn (mut g Gen) write_fn_typesymbol_declaration(sym table.TypeSymbol) { func := info.func is_fn_sig := func.name == '' not_anon := !info.is_anon - if !info.has_decl && (not_anon || is_fn_sig) { + if !info.has_decl && (not_anon || is_fn_sig) && !func.return_type.has_flag(.generic) { fn_name := sym.cname g.type_definitions.write('typedef ${g.typ(func.return_type)} (*$fn_name)(') for i, param in func.params { diff --git a/vlib/v/tests/generic_chan_test.v b/vlib/v/tests/generic_chan_test.v new file mode 100644 index 0000000000..a7aaf057d3 --- /dev/null +++ b/vlib/v/tests/generic_chan_test.v @@ -0,0 +1,22 @@ +fn mk_chan(f fn () T) chan T { + gench := chan T{cap: 1} + // // This does not work, yet + // go fn(ch2 chan T, f2 fn() T) { + // res := f2() + // ch2 <- res + // }(gench, f) + return gench +} + +fn g(x f64, y f64) f64 { + return x * x + y * y +} + +fn test_generic_chan_return() { + ch := mk_chan(fn () f64 { + return g(3, 4) + }) + ch <- 13.4 + res := <-ch + assert res == 13.4 +}