Repository: vyperlang/vyper

Issue:
`uint8` cannot be used as array index
### Version Information

* vyper Version (output of `vyper --version`): 0.3.1
* OS: linux
* Python Version (output of `python --version`): 3.10.1

### What's your issue about?

Command:
```
vyper-0.3.1 tests/vyper/simple/array/store_load_constant_array_witness_index.vy
```

Output:
```
Error compiling: tests/vyper/simple/array/store_load_constant_array_witness_index.vy
vyper.exceptions.TypeCheckFailure: get_element_ptr (256 <array>, [mload, 224 <index>]) did not return a value

This is an unhandled internal compiler error. Please create an issue on Github to notify the developers.
```

Example:
```python
SIZE: constant(uint8) = 4

@external
@pure
def main(index: uint8) -> uint8:
    array: uint8[SIZE] = [1, 2, 3, 4]
    return array[index]
```


Discussion:
Oh wild! Yes, that should throw if out of bounds
`uint8` can't be used as an array index, see https://github.com/vyperlang/vyper/blob/2f1584bf9d2fce15e2173b8befc83619c5deae79/vyper/old_codegen/parser_utils.py#L377-L378

I actually have a note to fix this in 0.3.2 but for now the workaround is to use `convert(index, uint256)` as the index.
https://github.com/vyperlang/vyper/blob/4f2e35472e2ba52a1b765dac5676a96f171af888/vyper/old_codegen/parser_utils.py#L409-L411
I was planning to fix this as part of implementing https://github.com/vyperlang/vyper/issues/2559 - which will genericize the code handling int types

Resolving patch:
diff --git a/vyper/codegen/core.py b/vyper/codegen/core.py
--- a/vyper/codegen/core.py
+++ b/vyper/codegen/core.py
@@ -14,7 +14,7 @@
     TupleLike,
     TupleType,
     ceil32,
-    is_base_type,
+    is_integer_type,
     is_signed_num,
 )
 from vyper.evm.opcodes import version_check
@@ -399,8 +399,7 @@ def _get_element_ptr_array(parent, key, pos, array_bounds_check):
 
     assert isinstance(parent.typ, ArrayLike)
 
-    # TODO allow other integer types
-    if not is_base_type(key.typ, ("int128", "int256", "uint256")):
+    if not is_integer_type(key.typ):
         return
 
     subtype = parent.typ.subtype
diff --git a/vyper/codegen/types/types.py b/vyper/codegen/types/types.py
--- a/vyper/codegen/types/types.py
+++ b/vyper/codegen/types/types.py
@@ -72,8 +72,8 @@ class IntegerTypeInfo:
 _int_parser = re.compile("^(u?)int([0-9]+)$")
 
 
-def is_integer_type(typename: str) -> bool:
-    return _int_parser.fullmatch(typename) is not None
+def is_integer_type(t: "NodeType") -> bool:
+    return isinstance(t, BaseType) and _int_parser.fullmatch(t.typ) is not None
 
 
 def parse_integer_typeinfo(typename: str) -> IntegerTypeInfo:
@@ -88,7 +88,7 @@ def parse_integer_typeinfo(typename: str) -> IntegerTypeInfo:
 
 
 def _basetype_to_abi_type(t: "BaseType") -> ABIType:
-    if is_integer_type(t.typ):
+    if is_integer_type(t):
         typinfo = parse_integer_typeinfo(t.typ)
         return ABI_GIntM(typinfo.bits, typinfo.is_signed)
     if t.typ == "address":


Test patch:
diff --git a/tests/parser/types/test_lists.py b/tests/parser/types/test_lists.py
--- a/tests/parser/types/test_lists.py
+++ b/tests/parser/types/test_lists.py
@@ -206,31 +206,33 @@ def test_multi4() -> uint256[2][2][2][2]:
     ]
 
 
-def test_uint256_accessor(get_contract_with_gas_estimation, assert_tx_failed):
-    code = """
+@pytest.mark.parametrize("type_", ["uint8", "uint256"])
+def test_unsigned_accessors(get_contract_with_gas_estimation, assert_tx_failed, type_):
+    code = f"""
 @external
-def bounds_check_uint256(ix: uint256) -> uint256:
+def bounds_check(ix: {type_}) -> uint256:
     xs: uint256[3] = [1,2,3]
     return xs[ix]
     """
     c = get_contract_with_gas_estimation(code)
-    assert c.bounds_check_uint256(0) == 1
-    assert c.bounds_check_uint256(2) == 3
-    assert_tx_failed(lambda: c.bounds_check_uint256(3))
+    assert c.bounds_check(0) == 1
+    assert c.bounds_check(2) == 3
+    assert_tx_failed(lambda: c.bounds_check(3))
 
 
-def test_int128_accessor(get_contract_with_gas_estimation, assert_tx_failed):
-    code = """
+@pytest.mark.parametrize("type_", ["int128", "int256"])
+def test_signed_accessors(get_contract_with_gas_estimation, assert_tx_failed, type_):
+    code = f"""
 @external
-def bounds_check_int128(ix: int128) -> uint256:
+def bounds_check(ix: {type_}) -> uint256:
     xs: uint256[3] = [1,2,3]
     return xs[ix]
     """
     c = get_contract_with_gas_estimation(code)
-    assert c.bounds_check_int128(0) == 1
-    assert c.bounds_check_int128(2) == 3
-    assert_tx_failed(lambda: c.bounds_check_int128(3))
-    assert_tx_failed(lambda: c.bounds_check_int128(-1))
+    assert c.bounds_check(0) == 1
+    assert c.bounds_check(2) == 3
+    assert_tx_failed(lambda: c.bounds_check(3))
+    assert_tx_failed(lambda: c.bounds_check(-1))
 
 
 def test_list_check_heterogeneous_types(get_contract_with_gas_estimation, assert_compile_failed):