all: handle `<-` arrow token for channel operations (#6152)
parent
c01fd4ac58
commit
9a5f040f72
|
@ -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 {
|
||||
|
|
|
@ -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 | }
|
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
ch := i64(3)
|
||||
obj := 5
|
||||
ch <- obj
|
||||
}
|
|
@ -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 | }
|
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
ch := chan string{}
|
||||
mut obj := 9
|
||||
obj = <-ch
|
||||
}
|
|
@ -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 | }
|
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
ch := chan u64{cap: 10}
|
||||
obj := 'test'
|
||||
ch <- obj
|
||||
}
|
|
@ -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 | }
|
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
ch := i64(3)
|
||||
obj := <-ch
|
||||
println(obj)
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue