all: support `thread` handles and `wait()` for functions returning optionals (#8990)
parent
aed348fb80
commit
f67bff1696
|
@ -49,6 +49,6 @@ fn start_client() ?&websocket.Client {
|
|||
|
||||
ws.connect() or { println(term.red('error on connect: $err')) }
|
||||
|
||||
go ws.listen() or { println(term.red('error on listen $err')) }
|
||||
go ws.listen() // or { println(term.red('error on listen $err')) }
|
||||
return ws
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ fn start_client() ? {
|
|||
// // println('type: $msg.opcode payload:\n$msg.payload ref: $r')
|
||||
// }, &r)
|
||||
ws.connect() or { println('error on connect: $err') }
|
||||
go write_echo(mut ws) or { println('error on write_echo $err') }
|
||||
go write_echo(mut ws) // or { println('error on write_echo $err') }
|
||||
ws.listen() or { println('error on listen $err') }
|
||||
unsafe {
|
||||
ws.free()
|
||||
|
|
|
@ -1333,9 +1333,13 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
|||
elem_sym := c.table.get_type_symbol(elem_typ)
|
||||
if elem_sym.kind == .thread {
|
||||
if call_expr.args.len != 0 {
|
||||
c.error('wait() does not have any arguments', call_expr.args[0].pos)
|
||||
c.error('`.wait()` does not have any arguments', call_expr.args[0].pos)
|
||||
}
|
||||
thread_ret_type := elem_sym.thread_info().return_type
|
||||
if thread_ret_type.has_flag(.optional) {
|
||||
c.error('`.wait()` cannot be called for an array when thread functions return optionals. Iterate over the arrays elements instead and handle each returned optional with `or`.',
|
||||
call_expr.pos)
|
||||
}
|
||||
call_expr.return_type = c.table.find_or_register_array(thread_ret_type)
|
||||
} else {
|
||||
c.error('`$left_type_sym.name` has no method `wait()` (only thread handles and arrays of them have)',
|
||||
|
@ -1428,6 +1432,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
|||
if call_expr.args.len > 0 {
|
||||
c.error('wait() does not have any arguments', call_expr.args[0].pos)
|
||||
}
|
||||
call_expr.return_type = info.return_type
|
||||
return info.return_type
|
||||
}
|
||||
mut method := table.Fn{}
|
||||
|
@ -3155,6 +3160,10 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
}
|
||||
ast.GoStmt {
|
||||
c.go_stmt(mut node)
|
||||
if node.call_expr.or_block.kind != .absent {
|
||||
c.error('optional handling cannot be done in `go` call. Do it when calling `.wait()`',
|
||||
node.call_expr.or_block.pos)
|
||||
}
|
||||
}
|
||||
ast.GotoLabel {}
|
||||
ast.GotoStmt {
|
||||
|
@ -3634,7 +3643,11 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
return c.call_expr(mut node)
|
||||
}
|
||||
ast.GoExpr {
|
||||
ret_type := c.call_expr(mut node.go_stmt.call_expr)
|
||||
mut ret_type := c.call_expr(mut node.go_stmt.call_expr)
|
||||
if node.go_stmt.call_expr.or_block.kind != .absent {
|
||||
c.error('optional handling cannot be done in `go` call. Do it when calling `.wait()`',
|
||||
node.go_stmt.call_expr.or_block.pos)
|
||||
}
|
||||
return c.table.find_or_register_thread(ret_type)
|
||||
}
|
||||
ast.ChanInit {
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
vlib/v/checker/tests/go_wait_or.vv:11:17: error: unexpected `?`, the function `wait` does not return an optional
|
||||
9 | go d(1)
|
||||
10 | ]
|
||||
11 | r := tg.wait() ?
|
||||
| ^
|
||||
12 | println(r)
|
||||
13 | s := tg[0].wait() or { panic('problem') }
|
||||
vlib/v/checker/tests/go_wait_or.vv:13:20: error: unexpected `or` block, the function `wait` does not return an optional
|
||||
11 | r := tg.wait() ?
|
||||
12 | println(r)
|
||||
13 | s := tg[0].wait() or { panic('problem') }
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
14 | println(s)
|
||||
15 | tg2 := [
|
||||
vlib/v/checker/tests/go_wait_or.vv:19:13: error: unexpected `or` block, the function `wait` does not return an optional
|
||||
17 | go e(1)
|
||||
18 | ]
|
||||
19 | tg2.wait() or { panic('problem') }
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
20 | tg2[0].wait() ?
|
||||
21 | tg3 := [
|
||||
vlib/v/checker/tests/go_wait_or.vv:20:16: error: unexpected `?`, the function `wait` does not return an optional
|
||||
18 | ]
|
||||
19 | tg2.wait() or { panic('problem') }
|
||||
20 | tg2[0].wait() ?
|
||||
| ^
|
||||
21 | tg3 := [
|
||||
22 | go f(0)
|
||||
vlib/v/checker/tests/go_wait_or.vv:25:6: error: `.wait()` cannot be called for an array when thread functions return optionals. Iterate over the arrays elements instead and handle each returned optional with `or`.
|
||||
23 | go f(1)
|
||||
24 | ]
|
||||
25 | tg3.wait() or { panic('problem') }
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
26 | for t in tg3 {
|
||||
27 | a := t.wait()
|
||||
vlib/v/checker/tests/go_wait_or.vv:27:10: error: wait() returns an option, so it should have either an `or {}` block, or `?` at the end
|
||||
25 | tg3.wait() or { panic('problem') }
|
||||
26 | for t in tg3 {
|
||||
27 | a := t.wait()
|
||||
| ~~~~~~
|
||||
28 | println(a)
|
||||
29 | }
|
||||
vlib/v/checker/tests/go_wait_or.vv:31:15: error: wait() returns an option, so it should have either an `or {}` block, or `?` at the end
|
||||
29 | }
|
||||
30 | for i, _ in tg3 {
|
||||
31 | a := tg3[i].wait()
|
||||
| ~~~~~~
|
||||
32 | println(a)
|
||||
33 | }
|
||||
vlib/v/checker/tests/go_wait_or.vv:38:6: error: `.wait()` cannot be called for an array when thread functions return optionals. Iterate over the arrays elements instead and handle each returned optional with `or`.
|
||||
36 | go g(1)
|
||||
37 | ]
|
||||
38 | tg4.wait()
|
||||
| ~~~~~~
|
||||
39 | tg4[0].wait()
|
||||
40 | go g(3) or { panic('problem') }
|
||||
vlib/v/checker/tests/go_wait_or.vv:39:9: error: wait() returns an option, so it should have either an `or {}` block, or `?` at the end
|
||||
37 | ]
|
||||
38 | tg4.wait()
|
||||
39 | tg4[0].wait()
|
||||
| ~~~~~~
|
||||
40 | go g(3) or { panic('problem') }
|
||||
41 | }
|
||||
vlib/v/checker/tests/go_wait_or.vv:40:10: error: optional handling cannot be done in `go` call. Do it when calling `.wait()`
|
||||
38 | tg4.wait()
|
||||
39 | tg4[0].wait()
|
||||
40 | go g(3) or { panic('problem') }
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
41 | }
|
|
@ -0,0 +1,41 @@
|
|||
fn d(n int) f64 { return f64(n) }
|
||||
fn e(n int) { }
|
||||
fn f(n int) ?f64 { return f64(n) }
|
||||
fn g(n int) ? { }
|
||||
|
||||
fn main() {
|
||||
tg := [
|
||||
go d(0)
|
||||
go d(1)
|
||||
]
|
||||
r := tg.wait() ?
|
||||
println(r)
|
||||
s := tg[0].wait() or { panic('problem') }
|
||||
println(s)
|
||||
tg2 := [
|
||||
go e(0)
|
||||
go e(1)
|
||||
]
|
||||
tg2.wait() or { panic('problem') }
|
||||
tg2[0].wait() ?
|
||||
tg3 := [
|
||||
go f(0)
|
||||
go f(1)
|
||||
]
|
||||
tg3.wait() or { panic('problem') }
|
||||
for t in tg3 {
|
||||
a := t.wait()
|
||||
println(a)
|
||||
}
|
||||
for i, _ in tg3 {
|
||||
a := tg3[i].wait()
|
||||
println(a)
|
||||
}
|
||||
tg4 := [
|
||||
go g(0)
|
||||
go g(1)
|
||||
]
|
||||
tg4.wait()
|
||||
tg4[0].wait()
|
||||
go g(3) or { panic('problem') }
|
||||
}
|
|
@ -5942,10 +5942,12 @@ fn (mut g Gen) go_stmt(node ast.GoStmt, joinable bool) string {
|
|||
if g.pref.os == .windows && node.call_expr.return_type != table.void_type {
|
||||
g.writeln('$arg_tmp_var->ret_ptr = malloc(sizeof($s_ret_typ));')
|
||||
}
|
||||
is_opt := node.call_expr.return_type.has_flag(.optional)
|
||||
gohandle_name := if node.call_expr.return_type == table.void_type {
|
||||
'__v_thread'
|
||||
if is_opt { '__v_thread_Option_void' } else { '__v_thread' }
|
||||
} else {
|
||||
'__v_thread_' + g.table.get_type_symbol(g.unwrap_generic(node.call_expr.return_type)).cname
|
||||
opt := if is_opt { 'Option_' } else { '' }
|
||||
'__v_thread_$opt${g.table.get_type_symbol(g.unwrap_generic(node.call_expr.return_type)).cname}'
|
||||
}
|
||||
if g.pref.os == .windows {
|
||||
simple_handle := if joinable && node.call_expr.return_type != table.void_type {
|
||||
|
|
|
@ -120,14 +120,27 @@ pub fn (mut p Parser) parse_chan_type() table.Type {
|
|||
}
|
||||
|
||||
pub fn (mut p Parser) parse_thread_type() table.Type {
|
||||
is_opt := p.peek_tok.kind == .question
|
||||
if is_opt {
|
||||
p.next()
|
||||
}
|
||||
if p.peek_tok.kind != .name && p.peek_tok.kind != .key_mut && p.peek_tok.kind != .amp
|
||||
&& p.peek_tok.kind != .lsbr {
|
||||
p.next()
|
||||
return table.thread_type
|
||||
if is_opt {
|
||||
mut ret_type := table.void_type
|
||||
ret_type = ret_type.set_flag(.optional)
|
||||
idx := p.table.find_or_register_thread(ret_type)
|
||||
return table.new_type(idx)
|
||||
} else {
|
||||
return table.thread_type
|
||||
}
|
||||
}
|
||||
p.next()
|
||||
elem_type := p.parse_type()
|
||||
idx := p.table.find_or_register_thread(elem_type)
|
||||
if !is_opt {
|
||||
p.next()
|
||||
}
|
||||
ret_type := p.parse_type()
|
||||
idx := p.table.find_or_register_thread(ret_type)
|
||||
return table.new_type(idx)
|
||||
}
|
||||
|
||||
|
|
|
@ -487,22 +487,32 @@ pub fn (t &Table) chan_cname(elem_type Type, is_mut bool) string {
|
|||
|
||||
[inline]
|
||||
pub fn (t &Table) thread_name(return_type Type) string {
|
||||
if return_type == void_type {
|
||||
return 'thread'
|
||||
if return_type.idx() == void_type_idx {
|
||||
if return_type.has_flag(.optional) {
|
||||
return 'thread ?'
|
||||
} else {
|
||||
return 'thread'
|
||||
}
|
||||
}
|
||||
return_type_sym := t.get_type_symbol(return_type)
|
||||
ptr := if return_type.is_ptr() { '&' } else { '' }
|
||||
return 'thread $ptr$return_type_sym.name'
|
||||
opt := if return_type.has_flag(.optional) { '?' } else { '' }
|
||||
return 'thread $opt$ptr$return_type_sym.name'
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &Table) thread_cname(return_type Type) string {
|
||||
if return_type == void_type {
|
||||
return '__v_thread'
|
||||
if return_type.has_flag(.optional) {
|
||||
return '__v_thread_Option_void'
|
||||
} else {
|
||||
return '__v_thread'
|
||||
}
|
||||
}
|
||||
return_type_sym := t.get_type_symbol(return_type)
|
||||
suffix := if return_type.is_ptr() { '_ptr' } else { '' }
|
||||
return '__v_thread_$return_type_sym.cname$suffix'
|
||||
prefix := if return_type.has_flag(.optional) { 'Option_' } else { '' }
|
||||
return '__v_thread_$prefix$return_type_sym.cname$suffix'
|
||||
}
|
||||
|
||||
// map_source_name generates the original name for the v source.
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
fn f(n int) ?f64 {
|
||||
if n < 0 {
|
||||
return error('negative number')
|
||||
}
|
||||
return n + f64(n) / 2
|
||||
}
|
||||
|
||||
fn g(n int) ? {
|
||||
if n % 2 == 0 {
|
||||
return error('even number')
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fn test_opt_val_wait() {
|
||||
h1 := go f(-1)
|
||||
h2 := go f(3)
|
||||
r1 := h1.wait() or { 17.0 }
|
||||
r2 := h2.wait() or { 23.0 }
|
||||
assert r1 == 17.0
|
||||
assert r2 == 4.5
|
||||
}
|
||||
|
||||
fn test_opt_void_wait() {
|
||||
h1 := go g(2)
|
||||
h2 := go g(3)
|
||||
mut x := 0
|
||||
mut y := 0
|
||||
h1.wait() or { x = 1 }
|
||||
h2.wait() or { y = 1 }
|
||||
assert x == 1
|
||||
assert y == 0
|
||||
}
|
||||
|
||||
fn propagate(n int, m int) ?f64 {
|
||||
h1 := go f(n)
|
||||
h2 := go g(m)
|
||||
r := h1.wait() ?
|
||||
h2.wait() ?
|
||||
return r
|
||||
}
|
||||
|
||||
fn test_propagate() {
|
||||
x := propagate(5, 3) or { 27.0 }
|
||||
y := propagate(-3, 3) or { 29.0 }
|
||||
z := propagate(5, 2) or { 31.0 }
|
||||
assert x == 7.5
|
||||
assert y == 29.0
|
||||
assert z == 31.0
|
||||
}
|
||||
|
||||
fn test_array_void_interate() {
|
||||
mut r := []thread ?{}
|
||||
for i in 0 .. 3 {
|
||||
r << go g(i)
|
||||
}
|
||||
mut res := []int{len: 3, init: 17}
|
||||
for i, t in r {
|
||||
t.wait() or { res[i] = i }
|
||||
}
|
||||
assert res[0] == 0
|
||||
assert res[1] == 17
|
||||
assert res[2] == 2
|
||||
}
|
||||
|
||||
fn test_array_val_interate() {
|
||||
mut r := []thread ?f64{}
|
||||
for i in -1 .. 2 {
|
||||
r << go f(i)
|
||||
}
|
||||
mut res := []f64{len: 3}
|
||||
for i, t in r {
|
||||
res[i] = t.wait() or { 17.0 }
|
||||
}
|
||||
assert res[0] == 17.0
|
||||
assert res[1] == 0.0
|
||||
assert res[2] == 1.5
|
||||
}
|
Loading…
Reference in New Issue