Skip to content

Commit 1b7486a

Browse files
committed
checker: relax the array int index rule, copy Go's behavior
1 parent f34a22f commit 1b7486a

9 files changed

Lines changed: 235 additions & 39 deletions

File tree

vlib/builtin/array.v

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,31 @@ fn (a array) get(i int) voidptr {
731731
}
732732
}
733733

734+
@[markused]
735+
fn (a array) get_i64(i i64) voidptr {
736+
$if !no_bounds_checking {
737+
if i < 0 || i >= i64(a.len) {
738+
panic_n2('array.get: index out of range (i,a.len):', i, a.len)
739+
}
740+
}
741+
unsafe {
742+
return &u8(a.data) + u64(i) * u64(a.element_size)
743+
}
744+
}
745+
746+
@[markused]
747+
fn (a array) get_u64(i u64) voidptr {
748+
$if !no_bounds_checking {
749+
if i >= u64(a.len) {
750+
panic('array.get: index out of range (i,a.len): ' + i.str() + ', ' +
751+
impl_i64_to_string(a.len))
752+
}
753+
}
754+
unsafe {
755+
return &u8(a.data) + i * u64(a.element_size)
756+
}
757+
}
758+
734759
@[markused]
735760
fn (a array) get_ni(i int) voidptr {
736761
return a.get(v_ni_index(i, a.len))
@@ -746,6 +771,26 @@ fn (a array) get_with_check(i int) voidptr {
746771
}
747772
}
748773

