Repository: vyperlang/vyper

Issue:
Got "HashMap must be defined with a key type and a value type" error for HashMap type on Vyper with Python 3.9
### Version Information

* vyper Version (output of `vyper --version`): 0.2.7
* OS: osx
* Python Version (output of `python --version`): Python 3.9.0
* Environment (output of `pip freeze`):

asttokens==2.0.3
attrs==20.2.0
base58==2.0.1
bitarray==1.2.2
black-mamba==0.5.5
blake2b-py==0.1.3
cached-property==1.5.2
certifi==2020.6.20
chardet==3.0.4
cytoolz==0.11.0
eth-abi==2.1.1
eth-account==0.5.4
eth-bloom==1.0.3
eth-hash==0.2.0
eth-keyfile==0.5.1
eth-keys==0.3.3
eth-rlp==0.2.1
eth-typing==2.2.2
eth-utils==1.9.5
hexbytes==0.2.1
idna==2.10
iniconfig==1.1.1
ipfshttpclient==0.6.1
jsonschema==3.2.0
lru-dict==1.1.6
more-itertools==8.5.0
multiaddr==0.0.9
mypy-extensions==0.4.3
netaddr==0.8.0
packaging==20.4
parsimonious==0.8.1
pluggy==0.13.1
protobuf==3.13.0
py==1.9.0
py-ecc==4.1.0
py-evm==0.3.0a20
pycryptodome==3.9.8
pyethash==0.1.27
pyparsing==2.4.7
pyrsistent==0.17.3
pytest==6.0.2
pytest-mock==3.3.1
requests==2.24.0
rlp==2.0.0
semantic-version==2.8.5
six==1.15.0
sortedcontainers==2.2.2
toml==0.10.1
toolz==0.11.1
trie==2.0.0a5
typing-extensions==3.7.4.3
urllib3==1.25.11
varint==1.0.2
vyper==0.2.7
web3==5.12.2
websockets==8.1

### What's your issue about?

Please include information like:

* full output of the error you received

This is the Vyper source code:

```python
x: HashMap[address, uint256]
```

This is the compilation output.

```bash
vyper.exceptions.StructureException: HashMap must be defined with a key type and a value type 
  contract "build/contracts", line 1:3
  ---> 1 x: HashMap[address, uint256]
  ----------^
       2
```

No problem with Python 3.8.5.



Discussion:
```
devo vyper token.vy
Error compiling: token.vy
vyper.exceptions.StructureException: HashMap must be defined with a key type and a value type
  contract "token.vy", line 17:23
       16 # Keep track of refunded bids so we can follow the withdraw pattern
  ---> 17 pendingReturns: public(HashMap[address, uint256])
  -------------------------------^
       18
```
Per #2182, Vyper doesn't yet support Python 3.9

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -63,7 +63,7 @@
     packages=find_packages(exclude=("tests", "docs")),
     python_requires=">=3.6",
     py_modules=["vyper"],
-    install_requires=["asttokens==2.0.3", "pycryptodome>=3.5.1,<4", "semantic-version==2.8.5"],
+    install_requires=["asttokens==2.0.4", "pycryptodome>=3.5.1,<4", "semantic-version==2.8.5"],
     setup_requires=["pytest-runner"],
     tests_require=extras_require["test"],
     extras_require=extras_require,
diff --git a/vyper/ast/annotation.py b/vyper/ast/annotation.py
--- a/vyper/ast/annotation.py
+++ b/vyper/ast/annotation.py
@@ -127,6 +127,24 @@ def visit_Expr(self, node):
 
         return node
 
+    def visit_Subscript(self, node):
+        """
+        Maintain consistency of `Subscript.slice` across python versions.
+
+        Starting from python 3.9, the `Index` node type has been deprecated,
+        and made impossible to instantiate via regular means. Here we do awful
+        hacky black magic to create an `Index` node. We need our own parser.
+        """
+        self.generic_visit(node)
+
+        if not isinstance(node.slice, python_ast.Index):
+            index = python_ast.Constant(value=node.slice, ast_type="Index")
+            index.__class__ = python_ast.Index
+            self.generic_visit(index)
+            node.slice = index
+
+        return node
+
     def visit_Constant(self, node):
         """
         Handle `Constant` when using Python >=3.8


Test patch:
diff --git a/tests/parser/syntax/test_create_with_code_of.py b/tests/parser/syntax/test_create_with_code_of.py
--- a/tests/parser/syntax/test_create_with_code_of.py
+++ b/tests/parser/syntax/test_create_with_code_of.py
@@ -2,7 +2,7 @@
 from pytest import raises
 
 from vyper import compiler
-from vyper.exceptions import SyntaxException
+from vyper.exceptions import ArgumentException, SyntaxException
 
 fail_list = [
     """
@@ -15,7 +15,7 @@ def foo():
 
 @pytest.mark.parametrize("bad_code", fail_list)
 def test_type_mismatch_exception(bad_code):
-    with raises(SyntaxException):
+    with raises((SyntaxException, ArgumentException)):
         compiler.compile_code(bad_code)
 
 
diff --git a/tests/parser/syntax/test_raw_call.py b/tests/parser/syntax/test_raw_call.py
--- a/tests/parser/syntax/test_raw_call.py
+++ b/tests/parser/syntax/test_raw_call.py
@@ -1,7 +1,7 @@
 import pytest
 
 from vyper import compiler
-from vyper.exceptions import InvalidType, SyntaxException
+from vyper.exceptions import ArgumentException, InvalidType, SyntaxException
 
 fail_list = [
     (
@@ -12,7 +12,7 @@ def foo():
         0x1234567890123456789012345678901234567890, b"cow", max_outsize=4, max_outsize=9
     )
     """,
-        SyntaxException,
+        (SyntaxException, ArgumentException),
     ),
     (
         """