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