774+
@[markused]
775+
fn (a array) get_with_check_i64(i i64) voidptr {
776+
if i < 0 || i >= i64(a.len) {
777+
return 0
778+
}
779+
unsafe {
780+
return &u8(a.data) + u64(i) * u64(a.element_size)
781+
}
782+
}
783+
784+
@[markused]
785+
fn (a array) get_with_check_u64(i u64) voidptr {
786+
if i >= u64(a.len) {
787+
return 0
788+
}
789+
unsafe {
790+
return &u8(a.data) + i * u64(a.element_size)
791+
}
792+
}
793+
749794
@[markused]
750795
fn (a array) get_with_check_ni(i int) voidptr {
751796
return a.get_with_check(v_ni_index(i, a.len))
@@ -1044,6 +1089,27 @@ fn (mut a array) set(i int, val voidptr) {
10441089
unsafe { vmemcpy(&u8(a.data) + u64(a.element_size) * u64(i), val, a.element_size) }
10451090
}
10461091

1092+
@[markused]
1093+
fn (mut a array) set_i64(i i64, val voidptr) {
1094+
$if !no_bounds_checking {
1095+
if i < 0 || i >= i64(a.len) {
1096+
panic_n2('array.set: index out of range (i,a.len):', i, a.len)
1097+
}
1098+
}
1099+
unsafe { vmemcpy(&u8(a.data) + u64(a.element_size) * u64(i), val, a.element_size) }
1100+
}
1101+
1102+
@[markused]
1103+
fn (mut a array) set_u64(i u64, val voidptr) {
1104+
$if !no_bounds_checking {
1105+
if i >= u64(a.len) {
1106+
panic('array.set: index out of range (i,a.len): ' + i.str() + ', ' +
1107+
impl_i64_to_string(a.len))
1108+
}
1109+
}
1110+
unsafe { vmemcpy(&u8(a.data) + u64(a.element_size) * i, val, a.element_size) }
1111+
}
1112+
10471113
@[markused]
10481114
fn (mut a array) set_ni(i int, val voidptr) {
10491115
a.set(v_ni_index(i, a.len), val)

vlib/builtin/builtin.c.v

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,28 @@ fn v_fixed_index(i int, len int) int {
7979
return i
8080
}
8181

82+
@[inline; markused]
83+
fn v_fixed_index_i64(i i64, len int) int {
84+
$if !no_bounds_checking {
85+
if i < 0 || i >= i64(len) {
86+
panic('fixed array index out of range (index: ' + i.str() + ', len: ' + i64(len).str() +
87+
')')
88+
}
89+
}
90+
return int(i)
91+
}
92+
93+
@[inline; markused]
94+
fn v_fixed_index_u64(i u64, len int) int {
95+
$if !no_bounds_checking {
96+
if i >= u64(len) {
97+
panic('fixed array index out of range (index: ' + i.str() + ', len: ' + i64(len).str() +
98+
')')
99+
}
100+
}
101+
return int(i)
102+
}
103+
82104
@[inline; markused]
83105
fn v_fixed_index_ni(i int, len int) int {
84106
return v_fixed_index(v_ni_index(i, len), len)

vlib/builtin/js/map_test.js.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,7 @@ fn test_i64_keys() {
923923
assert m.len == end
924924
keys := m.keys()
925925
for i in i64(0) .. end {
926-
assert keys[i] == i
926+
assert keys[int(i)] == i
927927
}
928928
for i in i64(0) .. end {
929929
m.delete(i)
@@ -949,7 +949,7 @@ fn test_u64_keys() {
949949
assert u64(m.len) == end
950950
keys := m.keys()
951951
for i in u64(0) .. end {
952-
assert keys[i] == i
952+
assert keys[int(i)] == i
953953
}
954954
for i in u64(0) .. end {
955955
m.delete(i)

vlib/builtin/string.v

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2156,6 +2156,27 @@ fn (s string) at(idx int) u8 {
21562156
return unsafe { s.str[idx] }
21572157
}
21582158

2159+
@[markused]
2160+
fn (s string) at_i64(idx i64) u8 {
2161+
$if !no_bounds_checking {
2162+
if idx < 0 || idx >= i64(s.len) {
2163+
panic_n2('string index out of range(idx,s.len):', idx, s.len)
2164+
}
2165+
}
2166+
return unsafe { s.str[int(idx)] }
2167+
}
2168+
2169+
@[markused]
2170+
fn (s string) at_u64(idx u64) u8 {
2171+
$if !no_bounds_checking {
2172+
if idx >= u64(s.len) {
2173+
panic('string index out of range(idx,s.len): ' + idx.str() + ', ' +
2174+
impl_i64_to_string(s.len))
2175+
}
2176+
}
2177+
return unsafe { s.str[int(idx)] }
2178+
}
2179+
21592180
@[markused]
21602181
fn (s string) at_ni(idx int) u8 {
21612182
return s.at(v_ni_index(idx, s.len))
@@ -2172,6 +2193,26 @@ fn (s string) at_with_check(idx int) ?u8 {
21722193
}
21732194
}
21742195

2196+
@[markused]
2197+
fn (s string) at_with_check_i64(idx i64) ?u8 {
2198+
if idx < 0 || idx >= i64(s.len) {
2199+
return none
2200+
}
2201+
unsafe {
2202+
return s.str[int(idx)]
2203+
}
2204+
}
2205+
2206+
@[markused]
2207+
fn (s string) at_with_check_u64(idx u64) ?u8 {
2208+
if idx >= u64(s.len) {
2209+
return none
2210+
}
2211+
unsafe {
2212+
return s.str[int(idx)]
2213+
}
2214+
}
2215+
21752216
@[markused]
21762217
fn (s string) at_with_check_ni(idx int) ?u8 {
21772218
return s.at_with_check(v_ni_index(idx, s.len))

vlib/v/checker/checker.v

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7707,7 +7707,7 @@ fn (c &Checker) internal_index_type(index_type ast.Type) ast.Type {
77077707
return internal_index_type
77087708
}
77097709

7710-
fn (mut c Checker) check_internal_index_type(index ast.Expr, index_type ast.Type, typ_sym &ast.TypeSymbol) bool {
7710+
fn (mut c Checker) check_internal_index_type(index ast.Expr, index_type ast.Type, typ_sym &ast.TypeSymbol, range_index bool, is_gated bool) bool {
77117711
if c.pref.translated || c.file.is_translated {
77127712
return true
77137713
}
@@ -7720,6 +7720,9 @@ fn (mut c Checker) check_internal_index_type(index ast.Expr, index_type ast.Type
77207720
}
77217721
return true
77227722
}
7723+
if c.pref.backend == .c && !range_index && !is_gated {
7724+
return true
7725+
}
77237726
int_size, _ := c.table.type_size(ast.int_type_idx)
77247727
internal_index_size, _ := c.table.type_size(internal_index_type.idx_type())
77257728
if internal_index_size > int_size {
@@ -7758,7 +7761,7 @@ fn (mut c Checker) check_index(typ_sym &ast.TypeSymbol, index ast.Expr, index_ty
77587761
c.error('cannot use Option or Result as index ${type_str}', index.pos())
77597762
return
77607763
}
7761-
if !c.check_internal_index_type(index, index_type, typ_sym) {
7764+
if !c.check_internal_index_type(index, index_type, typ_sym, range_index, is_gated) {
77627765
return
77637766
}
77647767
if index is ast.IntegerLiteral && !is_gated {
Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,6 @@
1-
vlib/v/checker/tests/index_expr_implicit_int_downcast_err.vv:10:12: error: cannot use `u64` as string index type `int`, use an explicit cast like `int(expr)`
2-
8 | _ = s[int(idx_u64)]
3-
9 | _ = a[idx_u32]
4-
10 | println(s[idx_u64])
5-
| ~~~~~~~
6-
11 | println(a[idx_i64])
7-
12 | println(a[idx_usize..])
8-
vlib/v/checker/tests/index_expr_implicit_int_downcast_err.vv:11:12: error: cannot use `i64` as index type `int`, use an explicit cast like `int(expr)`
9-
9 | _ = a[idx_u32]
10-
10 | println(s[idx_u64])
11-
11 | println(a[idx_i64])
12-
| ~~~~~~~
13-
12 | println(a[idx_usize..])
14-
13 | }
15-
vlib/v/checker/tests/index_expr_implicit_int_downcast_err.vv:12:12: error: cannot use `usize` as index type `int`, use an explicit cast like `int(expr)`
16-
10 | println(s[idx_u64])
17-
11 | println(a[idx_i64])
18-
12 | println(a[idx_usize..])
1+
vlib/v/checker/tests/index_expr_implicit_int_downcast_err.vv:4:12: error: cannot use `usize` as index type `int`, use an explicit cast like `int(expr)`
2+
2 | a := [1, 2, 3]
3+
3 | idx_usize := usize(1)
4+
4 | println(a[idx_usize..])
195
| ~~~~~~~~~
20-
13 | }
6+
5 | }
Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
fn main() {
2-
s := 'abc'
32
a := [1, 2, 3]
4-
idx_u64 := u64(1)
5-
idx_u32 := u32(1)
6-
idx_i64 := i64(1)
73
idx_usize := usize(1)
8-
_ = s[int(idx_u64)]
9-
_ = a[idx_u32]
10-
println(s[idx_u64])
11-
println(a[idx_i64])
124
println(a[idx_usize..])
135
}

0 commit comments

Comments
 (0)