diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 8acbdf5d6c..7b2d2a7698 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1654,6 +1654,26 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { } node.return_type = left_sym.info.return_type return left_sym.info.return_type + } else if final_left_sym.info is ast.ArrayFixed && method_name == 'wait' { + elem_sym := c.table.sym(final_left_sym.info.elem_type) + if elem_sym.kind == .thread { + if node.args.len != 0 { + c.error('`.wait()` does not have any arguments', node.args[0].pos) + } + thread_ret_type := c.unwrap_generic(elem_sym.thread_info().return_type) + if thread_ret_type.has_flag(.option) { + c.error('`.wait()` cannot be called for an array when thread functions return options. Iterate over the arrays elements instead and handle each returned option with `or`.', + node.pos) + } else if thread_ret_type.has_flag(.result) { + c.error('`.wait()` cannot be called for an array when thread functions return results. Iterate over the arrays elements instead and handle each returned result with `or`.', + node.pos) + } + node.return_type = c.table.find_or_register_array(thread_ret_type) + return node.return_type + } else { + c.error('`${left_sym.name}` has no method `wait()` (only thread handles and arrays of them have)', + node.left.pos()) + } } else if left_sym.kind == .char && left_type.nr_muls() == 0 && method_name == 'str' { c.error('calling `.str()` on type `char` is not allowed, use its address or cast it to an integer instead', node.left.pos().extend(node.pos)) diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index b1c978097a..6dc9dc64d0 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -1067,6 +1067,18 @@ fn (mut g Gen) gen_array_wait(node ast.CallExpr) { g.write(')') } +fn (mut g Gen) gen_fixed_array_wait(node ast.CallExpr) { + arr := g.table.sym(g.unwrap_generic(node.receiver_type)) + thread_type := arr.array_fixed_info().elem_type + thread_sym := g.table.sym(thread_type) + thread_ret_type := thread_sym.thread_info().return_type + eltyp := g.table.sym(thread_ret_type).cname + fn_name := g.register_thread_fixed_array_wait_call(node, eltyp) + g.write('${fn_name}(') + g.expr(node.left) + g.write(')') +} + fn (mut g Gen) gen_array_any(node ast.CallExpr) { tmp := g.new_tmp_var() mut s := g.go_before_stmt(0) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 907ddf20fc..b34886a590 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1287,6 +1287,52 @@ ${ret_typ} ${fn_name}(${thread_arr_typ} a) { return fn_name } +fn (mut g Gen) register_thread_fixed_array_wait_call(node ast.CallExpr, eltyp string) string { + is_void := eltyp == 'void' + thread_typ := if is_void { '__v_thread' } else { '__v_thread_${eltyp}' } + ret_typ := if is_void { 'void' } else { 'Array_${eltyp}' } + rec_sym := g.table.sym(node.receiver_type) + len := (rec_sym.info as ast.ArrayFixed).size + thread_arr_typ := rec_sym.cname + fn_name := '${thread_arr_typ}_wait' + mut should_register := false + lock g.waiter_fns { + if fn_name !in g.waiter_fns { + g.waiter_fns << fn_name + should_register = true + } + } + if should_register { + if is_void { + g.register_thread_void_wait_call() + g.gowrappers.writeln(' +void ${fn_name}(${thread_arr_typ} a) { + for (int i = 0; i < ${len}; ++i) { + ${thread_typ} t = ((${thread_typ}*)a)[i]; + if (t == 0) continue; + __v_thread_wait(t); + } +}') + } else { + g.gowrappers.writeln(' +${ret_typ} ${fn_name}(${thread_arr_typ} a) { + ${ret_typ} res = __new_array_with_default(${len}, ${len}, sizeof(${eltyp}), 0); + for (int i = 0; i < ${len}; ++i) { + ${thread_typ} t = ((${thread_typ}*)a)[i];') + if g.pref.os == .windows { + g.gowrappers.writeln('\t\tif (t.handle == 0) continue;') + } else { + g.gowrappers.writeln('\t\tif (t == 0) continue;') + } + g.gowrappers.writeln('\t\t((${eltyp}*)res.data)[i] = __v_thread_${eltyp}_wait(t); + } + return res; +}') + } + } + return fn_name +} + fn (mut g Gen) register_chan_pop_option_call(opt_el_type string, styp string) { g.chan_pop_options[opt_el_type] = styp } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index bd0bb9065a..572956d3b8 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1250,6 +1250,9 @@ fn (mut g Gen) method_call(node ast.CallExpr) { if g.gen_array_method_call(node, left_type) { return } + } else if left_sym.kind == .array_fixed && node.name == 'wait' { + g.gen_fixed_array_wait(node) + return } if final_left_sym.kind == .map { diff --git a/vlib/v/tests/fixed_array_of_threads_wait_test.v b/vlib/v/tests/fixed_array_of_threads_wait_test.v new file mode 100644 index 0000000000..d45ebc493d --- /dev/null +++ b/vlib/v/tests/fixed_array_of_threads_wait_test.v @@ -0,0 +1,15 @@ +fn foo() bool { + return true +} + +fn test_fixed_array_of_threads_wait() { + threads := [ + spawn foo(), + spawn foo(), + ]! + + results := threads.wait() + + println(results) + assert results == [true, true] +}