checker: check that array slicing indexes are valid (#5892)
parent
8653605b0a
commit
e6fc8eb015
|
@ -438,7 +438,7 @@ pub struct IndexExpr {
|
||||||
pub:
|
pub:
|
||||||
pos token.Position
|
pos token.Position
|
||||||
left Expr
|
left Expr
|
||||||
index Expr // [0], [start..end] etc
|
index Expr // [0] or RangeExpr [start..end]
|
||||||
pub mut:
|
pub mut:
|
||||||
left_type table.Type // array, map, fixed array
|
left_type table.Type // array, map, fixed array
|
||||||
is_setter bool
|
is_setter bool
|
||||||
|
|
|
@ -2956,29 +2956,8 @@ pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) table.Type {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type {
|
fn (mut c Checker) check_index_type(typ_sym &table.TypeSymbol, index_type table.Type,
|
||||||
typ := c.expr(node.left)
|
pos token.Position) {
|
||||||
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 {
|
|
||||||
index_type := c.expr(node.index)
|
|
||||||
index_type_sym := c.table.get_type_symbol(index_type)
|
index_type_sym := c.table.get_type_symbol(index_type)
|
||||||
// println('index expr left=$typ_sym.name $node.pos.line_nr')
|
// 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) &&
|
// if typ_sym.kind == .array && (!(table.type_idx(index_type) in table.number_type_idxs) &&
|
||||||
|
@ -2986,15 +2965,38 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type {
|
||||||
if typ_sym.kind in [.array, .array_fixed] && !(index_type.is_number() || index_type_sym.kind ==
|
if typ_sym.kind in [.array, .array_fixed] && !(index_type.is_number() || index_type_sym.kind ==
|
||||||
.enum_) {
|
.enum_) {
|
||||||
c.error('non-integer index `$index_type_sym.name` (array type `$typ_sym.name`)',
|
c.error('non-integer index `$index_type_sym.name` (array type `$typ_sym.name`)',
|
||||||
node.pos)
|
pos)
|
||||||
} else if typ_sym.kind == .map && index_type.idx() != table.string_type_idx {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type {
|
||||||
|
typ := c.expr(node.left)
|
||||||
|
node.left_type = typ
|
||||||
|
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 node.index !is ast.RangeExpr { // [1]
|
||||||
|
index_type := c.expr(node.index)
|
||||||
|
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)
|
c.error('non-string map index (map type `$typ_sym.name`)', node.pos)
|
||||||
}
|
}
|
||||||
value_type := c.table.value_type(typ)
|
value_type := c.table.value_type(typ)
|
||||||
if value_type != table.void_type {
|
if value_type != table.void_type {
|
||||||
return value_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
|
// array[1..2] => array
|
||||||
// fixed_array[1..2] => array
|
// fixed_array[1..2] => array
|
||||||
if typ_sym.kind == .array_fixed {
|
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() {
|
1 | fn main() {
|
||||||
2 | arr[0] := 2
|
2 | arr[0] := 2
|
||||||
| ~~
|
| ~~~
|
||||||
3 | }
|
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() {
|
1 | fn main() {
|
||||||
2 | arr := [1, 2]
|
2 | arr := [1, 2]
|
||||||
3 | arr[1] := 1
|
3 | arr[1] := 1
|
||||||
| ~~
|
| ~~~
|
||||||
4 | }
|
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() {
|
1 | fn main() {
|
||||||
2 | arr := [[1, 2], [0, 3]]
|
2 | arr := [[1, 2], [0, 3]]
|
||||||
3 | arr[1][0] := 1
|
3 | arr[1][0] := 1
|
||||||
| ~~
|
| ~~~
|
||||||
4 | }
|
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 {
|
fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
|
||||||
// left == `a` in `a[0]`
|
// left == `a` in `a[0]`
|
||||||
|
start_pos := p.tok.position()
|
||||||
p.next() // [
|
p.next() // [
|
||||||
mut has_low := true
|
mut has_low := true
|
||||||
if p.tok.kind == .dotdot {
|
if p.tok.kind == .dotdot {
|
||||||
|
@ -1035,10 +1036,11 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
|
||||||
// [..end]
|
// [..end]
|
||||||
p.next()
|
p.next()
|
||||||
high := p.expr(0)
|
high := p.expr(0)
|
||||||
|
pos := start_pos.extend(p.tok.position())
|
||||||
p.check(.rsbr)
|
p.check(.rsbr)
|
||||||
return ast.IndexExpr{
|
return ast.IndexExpr{
|
||||||
left: left
|
left: left
|
||||||
pos: p.tok.position()
|
pos: pos
|
||||||
index: ast.RangeExpr{
|
index: ast.RangeExpr{
|
||||||
low: ast.Expr{}
|
low: ast.Expr{}
|
||||||
high: high
|
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
|
mut has_high := false
|
||||||
if p.tok.kind == .dotdot {
|
if p.tok.kind == .dotdot {
|
||||||
// [start..end] or [start..]
|
// [start..end] or [start..]
|
||||||
|
@ -1056,10 +1058,11 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
|
||||||
has_high = true
|
has_high = true
|
||||||
high = p.expr(0)
|
high = p.expr(0)
|
||||||
}
|
}
|
||||||
|
pos := start_pos.extend(p.tok.position())
|
||||||
p.check(.rsbr)
|
p.check(.rsbr)
|
||||||
return ast.IndexExpr{
|
return ast.IndexExpr{
|
||||||
left: left
|
left: left
|
||||||
pos: p.tok.position()
|
pos: pos
|
||||||
index: ast.RangeExpr{
|
index: ast.RangeExpr{
|
||||||
low: expr
|
low: expr
|
||||||
high: high
|
high: high
|
||||||
|
@ -1069,11 +1072,12 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// [expr]
|
// [expr]
|
||||||
|
pos := start_pos.extend(p.tok.position())
|
||||||
p.check(.rsbr)
|
p.check(.rsbr)
|
||||||
return ast.IndexExpr{
|
return ast.IndexExpr{
|
||||||
left: left
|
left: left
|
||||||
index: expr
|
index: expr
|
||||||
pos: p.tok.position()
|
pos: pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue