Skip to content

Commit

Permalink
feat: improve warnings, refactor vyper_warn() (#3800)
Browse files Browse the repository at this point in the history
* add source information to vyper_warn() to give more helpful warnings
* add source information to the struct instantiation warning
  • Loading branch information
charles-cooper authored Feb 22, 2024
1 parent 21a511a commit 26eaa8a
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 28 deletions.
2 changes: 1 addition & 1 deletion tests/functional/syntax/test_structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,4 +594,4 @@ def foo():
expected += "Use kwargs instead e.g. Foo(a=1, b=2)"

assert len(w) == 1
assert str(w[0].message) == expected
assert str(w[0].message).startswith(expected)
7 changes: 5 additions & 2 deletions vyper/ast/parse.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import ast as python_ast
import tokenize
import warnings
from decimal import Decimal
from typing import Any, Dict, List, Optional, Union, cast

Expand All @@ -11,6 +10,7 @@
from vyper.compiler.settings import Settings
from vyper.exceptions import CompilerPanic, ParserException, SyntaxException
from vyper.typing import ModificationOffsets
from vyper.utils import vyper_warn


def parse_to_ast(*args: Any, **kwargs: Any) -> vy_ast.Module:
Expand Down Expand Up @@ -348,7 +348,10 @@ def visit_Call(self, node):
msg = "Instantiating a struct using a dictionary is deprecated "
msg += "as of v0.4.0 and will be disallowed in a future release. "
msg += "Use kwargs instead e.g. Foo(a=1, b=2)"
warnings.warn(msg, stacklevel=2)

# add full_source_code so that str(VyperException(msg, node)) works
node.full_source_code = self._source_code
vyper_warn(msg, node)

dict_ = node.args[0]
kw_list = []
Expand Down
22 changes: 13 additions & 9 deletions vyper/builtins/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1234,7 +1234,9 @@ class SelfDestruct(BuiltinFunctionT):
@process_inputs
def build_IR(self, expr, args, kwargs, context):
if not self._warned:
vyper_warn("`selfdestruct` is deprecated! The opcode is no longer recommended for use.")
vyper_warn(
"`selfdestruct` is deprecated! The opcode is no longer recommended for use.", expr
)
self._warned = True

context.check_is_not_constant("selfdestruct", expr)
Expand Down Expand Up @@ -1337,7 +1339,7 @@ class BitwiseAnd(BuiltinFunctionT):

def _try_fold(self, node):
if not self.__class__._warned:
vyper_warn("`bitwise_and()` is deprecated! Please use the & operator instead.")
vyper_warn("`bitwise_and()` is deprecated! Please use the & operator instead.", node)
self.__class__._warned = True

validate_call_args(node, 2)
Expand All @@ -1362,7 +1364,7 @@ class BitwiseOr(BuiltinFunctionT):

def _try_fold(self, node):
if not self.__class__._warned:
vyper_warn("`bitwise_or()` is deprecated! Please use the | operator instead.")
vyper_warn("`bitwise_or()` is deprecated! Please use the | operator instead.", node)
self.__class__._warned = True

validate_call_args(node, 2)
Expand All @@ -1387,7 +1389,7 @@ class BitwiseXor(BuiltinFunctionT):

def _try_fold(self, node):
if not self.__class__._warned:
vyper_warn("`bitwise_xor()` is deprecated! Please use the ^ operator instead.")
vyper_warn("`bitwise_xor()` is deprecated! Please use the ^ operator instead.", node)
self.__class__._warned = True

validate_call_args(node, 2)
Expand All @@ -1412,7 +1414,7 @@ class BitwiseNot(BuiltinFunctionT):

def _try_fold(self, node):
if not self.__class__._warned:
vyper_warn("`bitwise_not()` is deprecated! Please use the ~ operator instead.")
vyper_warn("`bitwise_not()` is deprecated! Please use the ~ operator instead.", node)
self.__class__._warned = True

validate_call_args(node, 1)
Expand All @@ -1438,7 +1440,7 @@ class Shift(BuiltinFunctionT):

def _try_fold(self, node):
if not self.__class__._warned:
vyper_warn("`shift()` is deprecated! Please use the << or >> operator instead.")
vyper_warn("`shift()` is deprecated! Please use the << or >> operator instead.", node)
self.__class__._warned = True

validate_call_args(node, 2)
Expand Down Expand Up @@ -1764,7 +1766,9 @@ class CreateForwarderTo(CreateMinimalProxyTo):

def build_IR(self, expr, context):
if not self._warned:
vyper_warn("`create_forwarder_to` is a deprecated alias of `create_minimal_proxy_to`!")
vyper_warn(
"`create_forwarder_to` is a deprecated alias of `create_minimal_proxy_to`!", expr
)
self._warned = True

return super().build_IR(expr, context)
Expand Down Expand Up @@ -2265,7 +2269,7 @@ class Breakpoint(BuiltinFunctionT):

def fetch_call_return(self, node):
if not self._warned:
vyper_warn("`breakpoint` should only be used for debugging!\n" + node._annotated_source)
vyper_warn("`breakpoint` should only be used for debugging!", node)
self._warned = True

return None
Expand All @@ -2285,7 +2289,7 @@ class Print(BuiltinFunctionT):

def fetch_call_return(self, node):
if not self._warned:
vyper_warn("`print` should only be used for debugging!\n" + node._annotated_source)
vyper_warn("`print` should only be used for debugging!", node)
self._warned = True

return None
Expand Down
19 changes: 6 additions & 13 deletions vyper/codegen/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
TypeCheckFailure,
TypeMismatch,
UnimplementedException,
VyperException,
tag_exceptions,
)
from vyper.semantics.types import (
Expand Down Expand Up @@ -280,21 +279,15 @@ def parse_Attribute(self):
return IRnode.from_list(["gas"], typ=UINT256_T)
elif key == "block.prevrandao":
if not version_check(begin="paris"):
warning = VyperException(
"tried to use block.prevrandao in pre-Paris "
"environment! Suggest using block.difficulty instead.",
self.expr,
)
vyper_warn(str(warning))
warning = "tried to use block.prevrandao in pre-Paris "
warning += "environment! Suggest using block.difficulty instead."
vyper_warn(warning, self.expr)
return IRnode.from_list(["prevrandao"], typ=UINT256_T)
elif key == "block.difficulty":
if version_check(begin="paris"):
warning = VyperException(
"tried to use block.difficulty in post-Paris "
"environment! Suggest using block.prevrandao instead.",
self.expr,
)
vyper_warn(str(warning))
warning = "tried to use block.difficulty in post-Paris "
warning += "environment! Suggest using block.prevrandao instead."
vyper_warn(warning, self.expr)
return IRnode.from_list(["difficulty"], typ=UINT256_T)
elif key == "block.timestamp":
return IRnode.from_list(["timestamp"], typ=UINT256_T)
Expand Down
9 changes: 6 additions & 3 deletions vyper/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import warnings
from typing import Generic, List, TypeVar, Union

from vyper.exceptions import CompilerPanic, DecimalOverrideException, InvalidLiteral
from vyper.exceptions import CompilerPanic, DecimalOverrideException, InvalidLiteral, VyperException

_T = TypeVar("_T")

Expand Down Expand Up @@ -208,8 +208,11 @@ def trace(n=5, out=sys.stderr):


# print a warning
def vyper_warn(msg, prefix="Warning: ", file_=sys.stderr):
print(f"{prefix}{msg}", file=file_)
def vyper_warn(msg, node=None):
if node is not None:
# use VyperException for its formatting abilities
msg = str(VyperException(msg, node))
warnings.warn(msg, stacklevel=2)


# converts a signature like Func(bool,uint256,address) to its 4 byte method ID
Expand Down

0 comments on commit 26eaa8a

Please sign in to comment.