checker: check that array slicing indexes are valid (#5892)
							parent
							
								
									8653605b0a
								
							
						
					
					
						commit
						e6fc8eb015
					
				| 
						 | 
				
			
			@ -438,7 +438,7 @@ pub struct IndexExpr {
 | 
			
		|||
pub:
 | 
			
		||||
	pos       token.Position
 | 
			
		||||
	left      Expr
 | 
			
		||||
	index     Expr // [0], [start..end] etc
 | 
			
		||||
	index     Expr // [0] or RangeExpr [start..end]
 | 
			
		||||
pub mut:
 | 
			
		||||
	left_type table.Type // array, map, fixed array
 | 
			
		||||
	is_setter bool
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2956,45 +2956,47 @@ pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) table.Type {
 | 
			
		|||
	return typ
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn (mut c Checker) check_index_type(typ_sym &table.TypeSymbol, index_type table.Type,
 | 
			
		||||
	pos token.Position) {
 | 
			
		||||
	index_type_sym := c.table.get_type_symbol(index_type)
 | 
			
		||||
	// println('index expr left=$typ_sym.name $node.pos.line_nr')
 | 
			
		||||
	// if typ_sym.kind == .array && (!(table.type_idx(index_type) in table.number_type_idxs) &&
 | 
			
		||||
	// index_type_sym.kind != .enum_) {
 | 
			
		||||
	if typ_sym.kind in [.array, .array_fixed] && !(index_type.is_number() || index_type_sym.kind ==
 | 
			
		||||
		.enum_) {
 | 
			
		||||
		c.error('non-integer index `$index_type_sym.name` (array type `$typ_sym.name`)',
 | 
			
		||||
			pos)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type {
 | 
			
		||||
	typ := c.expr(node.left)
 | 
			
		||||
	node.left_type = typ
 | 
			
		||||
	mut is_range := false // TODO is_range := node.index is ast.RangeExpr
 | 
			
		||||
	match node.index as index {
 | 
			
		||||
		ast.RangeExpr {
 | 
			
		||||
			is_range = true
 | 
			
		||||
			if index.has_low {
 | 
			
		||||
				c.expr(index.low)
 | 
			
		||||
			}
 | 
			
		||||
			if index.has_high {
 | 
			
		||||
				c.expr(index.high)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else {}
 | 
			
		||||
	}
 | 
			
		||||
	typ_sym := c.table.get_type_symbol(typ)
 | 
			
		||||
	if typ_sym.kind !in [.array, .array_fixed, .string, .map] && !typ.is_ptr() && !(!typ_sym.name[0].is_capital() &&
 | 
			
		||||
		typ_sym.name.ends_with('ptr')) && !typ.has_flag(.variadic) { // byteptr, charptr etc
 | 
			
		||||
		c.error('type `$typ_sym.name` does not support indexing', node.pos)
 | 
			
		||||
	}
 | 
			
		||||
	if !is_range {
 | 
			
		||||
	if node.index !is ast.RangeExpr { // [1]
 | 
			
		||||
		index_type := c.expr(node.index)
 | 
			
		||||
		index_type_sym := c.table.get_type_symbol(index_type)
 | 
			
		||||
		// println('index expr left=$typ_sym.name $node.pos.line_nr')
 | 
			
		||||
		// if typ_sym.kind == .array && (!(table.type_idx(index_type) in table.number_type_idxs) &&
 | 
			
		||||
		// index_type_sym.kind != .enum_) {
 | 
			
		||||
		if typ_sym.kind in [.array, .array_fixed] && !(index_type.is_number() || index_type_sym.kind ==
 | 
			
		||||
			.enum_) {
 | 
			
		||||
			c.error('non-integer index `$index_type_sym.name` (array type `$typ_sym.name`)',
 | 
			
		||||
				node.pos)
 | 
			
		||||
		} else if typ_sym.kind == .map && index_type.idx() != table.string_type_idx {
 | 
			
		||||
		c.check_index_type(typ_sym, index_type, node.pos)
 | 
			
		||||
		if typ_sym.kind == .map && index_type.idx() != table.string_type_idx {
 | 
			
		||||
			c.error('non-string map index (map type `$typ_sym.name`)', node.pos)
 | 
			
		||||
		}
 | 
			
		||||
		value_type := c.table.value_type(typ)
 | 
			
		||||
		if value_type != table.void_type {
 | 
			
		||||
			return value_type
 | 
			
		||||
		}
 | 
			
		||||
	} else if is_range {
 | 
			
		||||
	} else { // [1..2]
 | 
			
		||||
		range := node.index as ast.RangeExpr
 | 
			
		||||
		if range.has_low {
 | 
			
		||||
			index_type := c.expr(range.low)
 | 
			
		||||
			c.check_index_type(typ_sym, index_type, node.pos)
 | 
			
		||||
		}
 | 
			
		||||
		if range.has_high {
 | 
			
		||||
			index_type := c.expr(range.high)
 | 
			
		||||
			c.check_index_type(typ_sym, index_type, node.pos)
 | 
			
		||||
		}
 | 
			
		||||
		// array[1..2] => array
 | 
			
		||||
		// fixed_array[1..2] => array
 | 
			
		||||
		if typ_sym.kind == .array_fixed {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
vlib/v/checker/tests/array_declare_element_a.v:2:9: error: non-name `arr[0]` on left side of `:=` 
 | 
			
		||||
vlib/v/checker/tests/array_declare_element_a.v:2:5: error: non-name `arr[0]` on left side of `:=` 
 | 
			
		||||
    1 | fn main() {
 | 
			
		||||
    2 |     arr[0] := 2
 | 
			
		||||
      |            ~~
 | 
			
		||||
      |        ~~~
 | 
			
		||||
    3 | }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
vlib/v/checker/tests/array_declare_element_b.v:3:9: error: non-name `arr[1]` on left side of `:=` 
 | 
			
		||||
vlib/v/checker/tests/array_declare_element_b.v:3:5: error: non-name `arr[1]` on left side of `:=` 
 | 
			
		||||
    1 | fn main() {
 | 
			
		||||
    2 |     arr := [1, 2]
 | 
			
		||||
    3 |     arr[1] := 1
 | 
			
		||||
      |            ~~
 | 
			
		||||
      |        ~~~
 | 
			
		||||
    4 | }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
vlib/v/checker/tests/array_declare_element_c.v:3:12: error: non-name `arr[1][0]` on left side of `:=` 
 | 
			
		||||
vlib/v/checker/tests/array_declare_element_c.v:3:8: error: non-name `arr[1][0]` on left side of `:=` 
 | 
			
		||||
    1 | fn main() {
 | 
			
		||||
    2 |     arr := [[1, 2], [0, 3]]
 | 
			
		||||
    3 |     arr[1][0] := 1
 | 
			
		||||
      |               ~~
 | 
			
		||||
      |           ~~~
 | 
			
		||||
    4 | }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
vlib/v/checker/tests/index_expr.v:3:7: error: type `int` does not support indexing 
 | 
			
		||||
    1 | fn test_invalid_index() {
 | 
			
		||||
    2 |     v := 4
 | 
			
		||||
    3 |     _ = v[0]
 | 
			
		||||
      |          ~~~
 | 
			
		||||
    4 |     
 | 
			
		||||
    5 |     a := [2]
 | 
			
		||||
vlib/v/checker/tests/index_expr.v:6:7: error: non-integer index `array_int` (array type `array_int`) 
 | 
			
		||||
    4 |     
 | 
			
		||||
    5 |     a := [2]
 | 
			
		||||
    6 |     _ = a[a]
 | 
			
		||||
      |          ~~~
 | 
			
		||||
    7 | }
 | 
			
		||||
    8 |
 | 
			
		||||
vlib/v/checker/tests/index_expr.v:11:7: error: type `int` does not support indexing 
 | 
			
		||||
    9 | fn test_invalid_slice() {
 | 
			
		||||
   10 |     v := 4
 | 
			
		||||
   11 |     _ = v[1..]
 | 
			
		||||
      |          ~~~~~
 | 
			
		||||
   12 |     _ = v[..1]
 | 
			
		||||
   13 |
 | 
			
		||||
vlib/v/checker/tests/index_expr.v:12:7: error: type `int` does not support indexing 
 | 
			
		||||
   10 |     v := 4
 | 
			
		||||
   11 |     _ = v[1..]
 | 
			
		||||
   12 |     _ = v[..1]
 | 
			
		||||
      |          ~~~~~
 | 
			
		||||
   13 |     
 | 
			
		||||
   14 |     a := [2]
 | 
			
		||||
vlib/v/checker/tests/index_expr.v:15:7: error: non-integer index `array_int` (array type `array_int`) 
 | 
			
		||||
   13 |     
 | 
			
		||||
   14 |     a := [2]
 | 
			
		||||
   15 |     _ = a[a..]
 | 
			
		||||
      |          ~~~~~
 | 
			
		||||
   16 |     _ = a[..a]
 | 
			
		||||
   17 | }
 | 
			
		||||
vlib/v/checker/tests/index_expr.v:16:7: error: non-integer index `array_int` (array type `array_int`) 
 | 
			
		||||
   14 |     a := [2]
 | 
			
		||||
   15 |     _ = a[a..]
 | 
			
		||||
   16 |     _ = a[..a]
 | 
			
		||||
      |          ~~~~~
 | 
			
		||||
   17 | }
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
fn test_invalid_index() {
 | 
			
		||||
	v := 4
 | 
			
		||||
	_ = v[0]
 | 
			
		||||
	
 | 
			
		||||
	a := [2]
 | 
			
		||||
	_ = a[a]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_invalid_slice() {
 | 
			
		||||
	v := 4
 | 
			
		||||
	_ = v[1..]
 | 
			
		||||
	_ = v[..1]
 | 
			
		||||
	
 | 
			
		||||
	a := [2]
 | 
			
		||||
	_ = a[a..]
 | 
			
		||||
	_ = a[..a]
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1028,6 +1028,7 @@ pub fn (mut p Parser) name_expr() ast.Expr {
 | 
			
		|||
 | 
			
		||||
fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
 | 
			
		||||
	// left == `a` in `a[0]`
 | 
			
		||||
	start_pos := p.tok.position()
 | 
			
		||||
	p.next() // [
 | 
			
		||||
	mut has_low := true
 | 
			
		||||
	if p.tok.kind == .dotdot {
 | 
			
		||||
| 
						 | 
				
			
			@ -1035,10 +1036,11 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
 | 
			
		|||
		// [..end]
 | 
			
		||||
		p.next()
 | 
			
		||||
		high := p.expr(0)
 | 
			
		||||
		pos := start_pos.extend(p.tok.position())
 | 
			
		||||
		p.check(.rsbr)
 | 
			
		||||
		return ast.IndexExpr{
 | 
			
		||||
			left: left
 | 
			
		||||
			pos: p.tok.position()
 | 
			
		||||
			pos: pos
 | 
			
		||||
			index: ast.RangeExpr{
 | 
			
		||||
				low: ast.Expr{}
 | 
			
		||||
				high: high
 | 
			
		||||
| 
						 | 
				
			
			@ -1046,7 +1048,7 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	expr := p.expr(0) // `[expr]` or  `[expr..]`
 | 
			
		||||
	expr := p.expr(0) // `[expr]` or  `[expr..`
 | 
			
		||||
	mut has_high := false
 | 
			
		||||
	if p.tok.kind == .dotdot {
 | 
			
		||||
		// [start..end] or [start..]
 | 
			
		||||
| 
						 | 
				
			
			@ -1056,10 +1058,11 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
 | 
			
		|||
			has_high = true
 | 
			
		||||
			high = p.expr(0)
 | 
			
		||||
		}
 | 
			
		||||
		pos := start_pos.extend(p.tok.position())
 | 
			
		||||
		p.check(.rsbr)
 | 
			
		||||
		return ast.IndexExpr{
 | 
			
		||||
			left: left
 | 
			
		||||
			pos: p.tok.position()
 | 
			
		||||
			pos: pos
 | 
			
		||||
			index: ast.RangeExpr{
 | 
			
		||||
				low: expr
 | 
			
		||||
				high: high
 | 
			
		||||
| 
						 | 
				
			
			@ -1069,11 +1072,12 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// [expr]
 | 
			
		||||
	pos := start_pos.extend(p.tok.position())
 | 
			
		||||
	p.check(.rsbr)
 | 
			
		||||
	return ast.IndexExpr{
 | 
			
		||||
		left: left
 | 
			
		||||
		index: expr
 | 
			
		||||
		pos: p.tok.position()
 | 
			
		||||
		pos: pos
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue