sync/select: allow push of literals and calculated expressions (#6429)

pull/6431/head
Uwe Krüger 2020-09-20 03:50:09 +02:00 committed by GitHub
parent c781a5f245
commit 4ae88c69ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 96 additions and 24 deletions

View File

@ -36,32 +36,23 @@ fn test_select() {
go do_send_int(chi)
go do_send_byte(chb)
go do_send_i64(chl)
mut channels := [&sync.Channel(chi), &sync.Channel(recch), &sync.Channel(chl), &sync.Channel(chb)]
directions := [sync.Direction.pop, .push, .pop, .pop]
mut sum := i64(0)
mut rl := i64(0)
mut ri := int(0)
mut rb := byte(0)
mut sl := i64(0)
mut objs := [voidptr(&ri), &sl, &rl, &rb]
for _ in 0 .. 1200 {
idx := sync.channel_select(mut channels, directions, mut objs, -1)
match idx {
0 {
select {
ri := <-chi {
sum += ri
}
1 {
recch <- sl {
sl++
}
2 {
rl = <-chl {
sum += rl
}
3 {
rb := <-chb {
sum += rb
}
else {
println('got $idx (timeout)')
}
}
}
// Use Gauß' formula for the first 2 contributions

View File

@ -5,9 +5,12 @@ struct St {
a int
}
fn f1(ch1 chan int, ch2 chan St, ch3 chan int, sem sync.Semaphore) {
fn getint() int {
return 8
}
fn f1(ch1 chan int, ch2 chan St, ch3 chan int, ch4 chan int, ch5 chan int, sem sync.Semaphore) {
mut a := 5
st := St{}
select {
a = <-ch3 {
a = 0
@ -15,9 +18,18 @@ fn f1(ch1 chan int, ch2 chan St, ch3 chan int, sem sync.Semaphore) {
b := <-ch2 {
a = b.a
}
ch2 <- st {
ch3 <- 5 {
a = 1
}
ch2 <- St{a: 37} {
a = 2
}
ch4 <- (6 + 7 * 9) {
a = 8
}
ch5 <- getint() {
a = 9
}
> 300 * time.millisecond {
a = 3
}
@ -30,7 +42,7 @@ fn f2(ch1 chan St, ch2 chan int, sem sync.Semaphore) {
mut r := 23
for i in 0 .. 2 {
select {
b := <- ch1 {
b := <-ch1 {
r = b.a
}
ch2 <- r {
@ -50,6 +62,8 @@ fn test_select_blocks() {
ch1 := chan int{cap: 1}
ch2 := chan St{}
ch3 := chan int{}
ch4 := chan int{}
ch5 := chan int{}
sem := sync.new_semaphore()
mut r := false
t := select {
@ -69,7 +83,7 @@ fn test_select_blocks() {
ch2 <- St{a: 13}
sem.wait()
stopwatch := time.new_stopwatch({})
go f1(ch1, ch2, ch3, sem)
go f1(ch1, ch2, ch3, ch4, ch5, sem)
sem.wait()
elapsed_ms := f64(stopwatch.elapsed()) / time.millisecond
assert elapsed_ms >= 295.0

View File

@ -1,3 +1,11 @@
/*
* ATTENTION! Do not use this file as an example!
* For that, please look at `channel_select_2_test.v` or `channel_select_3_test.v`
*
* This test case uses the implementation in `sync/channels.v` directly
* in order to test it independently from the support in the core language
*/
import sync
fn do_rec_i64(mut ch sync.Channel) {

View File

@ -3064,6 +3064,48 @@ pub fn (mut c Checker) select_expr(mut node ast.SelectExpr) table.Type {
node.expected_type = c.expected_type
for branch in node.branches {
c.stmt(branch.stmt)
match branch.stmt as stmt {
ast.ExprStmt {
if branch.is_timeout {
if !stmt.typ.is_int() {
tsym := c.table.get_type_symbol(stmt.typ)
c.error('invalid type `$tsym.name` for timeout - expected integer type aka `time.Duration`',
stmt.pos)
}
} else {
if stmt.expr is ast.InfixExpr as expr {
if expr.left !is ast.Ident &&
expr.left !is ast.SelectorExpr && expr.left !is ast.IndexExpr {
c.error('channel in `select` key must be predefined', expr.left.position())
}
} else {
c.error('invalid expression for `select` key', stmt.expr.position())
}
}
}
ast.AssignStmt {
match stmt.right[0] as expr {
ast.PrefixExpr {
if expr.right !is ast.Ident &&
expr.right !is ast.SelectorExpr && expr.right !is ast.IndexExpr {
c.error('channel in `select` key must be predefined', expr.right.position())
}
if expr.or_block.kind != .absent {
err_prefix := if expr.or_block.kind == .block { 'or block' } else { 'error propagation' }
c.error('$err_prefix not allowed in `select` key', expr.or_block.pos)
}
}
else {
c.error('`<-` receive expression expected', stmt.right[0].position())
}
}
}
else {
if !branch.is_else {
c.error('receive or send statement expected as `select` key', branch.stmt.position())
}
}
}
c.stmts(branch.stmts)
}
return table.bool_type

View File

@ -2767,11 +2767,23 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
} else {
match branch.stmt as stmt {
ast.ExprStmt {
// send expression
expr := stmt.expr as ast.InfixExpr
channels << expr.left
objs << expr.right
tmp_objs << ''
elem_types << ''
if expr.right is ast.Ident ||
expr.right is ast.IndexExpr || expr.right is ast.SelectorExpr || expr.right is ast.StructInit {
// addressable objects in the `C` output
objs << expr.right
tmp_objs << ''
elem_types << ''
} else {
// must be evaluated to tmp var before real `select` is performed
objs << ast.Expr{}
tmp_obj := g.new_tmp_var()
tmp_objs << tmp_obj
el_stype := g.typ(g.table.mktyp(expr.right_type))
g.writeln('$el_stype $tmp_obj;')
}
is_push << true
}
ast.AssignStmt {
@ -2858,7 +2870,7 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
g.writeln('-1) {')
} else {
g.writeln('$i) {')
if tmp_objs[i] != '' {
if !is_push[i] && tmp_objs[i] != '' {
g.write('\t${elem_types[i]}')
g.expr(objs[i])
g.writeln(' = ${tmp_objs[i]};')

View File

@ -358,6 +358,7 @@ fn (mut p Parser) select_expr() ast.SelectExpr {
}
} else {
p.inside_match = true
p.inside_select = true
exprs, comments := p.expr_list()
if exprs.len != 1 {
p.error('only one expression allowed as `select` key')
@ -373,6 +374,7 @@ fn (mut p Parser) select_expr() ast.SelectExpr {
}
}
p.inside_match = false
p.inside_select = false
match stmt {
ast.ExprStmt {
if !stmt.is_expr {

View File

@ -47,6 +47,7 @@ mut:
is_amp bool // for generating the right code for `&Foo{}`
returns bool
inside_match bool // to separate `match A { }` from `Struct{}`
inside_select bool // to allow `ch <- Struct{} {` inside `select`
inside_match_case bool // to separate `match_expr { }` from `Struct{}`
inside_match_body bool // to fix eval not used TODO
inside_unsafe bool
@ -920,6 +921,7 @@ pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident {
}
pub fn (mut p Parser) name_expr() ast.Expr {
prev_tok_kind := p.prev_tok.kind
mut node := ast.Expr{}
if p.expecting_type {
p.expecting_type = false
@ -1073,7 +1075,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
}
} else if (p.peek_tok.kind == .lcbr ||
(p.peek_tok.kind == .lt && lit0_is_capital)) &&
!p.inside_match && !p.inside_match_case && !p.inside_if && !p.inside_for { // && (p.tok.lit[0].is_capital() || p.builtin_mod) {
(!p.inside_match || (p.inside_select && prev_tok_kind == .arrow && lit0_is_capital)) && !p.inside_match_case &&
!p.inside_if && !p.inside_for { // && (p.tok.lit[0].is_capital() || p.builtin_mod) {
return p.struct_init(false) // short_syntax: false
} else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) {
// `Color.green`