diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index ad362486cc..77a1207611 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -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 diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b6f32572c4..781d9a84b3 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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 { diff --git a/vlib/v/checker/tests/array_declare_element_a.out b/vlib/v/checker/tests/array_declare_element_a.out index 5b51a6a338..8f90615b93 100644 --- a/vlib/v/checker/tests/array_declare_element_a.out +++ b/vlib/v/checker/tests/array_declare_element_a.out @@ -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 | } diff --git a/vlib/v/checker/tests/array_declare_element_b.out b/vlib/v/checker/tests/array_declare_element_b.out index e603d3dcf7..1cbe0020b2 100644 --- a/vlib/v/checker/tests/array_declare_element_b.out +++ b/vlib/v/checker/tests/array_declare_element_b.out @@ -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 | } diff --git a/vlib/v/checker/tests/array_declare_element_c.out b/vlib/v/checker/tests/array_declare_element_c.out index 237da0682b..ac3addf688 100644 --- a/vlib/v/checker/tests/array_declare_element_c.out +++ b/vlib/v/checker/tests/array_declare_element_c.out @@ -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 | } diff --git a/vlib/v/checker/tests/index_expr.out b/vlib/v/checker/tests/index_expr.out new file mode 100644 index 0000000000..7f901ef53e --- /dev/null +++ b/vlib/v/checker/tests/index_expr.out @@ -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 | } diff --git a/vlib/v/checker/tests/index_expr.vv b/vlib/v/checker/tests/index_expr.vv new file mode 100644 index 0000000000..7bce476514 --- /dev/null +++ b/vlib/v/checker/tests/index_expr.vv @@ -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] +} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 123c296f19..10b2af49f3 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -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 } }