Skip to content

Commit

Permalink
fix[ux]: fix error message for "staticall" typo (#4438)
Browse files Browse the repository at this point in the history
the "staticall" typo is very common, and was raising a hard-to-read
error message from the python parser like "invalid syntax. Perhaps you
forgot a comma?"

this commit adds logic to `ast/parse.py`, so we can add a hint to the
exception after we have successfully gone through the python parser and
have the ability to add source info and a hint.
  • Loading branch information
charles-cooper authored Jan 9, 2025
1 parent 4507d2a commit 66272e6
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 6 deletions.
30 changes: 28 additions & 2 deletions tests/functional/syntax/exceptions/test_syntax_exception.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest

from vyper.compiler import compile_code
from vyper.exceptions import SyntaxException

fail_list = [
Expand Down Expand Up @@ -107,5 +108,30 @@ def foo():


@pytest.mark.parametrize("bad_code", fail_list)
def test_syntax_exception(assert_compile_failed, get_contract, bad_code):
assert_compile_failed(lambda: get_contract(bad_code), SyntaxException)
def test_syntax_exception(bad_code):
with pytest.raises(SyntaxException):
compile_code(bad_code)


def test_bad_staticcall_keyword():
bad_code = """
from ethereum.ercs import IERC20Detailed
def foo():
staticcall ERC20(msg.sender).transfer(msg.sender, staticall IERC20Detailed(msg.sender).decimals())
""" # noqa
with pytest.raises(SyntaxException) as e:
compile_code(bad_code)

expected_error = """
invalid syntax. Perhaps you forgot a comma? (<unknown>, line 5)
contract "<unknown>:5", line 5:54
4 def foo():
---> 5 staticcall ERC20(msg.sender).transfer(msg.sender, staticall IERC20Detailed(msg.sender).decimals())
-------------------------------------------------------------^
6
(hint: did you mean `staticcall`?)
""" # noqa
assert str(e.value) == expected_error.strip()
11 changes: 10 additions & 1 deletion vyper/ast/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,16 @@ def _parse_to_ast_with_settings(
# SyntaxError offset is 1-based, not 0-based (see:
# https://docs.python.org/3/library/exceptions.html#SyntaxError.offset)
offset -= 1
raise SyntaxException(str(e.msg), vyper_source, e.lineno, offset) from None
new_e = SyntaxException(str(e), vyper_source, e.lineno, offset)

likely_errors = ("staticall", "staticcal")
tmp = str(new_e)
for s in likely_errors:
if s in tmp:
new_e._hint = "did you mean `staticcall`?"
break

raise new_e from None

# Add dummy function node to ensure local variables are treated as `AnnAssign`
# instead of state variables (`VariableDecl`)
Expand Down
5 changes: 2 additions & 3 deletions vyper/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,14 @@ class VyperException(_BaseVyperException):


class SyntaxException(VyperException):

"""Invalid syntax."""

def __init__(self, message, source_code, lineno, col_offset):
def __init__(self, message, source_code, lineno, col_offset, hint=None):
item = types.SimpleNamespace() # TODO: Create an actual object for this
item.lineno = lineno
item.col_offset = col_offset
item.full_source_code = source_code
super().__init__(message, item)
super().__init__(message, item, hint=hint)


class DecimalOverrideException(VyperException):
Expand Down

0 comments on commit 66272e6

Please sign in to comment.