checker: check argument for `chan.try_push/pop()` (#9798)

pull/9814/head
Uwe Krüger 2021-04-19 10:41:21 +02:00 committed by GitHub
parent a45da620e6
commit 8ab0d42b5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 78 additions and 12 deletions

View File

@ -2904,7 +2904,7 @@ println(l)
println(c)
mut b := Abc{}
ch2 := chan Abc{}
res2 := ch2.try_pop(b) // try to perform `b = <-ch2`
res2 := ch2.try_pop(mut b) // try to perform `b = <-ch2`
```
The `try_push/pop()` methods will return immediately with one of the results

View File

@ -18,7 +18,7 @@ fn do_rec(ch chan int, resch chan i64, n int) {
mut sum := i64(0)
for _ in 0 .. n {
mut r := 0
for ch.try_pop(r) != .success {
for ch.try_pop(mut r) != .success {
}
sum += r
}

View File

@ -7,7 +7,7 @@ fn test_channel_try_buffered() {
}
}
mut obj := int(0)
for ch.try_pop(obj) == .success {
for ch.try_pop(mut obj) == .success {
println(obj)
}
assert obj == 6

View File

@ -8,6 +8,6 @@ fn test_channel_try_unbuffered() {
panic('push on non-ready channel not detected')
}
mut obj := -17
for ch.try_pop(obj) == .success {}
for ch.try_pop(mut obj) == .success {}
assert obj == -17
}

View File

@ -1612,22 +1612,44 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
} else {
call_expr.return_type = method.return_type
}
mut exp_arg_typ := ast.Type(0) // type of 1st arg for special builtin methods
mut param_is_mut := false
mut no_type_promotion := false
if left_type_sym.kind == .chan {
elem_typ := (left_type_sym.info as ast.Chan).elem_type
if method_name == 'try_push' {
exp_arg_typ = elem_typ.to_ptr()
} else if method_name == 'try_pop' {
exp_arg_typ = elem_typ
param_is_mut = true
no_type_promotion = true
}
}
// if method_name == 'clone' {
// println('CLONE nr args=$method.args.len')
// }
// call_expr.args << method.args[0].typ
// call_expr.exp_arg_types << method.args[0].typ
for i, arg in call_expr.args {
exp_arg_typ := if method.is_variadic && i >= method.params.len - 1 {
method.params[method.params.len - 1].typ
} else {
method.params[i + 1].typ
if i > 0 || exp_arg_typ == ast.Type(0) {
exp_arg_typ = if method.is_variadic && i >= method.params.len - 1 {
method.params[method.params.len - 1].typ
} else {
method.params[i + 1].typ
}
param_is_mut = false
no_type_promotion = false
}
exp_arg_sym := c.table.get_type_symbol(exp_arg_typ)
c.expected_type = exp_arg_typ
got_arg_typ := c.check_expr_opt_call(arg.expr, c.expr(arg.expr))
call_expr.args[i].typ = got_arg_typ
if no_type_promotion {
if got_arg_typ != exp_arg_typ {
c.error('cannot use `${c.table.get_type_symbol(got_arg_typ).name}` as argument for `$method.name` (`$exp_arg_sym.name` expected)',
arg.pos)
}
}
if method.is_variadic && got_arg_typ.has_flag(.variadic) && call_expr.args.len - 1 > i {
c.error('when forwarding a variadic variable, it must be the final argument',
arg.pos)
@ -1656,6 +1678,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
} else {
method.params[i + 1]
}
param_is_mut = param_is_mut || param.is_mut
param_share := param.typ.share()
if param_share == .shared_t && (c.locked_names.len > 0 || c.rlocked_names.len > 0) {
c.error('method with `shared` arguments cannot be called inside `lock`/`rlock` block',
@ -1663,12 +1686,12 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
}
if arg.is_mut {
to_lock, pos := c.fail_if_immutable(arg.expr)
if !param.is_mut {
if !param_is_mut {
tok := arg.share.str()
c.error('`$call_expr.name` parameter `$param.name` is not `$tok`, `$tok` is not needed`',
arg.expr.position())
} else {
if param.typ.share() != arg.share {
if param_share != arg.share {
c.error('wrong shared type', arg.expr.position())
}
if to_lock != '' && param_share != .shared_t {
@ -1677,7 +1700,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
}
}
} else {
if param.is_mut {
if param_is_mut {
tok := arg.share.str()
c.error('`$call_expr.name` parameter `$param.name` is `$tok`, you need to provide `$tok` e.g. `$tok arg${
i + 1}`', arg.expr.position())

View File

@ -0,0 +1,28 @@
vlib/v/checker/tests/chan_args.vv:4:19: error: cannot use `int` as `&f64` in argument 1 to `chan f64.try_push`
2 | ch := chan f64{cap: 5}
3 | a := 2
4 | _ := ch.try_push(a)
| ^
5 | _ := ch.try_push(2.5)
6 | b := 2.5
vlib/v/checker/tests/chan_args.vv:5:19: error: cannot use `float literal` as `&f64` in argument 1 to `chan f64.try_push`
3 | a := 2
4 | _ := ch.try_push(a)
5 | _ := ch.try_push(2.5)
| ~~~
6 | b := 2.5
7 | _ := ch.try_pop(b)
vlib/v/checker/tests/chan_args.vv:7:18: error: `try_pop` parameter `obj` is `mut`, you need to provide `mut` e.g. `mut arg1`
5 | _ := ch.try_push(2.5)
6 | b := 2.5
7 | _ := ch.try_pop(b)
| ^
8 | // this should work:
9 | _ := ch.try_push(b)
vlib/v/checker/tests/chan_args.vv:11:22: error: cannot use `int` as argument for `try_pop` (`f64` expected)
9 | _ := ch.try_push(b)
10 | mut c := 7
11 | _ := ch.try_pop(mut c)
| ^
12 | mut x := 12.5
13 | // this should work:

View File

@ -0,0 +1,15 @@
fn main() {
ch := chan f64{cap: 5}
a := 2
_ := ch.try_push(a)
_ := ch.try_push(2.5)
b := 2.5
_ := ch.try_pop(b)
// this should work:
_ := ch.try_push(b)
mut c := 7
_ := ch.try_pop(mut c)
mut x := 12.5
// this should work:
_ := ch.try_pop(mut x)
}