diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index dffab588f0..78a242559a 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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 { diff --git a/vlib/v/checker/tests/arrow_op_wrong_left_type_err_a.out b/vlib/v/checker/tests/arrow_op_wrong_left_type_err_a.out new file mode 100644 index 0000000000..3853891eac --- /dev/null +++ b/vlib/v/checker/tests/arrow_op_wrong_left_type_err_a.out @@ -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 | } diff --git a/vlib/v/checker/tests/arrow_op_wrong_left_type_err_a.vv b/vlib/v/checker/tests/arrow_op_wrong_left_type_err_a.vv new file mode 100644 index 0000000000..d20520507e --- /dev/null +++ b/vlib/v/checker/tests/arrow_op_wrong_left_type_err_a.vv @@ -0,0 +1,5 @@ +fn main() { + ch := i64(3) + obj := 5 + ch <- obj +} diff --git a/vlib/v/checker/tests/arrow_op_wrong_left_type_err_b.out b/vlib/v/checker/tests/arrow_op_wrong_left_type_err_b.out new file mode 100644 index 0000000000..b047fc8b06 --- /dev/null +++ b/vlib/v/checker/tests/arrow_op_wrong_left_type_err_b.out @@ -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 | } diff --git a/vlib/v/checker/tests/arrow_op_wrong_left_type_err_b.vv b/vlib/v/checker/tests/arrow_op_wrong_left_type_err_b.vv new file mode 100644 index 0000000000..22661ed705 --- /dev/null +++ b/vlib/v/checker/tests/arrow_op_wrong_left_type_err_b.vv @@ -0,0 +1,5 @@ +fn main() { + ch := chan string{} + mut obj := 9 + obj = <-ch +} diff --git a/vlib/v/checker/tests/arrow_op_wrong_right_type_err_a.out b/vlib/v/checker/tests/arrow_op_wrong_right_type_err_a.out new file mode 100644 index 0000000000..5b9ad8b1ad --- /dev/null +++ b/vlib/v/checker/tests/arrow_op_wrong_right_type_err_a.out @@ -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 | } diff --git a/vlib/v/checker/tests/arrow_op_wrong_right_type_err_a.vv b/vlib/v/checker/tests/arrow_op_wrong_right_type_err_a.vv new file mode 100644 index 0000000000..f74184d51f --- /dev/null +++ b/vlib/v/checker/tests/arrow_op_wrong_right_type_err_a.vv @@ -0,0 +1,5 @@ +fn main() { + ch := chan u64{cap: 10} + obj := 'test' + ch <- obj +} diff --git a/vlib/v/checker/tests/arrow_op_wrong_right_type_err_b.out b/vlib/v/checker/tests/arrow_op_wrong_right_type_err_b.out new file mode 100644 index 0000000000..df2c9f771a --- /dev/null +++ b/vlib/v/checker/tests/arrow_op_wrong_right_type_err_b.out @@ -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 | } diff --git a/vlib/v/checker/tests/arrow_op_wrong_right_type_err_b.vv b/vlib/v/checker/tests/arrow_op_wrong_right_type_err_b.vv new file mode 100644 index 0000000000..48de2bf58a --- /dev/null +++ b/vlib/v/checker/tests/arrow_op_wrong_right_type_err_b.vv @@ -0,0 +1,5 @@ +fn main() { + ch := i64(3) + obj := <-ch + println(obj) +} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index b266c957f6..3fa3893e5c 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -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 { diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index 33c580a166..f8191bc283 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -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() } diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index fb5d7212ee..12d7f9df4d 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -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) } diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index 3403b0b34f..3f02010f0e 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -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] }