all: handle `<-` arrow token for channel operations (#6152)

pull/6154/head
Uwe Krüger 2020-08-17 20:12:00 +02:00 committed by GitHub
parent c01fd4ac58
commit 9a5f040f72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 74 additions and 9 deletions

View File

@ -639,6 +639,17 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
}
return table.bool_type
}
.arrow { // `chan <- elem`
if left.kind == .chan {
elem_type := left.chan_info().elem_type
if !c.check_types(right_type, elem_type) {
c.error('cannot push `$right.name` on `$left.name`', right_pos)
}
} else {
c.error('cannot push on non-channel `$left.name`', left_pos)
}
return table.void_type
}
else {
// use `()` to make the boolean expression clear error
// for example: `(a && b) || c` instead of `a && b || c`
@ -2441,6 +2452,14 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
if node.op == .not && right_type != table.bool_type_idx && !c.pref.translated {
c.error('! operator can only be used with bool types', node.pos)
}
if node.op == .arrow {
right := c.table.get_type_symbol(right_type)
if right.kind == .chan {
return right.chan_info().elem_type
} else {
c.error('<- operator can only be used with `chan` types', node.pos)
}
}
return right_type
}
ast.None {

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/arrow_op_wrong_left_type_err_a.v:4:2: error: cannot push on non-channel `i64`
2 | ch := i64(3)
3 | obj := 5
4 | ch <- obj
| ~~
5 | }

View File

@ -0,0 +1,5 @@
fn main() {
ch := i64(3)
obj := 5
ch <- obj
}

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/arrow_op_wrong_left_type_err_b.v:4:8: error: cannot assign `string` to `obj` of type `int`
2 | ch := chan string{}
3 | mut obj := 9
4 | obj = <-ch
| ~~
5 | }

View File

@ -0,0 +1,5 @@
fn main() {
ch := chan string{}
mut obj := 9
obj = <-ch
}

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/arrow_op_wrong_right_type_err_a.v:4:8: error: cannot push `string` on `chan_u64`
2 | ch := chan u64{cap: 10}
3 | obj := 'test'
4 | ch <- obj
| ~~~
5 | }

View File

@ -0,0 +1,5 @@
fn main() {
ch := chan u64{cap: 10}
obj := 'test'
ch <- obj
}

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/arrow_op_wrong_right_type_err_b.v:3:9: error: <- operator can only be used with `chan` types
1 | fn main() {
2 | ch := i64(3)
3 | obj := <-ch
| ~~
4 | println(obj)
5 | }

View File

@ -0,0 +1,5 @@
fn main() {
ch := i64(3)
obj := <-ch
println(obj)
}

View File

@ -858,7 +858,7 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
return p.partial_assign_stmt(left, left_comments)
} else if is_top_level && tok.kind !in [.key_if, .key_match, .key_lock, .key_rlock] &&
left0 !is ast.CallExpr && left0 !is ast.PostfixExpr && !(left0 is ast.InfixExpr &&
(left0 as ast.InfixExpr).op == .left_shift) && left0 !is ast.ComptimeCall {
(left0 as ast.InfixExpr).op in [.left_shift, .arrow]) && left0 !is ast.ComptimeCall {
p.error_with_pos('expression evaluated but not used', left0.position())
}
if left.len == 1 {

View File

@ -60,7 +60,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
}
p.next()
}
.minus, .amp, .mul, .not, .bit_not {
.minus, .amp, .mul, .not, .bit_not, .arrow {
// -1, -a, !x, &x, ~x
node = p.prefix_expr()
}

View File

@ -1037,6 +1037,9 @@ fn (mut s Scanner) text_scan() token.Token {
}
s.pos++
return s.new_token(.left_shift, '', 2)
} else if nextc == `-` {
s.pos++
return s.new_token(.arrow, '', 2)
} else {
return s.new_token(.lt, '', 1)
}
@ -1045,9 +1048,6 @@ fn (mut s Scanner) text_scan() token.Token {
if nextc == `=` {
s.pos++
return s.new_token(.eq, '', 2)
} else if nextc == `>` {
s.pos++
return s.new_token(.arrow, '', 2)
} else {
return s.new_token(.assign, '', 1)
}

View File

@ -39,7 +39,7 @@ pub enum Kind {
comma
semicolon
colon
arrow // =>
arrow // <-
amp
hash
dollar
@ -181,7 +181,7 @@ fn build_token_str() []string {
// s[Kind.at] = '@'
s[Kind.semicolon] = ';'
s[Kind.colon] = ':'
s[Kind.arrow] = '=>'
s[Kind.arrow] = '<-'
s[Kind.assign] = '='
s[Kind.decl_assign] = ':='
s[Kind.plus_assign] = '+='
@ -339,6 +339,7 @@ pub fn build_precedences() []Precedence {
p[Kind.left_shift] = .product
p[Kind.right_shift] = .product
p[Kind.amp] = .product
p[Kind.arrow] = .product
// `+` | `-` | `|` | `^`
p[Kind.plus] = .sum
p[Kind.minus] = .sum
@ -394,7 +395,7 @@ pub fn (tok Token) is_scalar() bool {
pub fn (tok Token) is_unary() bool {
return tok.kind in [
// `+` | `-` | `!` | `~` | `*` | `&`
.plus, .minus, .not, .bit_not, .mul, .amp]
.plus, .minus, .not, .bit_not, .mul, .amp, .arrow]
}
pub fn (tok Kind) is_relational() bool {
@ -412,5 +413,5 @@ pub fn (kind Kind) is_infix() bool {
//
.key_as, .ge, .le, .logical_or, .xor, .not_in, .key_is, .not_is,
//
.and, .dot, .pipe, .amp, .left_shift, .right_shift]
.and, .dot, .pipe, .amp, .left_shift, .right_shift, .arrow]
}