diff --git a/tests/functional/builtins/codegen/test_empty.py b/tests/functional/builtins/codegen/test_empty.py index dd6c5c7cc1..3088162238 100644 --- a/tests/functional/builtins/codegen/test_empty.py +++ b/tests/functional/builtins/codegen/test_empty.py @@ -672,11 +672,11 @@ def test_empty_array_in_event_logging(get_contract, get_logs): @external def foo(): log MyLog( - b'hellohellohellohellohellohellohellohellohello', - empty(int128[2][3]), - 314159, - b'helphelphelphelphelphelphelphelphelphelphelp', - empty(uint256[3]) + arg1=b'hellohellohellohellohellohellohellohellohello', + arg2=empty(int128[2][3]), + arg3=314159, + arg4=b'helphelphelphelphelphelphelphelphelphelphelp', + arg5=empty(uint256[3]) ) """ diff --git a/tests/functional/codegen/calling_convention/test_default_function.py b/tests/functional/codegen/calling_convention/test_default_function.py index 4d54e31f91..08d9c08678 100644 --- a/tests/functional/codegen/calling_convention/test_default_function.py +++ b/tests/functional/codegen/calling_convention/test_default_function.py @@ -28,7 +28,7 @@ def test_basic_default(env, get_logs, get_contract): @external @payable def __default__(): - log Sent(msg.sender) + log Sent(sender=msg.sender) """ c = get_contract(code) env.set_balance(env.deployer, 10**18) @@ -46,13 +46,13 @@ def test_basic_default_default_param_function(env, get_logs, get_contract): @external @payable def fooBar(a: int128 = 12345) -> int128: - log Sent(empty(address)) + log Sent(sender=empty(address)) return a @external @payable def __default__(): - log Sent(msg.sender) + log Sent(sender=msg.sender) """ c = get_contract(code) env.set_balance(env.deployer, 10**18) @@ -69,7 +69,7 @@ def test_basic_default_not_payable(env, tx_failed, get_contract): @external def __default__(): - log Sent(msg.sender) + log Sent(sender=msg.sender) """ c = get_contract(code) env.set_balance(env.deployer, 10**17) @@ -103,7 +103,7 @@ def test_always_public_2(assert_compile_failed, get_contract): sender: indexed(address) def __default__(): - log Sent(msg.sender) + log Sent(sender=msg.sender) """ assert_compile_failed(lambda: get_contract(code)) @@ -119,12 +119,12 @@ def test_zero_method_id(env, get_logs, get_contract, tx_failed): @payable # function selector: 0x00000000 def blockHashAskewLimitary(v: uint256) -> uint256: - log Sent(2) + log Sent(sig=2) return 7 @external def __default__(): - log Sent(1) + log Sent(sig=1) """ c = get_contract(code) @@ -165,12 +165,12 @@ def test_another_zero_method_id(env, get_logs, get_contract, tx_failed): @payable # function selector: 0x00000000 def wycpnbqcyf() -> uint256: - log Sent(2) + log Sent(sig=2) return 7 @external def __default__(): - log Sent(1) + log Sent(sig=1) """ c = get_contract(code) @@ -205,12 +205,12 @@ def test_partial_selector_match_trailing_zeroes(env, get_logs, get_contract): @payable # function selector: 0xd88e0b00 def fow() -> uint256: - log Sent(2) + log Sent(sig=2) return 7 @external def __default__(): - log Sent(1) + log Sent(sig=1) """ c = get_contract(code) diff --git a/tests/functional/codegen/features/decorators/test_private.py b/tests/functional/codegen/features/decorators/test_private.py index d313aa3bda..b9e34ea49b 100644 --- a/tests/functional/codegen/features/decorators/test_private.py +++ b/tests/functional/codegen/features/decorators/test_private.py @@ -436,7 +436,7 @@ def i_am_me() -> bool: @external @nonpayable def whoami() -> address: - log Addr(self._whoami()) + log Addr(addr=self._whoami()) return self._whoami() """ diff --git a/tests/functional/codegen/features/test_logging.py b/tests/functional/codegen/features/test_logging.py index cf77a30bd9..2bb646e6ef 100644 --- a/tests/functional/codegen/features/test_logging.py +++ b/tests/functional/codegen/features/test_logging.py @@ -5,13 +5,14 @@ from tests.utils import decimal_to_int from vyper import compile_code from vyper.exceptions import ( - ArgumentException, EventDeclarationException, + InstantiationException, InvalidType, NamespaceCollision, StructureException, TypeMismatch, UndeclaredDefinition, + UnknownAttribute, ) from vyper.utils import keccak256 @@ -50,7 +51,7 @@ def test_event_logging_with_topics(get_logs, keccak, get_contract): @external def foo(): self.a = b"bar" - log MyLog(self.a) + log MyLog(arg1=self.a) """ c = get_contract(loggy_code) @@ -78,7 +79,7 @@ def test_event_logging_with_multiple_topics(env, keccak, get_logs, get_contract) @external def foo(): - log MyLog(-2, True, self) + log MyLog(arg1=-2, arg2=True, arg3=self) """ c = get_contract(loggy_code) @@ -120,7 +121,7 @@ def test_event_logging_with_multiple_topics_var_and_store(get_contract, get_logs def foo(arg1: int128): a: bool = True self.b = self - log MyLog(arg1, a, self.b) + log MyLog(arg1=arg1, arg2=a, arg3=self.b) """ c = get_contract(code) @@ -141,13 +142,13 @@ def test_logging_the_same_event_multiple_times_with_topics(env, keccak, get_logs @external def foo(): - log MyLog(1, self) - log MyLog(1, self) + log MyLog(arg1=1, arg2=self) + log MyLog(arg1=1, arg2=self) @external def bar(): - log MyLog(1, self) - log MyLog(1, self) + log MyLog(arg1=1, arg2=self) + log MyLog(arg1=1, arg2=self) """ c = get_contract(loggy_code) @@ -198,7 +199,7 @@ def test_event_logging_with_data(get_logs, keccak, get_contract): @external def foo(): - log MyLog(123) + log MyLog(arg1=123) """ c = get_contract(loggy_code) @@ -231,8 +232,16 @@ def test_event_logging_with_fixed_array_data(env, keccak, get_logs, get_contract @external def foo(): - log MyLog([1,2], [block.timestamp, block.timestamp+1, block.timestamp+2], [[1,2],[1,2]]) - log MyLog([1,2], [block.timestamp, block.timestamp+1, block.timestamp+2], [[1,2],[1,2]]) + log MyLog( + arg1=[1,2], + arg2=[block.timestamp, block.timestamp+1, block.timestamp+2], + arg3=[[1,2],[1,2]] + ) + log MyLog( + arg1=[1,2], + arg2=[block.timestamp, block.timestamp+1, block.timestamp+2], + arg3=[[1,2],[1,2]] + ) """ c = get_contract(loggy_code) @@ -271,7 +280,7 @@ def test_logging_with_input_bytes_1(env, keccak, get_logs, get_contract): @external def foo(arg1: Bytes[29], arg2: Bytes[31]): - log MyLog(b'bar', arg1, arg2) + log MyLog(arg1=b'bar', arg2=arg1, arg3=arg2) """ c = get_contract(loggy_code) @@ -307,7 +316,7 @@ def test_event_logging_with_bytes_input_2(env, keccak, get_logs, get_contract): @external def foo(_arg1: Bytes[20]): - log MyLog(_arg1) + log MyLog(arg1=_arg1) """ c = get_contract(loggy_code) @@ -335,7 +344,7 @@ def test_event_logging_with_bytes_input_3(get_logs, keccak, get_contract): @external def foo(_arg1: Bytes[5]): - log MyLog(_arg1) + log MyLog(arg1=_arg1) """ c = get_contract(loggy_code) @@ -369,7 +378,7 @@ def test_event_logging_with_data_with_different_types(env, keccak, get_logs, get @external def foo(): - log MyLog(123, b'home', b'bar', 0xc305c901078781C232A2a521C2aF7980f8385ee9, self, block.timestamp) # noqa: E501 + log MyLog(arg1=123, arg2=b'home', arg3=b'bar', arg4=0xc305c901078781C232A2a521C2aF7980f8385ee9, arg5=self, arg6=block.timestamp) # noqa: E501 """ c = get_contract(loggy_code) @@ -412,7 +421,7 @@ def test_event_logging_with_topics_and_data_1(env, keccak, get_logs, get_contrac @external def foo(): - log MyLog(1, b'bar') + log MyLog(arg1=1, arg2=b'bar') """ c = get_contract(loggy_code) @@ -457,8 +466,8 @@ def test_event_logging_with_multiple_logs_topics_and_data(env, keccak, get_logs, @external def foo(): - log MyLog(1, b'bar') - log YourLog(self, MyStruct(x=1, y=b'abc', z=SmallStruct(t='house', w=13.5))) + log MyLog(arg1=1, arg2=b'bar') + log YourLog(arg1=self, arg2=MyStruct(x=1, y=b'abc', z=SmallStruct(t='house', w=13.5))) """ c = get_contract(loggy_code) @@ -524,7 +533,7 @@ def test_fails_when_input_is_the_wrong_type(tx_failed, get_contract): @external def foo_(): - log MyLog(b'yo') + log MyLog(arg1=b'yo') """ with tx_failed(TypeMismatch): @@ -539,7 +548,7 @@ def test_fails_when_topic_is_the_wrong_size(tx_failed, get_contract): @external def foo(): - log MyLog(b'bars') + log MyLog(arg1=b'bars') """ with tx_failed(TypeMismatch): @@ -553,7 +562,7 @@ def test_fails_when_input_topic_is_the_wrong_size(tx_failed, get_contract): @external def foo(arg1: Bytes[4]): - log MyLog(arg1) + log MyLog(arg1=arg1) """ with tx_failed(TypeMismatch): @@ -567,7 +576,7 @@ def test_fails_when_data_is_the_wrong_size(tx_failed, get_contract): @external def foo(): - log MyLog(b'bars') + log MyLog(arg1=b'bars') """ with tx_failed(TypeMismatch): @@ -581,7 +590,7 @@ def test_fails_when_input_data_is_the_wrong_size(tx_failed, get_contract): @external def foo(arg1: Bytes[4]): - log MyLog(arg1) + log MyLog(arg1=arg1) """ with tx_failed(TypeMismatch): @@ -610,7 +619,7 @@ def test_logging_fails_with_over_three_topics(tx_failed, get_contract): @deploy def __init__(): - log MyLog(1, 2, 3, 4) + log MyLog(arg1=1, arg2=2, arg3=3, arg4=4) """ with tx_failed(EventDeclarationException): @@ -650,7 +659,7 @@ def test_logging_fails_with_topic_type_mismatch(tx_failed, get_contract): @external def foo(): - log MyLog(self) + log MyLog(arg1=self) """ with tx_failed(TypeMismatch): @@ -664,7 +673,7 @@ def test_logging_fails_with_data_type_mismatch(tx_failed, get_contract): @external def foo(): - log MyLog(self) + log MyLog(arg1=self) """ with tx_failed(TypeMismatch): @@ -680,9 +689,9 @@ def test_logging_fails_when_number_of_arguments_is_greater_than_declaration( @external def foo(): - log MyLog(1, 2) + log MyLog(arg1=1, arg2=2) """ - with tx_failed(ArgumentException): + with tx_failed(UnknownAttribute): get_contract(loggy_code) @@ -694,9 +703,9 @@ def test_logging_fails_when_number_of_arguments_is_less_than_declaration(tx_fail @external def foo(): - log MyLog(1) + log MyLog(arg1=1) """ - with tx_failed(ArgumentException): + with tx_failed(InstantiationException): get_contract(loggy_code) @@ -852,7 +861,7 @@ def test_variable_list_packing(get_logs, get_contract): @external def foo(): a: int128[4] = [1, 2, 3, 4] - log Bar(a) + log Bar(_value=a) """ c = get_contract(code) @@ -868,7 +877,7 @@ def test_literal_list_packing(get_logs, get_contract): @external def foo(): - log Bar([1, 2, 3, 4]) + log Bar(_value=[1, 2, 3, 4]) """ c = get_contract(code) @@ -886,7 +895,7 @@ def test_storage_list_packing(get_logs, get_contract): @external def foo(): - log Bar(self.x) + log Bar(_value=self.x) @external def set_list(): @@ -910,7 +919,7 @@ def test_passed_list_packing(get_logs, get_contract): @external def foo(barbaric: int128[4]): - log Bar(barbaric) + log Bar(_value=barbaric) """ c = get_contract(code) @@ -926,7 +935,7 @@ def test_variable_decimal_list_packing(get_logs, get_contract): @external def foo(): - log Bar([1.11, 2.22, 3.33, 4.44]) + log Bar(_value=[1.11, 2.22, 3.33, 4.44]) """ c = get_contract(code) @@ -949,7 +958,7 @@ def test_storage_byte_packing(get_logs, get_contract): @external def foo(a: int128): - log MyLog(self.x) + log MyLog(arg1=self.x) @external def setbytez(): @@ -975,7 +984,7 @@ def test_storage_decimal_list_packing(get_logs, get_contract): @external def foo(): - log Bar(self.x) + log Bar(_value=self.x) @external def set_list(): @@ -1004,7 +1013,7 @@ def test_logging_fails_when_input_is_too_big(tx_failed, get_contract): @external def foo(inp: Bytes[33]): - log Bar(inp) + log Bar(_value=inp) """ with tx_failed(TypeMismatch): get_contract(code) @@ -1019,7 +1028,7 @@ def test_2nd_var_list_packing(get_logs, get_contract): @external def foo(): a: int128[4] = [1, 2, 3, 4] - log Bar(10, a) + log Bar(arg1=10, arg2=a) """ c = get_contract(code) @@ -1037,7 +1046,7 @@ def test_2nd_var_storage_list_packing(get_logs, get_contract): @external def foo(): - log Bar(10, self.x) + log Bar(arg1=10, arg2=self.x) @external def set_list(): @@ -1071,7 +1080,7 @@ def __init__(): @external def foo(): v: int128[3] = [7, 8, 9] - log Bar(10, self.x, b"test", v, self.y) + log Bar(arg1=10, arg2=self.x, arg3=b"test", arg4=v, arg5=self.y) @external def set_list(): @@ -1104,7 +1113,7 @@ def test_hashed_indexed_topics_calldata(get_logs, keccak, get_contract): @external def foo(a: Bytes[36], b: int128, c: String[7]): - log MyLog(a, b, c) + log MyLog(arg1=a, arg2=b, arg3=c) """ c = get_contract(loggy_code) @@ -1144,7 +1153,7 @@ def foo(): a: Bytes[10] = b"potato" b: int128 = -777 c: String[44] = "why hello, neighbor! how are you today?" - log MyLog(a, b, c) + log MyLog(arg1=a, arg2=b, arg3=c) """ c = get_contract(loggy_code) @@ -1191,7 +1200,7 @@ def setter(_a: Bytes[32], _b: int128, _c: String[6]): @external def foo(): - log MyLog(self.a, self.b, self.c) + log MyLog(arg1=self.a, arg2=self.b, arg3=self.c) """ c = get_contract(loggy_code) @@ -1229,7 +1238,7 @@ def test_hashed_indexed_topics_storxxage(get_logs, keccak, get_contract): @external def foo(): - log MyLog(b"wow", 666, "madness!") + log MyLog(arg1=b"wow", arg2=666, arg3="madness!") """ c = get_contract(loggy_code) diff --git a/tests/functional/codegen/features/test_logging_bytes_extended.py b/tests/functional/codegen/features/test_logging_bytes_extended.py index 6b84cdd23a..64c848bb8e 100644 --- a/tests/functional/codegen/features/test_logging_bytes_extended.py +++ b/tests/functional/codegen/features/test_logging_bytes_extended.py @@ -7,7 +7,7 @@ def test_bytes_logging_extended(get_contract, get_logs): @external def foo(): - log MyLog(667788, b'hellohellohellohellohellohellohellohellohello', 334455) + log MyLog(arg1=667788, arg2=b'hellohellohellohellohellohellohellohellohello', arg3=334455) """ c = get_contract(code) @@ -31,7 +31,7 @@ def foo(): a: Bytes[64] = b'hellohellohellohellohellohellohellohellohello' b: Bytes[64] = b'hellohellohellohellohellohellohellohello' # test literal much smaller than buffer - log MyLog(a, b, b'hello') + log MyLog(arg1=a, arg2=b, arg3=b'hello') """ c = get_contract(code) @@ -51,7 +51,7 @@ def test_bytes_logging_extended_passthrough(get_contract, get_logs): @external def foo(a: int128, b: Bytes[64], c: int128): - log MyLog(a, b, c) + log MyLog(arg1=a, arg2=b, arg3=c) """ c = get_contract(code) @@ -77,7 +77,7 @@ def test_bytes_logging_extended_storage(get_contract, get_logs): @external def foo(): - log MyLog(self.a, self.b, self.c) + log MyLog(arg1=self.a, arg2=self.b, arg3=self.c) @external def set(x: int128, y: Bytes[64], z: int128): @@ -114,10 +114,10 @@ def test_bytes_logging_extended_mixed_with_lists(get_contract, get_logs): @external def foo(): log MyLog( - [[24, 26], [12, 10]], - b'hellohellohellohellohellohellohellohellohello', - 314159, - b'helphelphelphelphelphelphelphelphelphelphelp' + arg1=[[24, 26], [12, 10]], + arg2=b'hellohellohellohellohellohellohellohellohello', + arg3=314159, + arg4=b'helphelphelphelphelphelphelphelphelphelphelp' ) """ diff --git a/tests/functional/codegen/features/test_logging_from_call.py b/tests/functional/codegen/features/test_logging_from_call.py index 190be7b4f4..2b14cd8398 100644 --- a/tests/functional/codegen/features/test_logging_from_call.py +++ b/tests/functional/codegen/features/test_logging_from_call.py @@ -21,11 +21,11 @@ def to_bytes32(_value: uint256) -> bytes32: @external def test_func(_value: uint256): data2: Bytes[60] = concat(self.to_bytes32(_value),self.to_bytes(_value),b"testing") - log TestLog(self.to_bytes32(_value), data2, self.to_bytes(_value)) + log TestLog(testData1=self.to_bytes32(_value), testData2=data2, testData3=self.to_bytes(_value)) loggedValue: bytes32 = self.to_bytes32(_value) loggedValue2: Bytes[8] = self.to_bytes(_value) - log TestLog(loggedValue, data2, loggedValue2) + log TestLog(testData1=loggedValue, testData2=data2, testData3=loggedValue2) """ c = get_contract(code) @@ -65,8 +65,8 @@ def test_func(_value: uint256,input: Bytes[133]): data2: Bytes[200] = b"hello world" - # log TestLog(self.to_bytes32(_value),input,self.to_bytes(_value)) - log TestLog(self.to_bytes32(_value),input,"bababa") + # log TestLog(testData1=self.to_bytes32(_value),testData2=input,testData3=self.to_bytes(_value)) + log TestLog(testData1=self.to_bytes32(_value),testData2=input,testData3="bababa") """ c = get_contract(code) @@ -99,8 +99,8 @@ def test_func(_value: uint256,input: Bytes[133]): data2: Bytes[200] = b"hello world" # log will be malformed - # log TestLog(self.to_bytes32(_value),input,self.to_bytes(_value)) - log TestLog(self.to_bytes32(_value), input) + # log TestLog(testData1=self.to_bytes32(_value),testData2=input,testData3=self.to_bytes(_value)) + log TestLog(testData1=self.to_bytes32(_value), testData2=input) """ c = get_contract(code) @@ -137,12 +137,12 @@ def test_func(_value: uint256,input: Bytes[2048]): data2: Bytes[2064] = concat(self.to_bytes(_value),self.to_bytes(_value),input) # log will be malformed - log TestLog(self.to_bytes32(_value), data2, self.to_bytes(_value)) + log TestLog(testData1=self.to_bytes32(_value), testData2=data2, testData3=self.to_bytes(_value)) loggedValue: Bytes[8] = self.to_bytes(_value) # log will be normal - log TestLog(self.to_bytes32(_value),data2,loggedValue) + log TestLog(testData1=self.to_bytes32(_value),testData2=data2,testData3=loggedValue) """ c = get_contract(code) diff --git a/tests/functional/codegen/features/test_memory_dealloc.py b/tests/functional/codegen/features/test_memory_dealloc.py index 3be57038ef..b733de736b 100644 --- a/tests/functional/codegen/features/test_memory_dealloc.py +++ b/tests/functional/codegen/features/test_memory_dealloc.py @@ -9,7 +9,7 @@ def sendit(): nonpayable @external def foo(target: address) -> uint256[2]: - log Shimmy(empty(address), 3) + log Shimmy(a=empty(address), b=3) amount: uint256 = 1 flargen: uint256 = 42 extcall Other(target).sendit() diff --git a/tests/functional/codegen/modules/test_events.py b/tests/functional/codegen/modules/test_events.py index ae5198cf90..c32a66caec 100644 --- a/tests/functional/codegen/modules/test_events.py +++ b/tests/functional/codegen/modules/test_events.py @@ -50,7 +50,7 @@ def test_module_event_indexed(get_contract, make_input_bundle, get_logs): @internal def foo(): - log MyEvent(5, 6) + log MyEvent(x=5, y=6) """ main = """ import lib1 diff --git a/tests/functional/codegen/types/test_string.py b/tests/functional/codegen/types/test_string.py index 51899b50f3..1c186eeb6e 100644 --- a/tests/functional/codegen/types/test_string.py +++ b/tests/functional/codegen/types/test_string.py @@ -116,7 +116,7 @@ def test_logging_extended_string(get_contract, get_logs): @external def foo(): - log MyLog(667788, 'hellohellohellohellohellohellohellohellohello', 334455) + log MyLog(arg1=667788, arg2='hellohellohellohellohellohellohellohellohello', arg3=334455) """ c = get_contract(code) diff --git a/tests/functional/syntax/exceptions/test_type_mismatch_exception.py b/tests/functional/syntax/exceptions/test_type_mismatch_exception.py index 514f2df618..76c5c481f0 100644 --- a/tests/functional/syntax/exceptions/test_type_mismatch_exception.py +++ b/tests/functional/syntax/exceptions/test_type_mismatch_exception.py @@ -41,7 +41,7 @@ def foo(): message: String[1] @external def foo(): - log Foo("abcd") + log Foo(message="abcd") """, # Address literal must be checksummed """ diff --git a/tests/functional/syntax/names/test_event_names.py b/tests/functional/syntax/names/test_event_names.py index 367b646bfe..28cd6bdad0 100644 --- a/tests/functional/syntax/names/test_event_names.py +++ b/tests/functional/syntax/names/test_event_names.py @@ -26,7 +26,7 @@ def foo(i: int128) -> int128: @external def foo(i: int128) -> int128: temp_var : int128 = i - log int128(temp_var) + log int128(variable=temp_var) return temp_var """, NamespaceCollision, @@ -39,7 +39,7 @@ def foo(i: int128) -> int128: @external def foo(i: int128) -> int128: temp_var : int128 = i - log decimal(temp_var) + log decimal(variable=temp_var) return temp_var """, NamespaceCollision, @@ -52,7 +52,7 @@ def foo(i: int128) -> int128: @external def foo(i: int128) -> int128: temp_var : int128 = i - log wei(temp_var) + log wei(variable=temp_var) return temp_var """, StructureException, @@ -65,7 +65,7 @@ def foo(i: int128) -> int128: @external def foo(i: int128) -> int128: temp_var : int128 = i - log false(temp_var) + log false(variable=temp_var) return temp_var """, StructureException, @@ -102,7 +102,7 @@ def test_varname_validity_fail(bad_code, exc): @external def foo(i: int128) -> int128: variable : int128 = i - log Assigned(variable) + log Assigned(variable=variable) return variable """, """ @@ -122,7 +122,7 @@ def foo(i: int128) -> int128: @external def foo(i: int128) -> int128: variable : int128 = i - log Assigned1(variable) + log Assigned1(variable=variable) return variable """, ] diff --git a/tests/functional/syntax/test_ann_assign.py b/tests/functional/syntax/test_ann_assign.py index 23ebeb9560..fba9eff38d 100644 --- a/tests/functional/syntax/test_ann_assign.py +++ b/tests/functional/syntax/test_ann_assign.py @@ -3,11 +3,11 @@ from vyper import compiler from vyper.exceptions import ( + InstantiationException, InvalidAttribute, TypeMismatch, UndeclaredDefinition, UnknownAttribute, - VariableDeclarationException, ) fail_list = [ @@ -73,7 +73,7 @@ def foo() -> int128: def foo() -> int128: s: S = S(a=1) """, - VariableDeclarationException, + InstantiationException, ), ( """ diff --git a/tests/functional/syntax/test_external_calls.py b/tests/functional/syntax/test_external_calls.py index a8fb5ae87b..fd6fa28cc9 100644 --- a/tests/functional/syntax/test_external_calls.py +++ b/tests/functional/syntax/test_external_calls.py @@ -61,7 +61,7 @@ def foo(f: Foo): s: uint256 = staticcall f.foo() """, # TODO: tokenizer currently has issue with log+staticcall/extcall, e.g. - # `log Bar(staticcall f.foo() + extcall f.bar())` + # `log Bar(_value=staticcall f.foo() + extcall f.bar())` ] diff --git a/tests/functional/syntax/test_interfaces.py b/tests/functional/syntax/test_interfaces.py index ea06e0ab2f..20813c48d1 100644 --- a/tests/functional/syntax/test_interfaces.py +++ b/tests/functional/syntax/test_interfaces.py @@ -158,12 +158,12 @@ def f(a: uint256): # visibility is nonpayable instead of view @external def transfer(_to : address, _value : uint256) -> bool: - log Transfer(msg.sender, _to, _value) + log Transfer(sender=msg.sender, receiver=_to, value=_value) return True @external def transferFrom(_from : address, _to : address, _value : uint256) -> bool: - log IERC20.Transfer(_from, _to, _value) + log IERC20.Transfer(sender=_from, receiver=_to, value=_value) return True @external diff --git a/tests/functional/syntax/test_logging.py b/tests/functional/syntax/test_logging.py index b96700a128..7f8f141b99 100644 --- a/tests/functional/syntax/test_logging.py +++ b/tests/functional/syntax/test_logging.py @@ -1,7 +1,13 @@ import pytest from vyper import compiler -from vyper.exceptions import StructureException, TypeMismatch +from vyper.exceptions import ( + InstantiationException, + InvalidAttribute, + StructureException, + TypeMismatch, + UnknownAttribute, +) fail_list = [ """ @@ -12,7 +18,7 @@ @external def foo(): - log Bar(self.x) + log Bar(_value=self.x) """, """ event Bar: @@ -21,7 +27,7 @@ def foo(): @external def foo(): x: decimal[4] = [0.0, 0.0, 0.0, 0.0] - log Bar(x) + log Bar(_value=x) """, """ struct Foo: @@ -37,7 +43,7 @@ def foo(): @external def test(): - log Test(-7) + log Test(n=-7) """, ] @@ -48,6 +54,61 @@ def test_logging_fail(bad_code): compiler.compile_code(bad_code) +def test_logging_fail_mixed_positional_kwargs(): + code = """ +event Test: + n: uint256 + o: uint256 + +@external +def test(): + log Test(7, o=12) + """ + with pytest.raises(InstantiationException): + compiler.compile_code(code) + + +def test_logging_fail_unknown_kwarg(): + code = """ +event Test: + n: uint256 + +@external +def test(): + log Test(n=7, o=12) + """ + with pytest.raises(UnknownAttribute): + compiler.compile_code(code) + + +def test_logging_fail_missing_kwarg(): + code = """ +event Test: + n: uint256 + o: uint256 + +@external +def test(): + log Test(n=7) + """ + with pytest.raises(InstantiationException): + compiler.compile_code(code) + + +def test_logging_fail_kwargs_out_of_order(): + code = """ +event Test: + n: uint256 + o: uint256 + +@external +def test(): + log Test(o=12, n=7) + """ + with pytest.raises(InvalidAttribute): + compiler.compile_code(code) + + @pytest.mark.parametrize("mutability", ["@pure", "@view"]) @pytest.mark.parametrize("visibility", ["@internal", "@external"]) def test_logging_from_non_mutable(mutability, visibility): @@ -58,7 +119,23 @@ def test_logging_from_non_mutable(mutability, visibility): {visibility} {mutability} def test(): - log Test(1) + log Test(n=1) """ with pytest.raises(StructureException): compiler.compile_code(code) + + +def test_logging_with_positional_args(get_contract, get_logs): + # TODO: Remove when positional arguments are fully deprecated + code = """ +event Test: + n: uint256 + +@external +def test(): + log Test(1) + """ + c = get_contract(code) + c.test() + (log,) = get_logs(c, "Test") + assert log.args.n == 1 diff --git a/tests/functional/syntax/test_structs.py b/tests/functional/syntax/test_structs.py index 9a9a397c48..c08859cd92 100644 --- a/tests/functional/syntax/test_structs.py +++ b/tests/functional/syntax/test_structs.py @@ -5,6 +5,7 @@ from vyper import compiler from vyper.exceptions import ( InstantiationException, + InvalidAttribute, StructureException, SyntaxException, TypeMismatch, @@ -32,7 +33,8 @@ def foo(): """, UnknownAttribute, ), - """ + ( + """ struct A: x: int128 y: int128 @@ -41,6 +43,8 @@ def foo(): def foo(): self.a = A(x=1) """, + InstantiationException, + ), """ struct A: x: int128 @@ -61,7 +65,8 @@ def foo(): def foo(): self.a = A(self.b) """, - """ + ( + """ struct A: x: int128 y: int128 @@ -70,6 +75,8 @@ def foo(): def foo(): self.a = A({x: 1}) """, + InstantiationException, + ), """ struct C: c: int128 @@ -386,7 +393,7 @@ def foo(): def foo(): self.b = B(foo=1, foo=2) """, - UnknownAttribute, + InvalidAttribute, ), ( """ diff --git a/vyper/codegen/stmt.py b/vyper/codegen/stmt.py index 225cede747..b1e26d7d5f 100644 --- a/vyper/codegen/stmt.py +++ b/vyper/codegen/stmt.py @@ -93,7 +93,13 @@ def parse_If(self): def parse_Log(self): event = self.stmt._metadata["type"] - args = [Expr(arg, self.context).ir_node for arg in self.stmt.value.args] + if len(self.stmt.value.keywords) > 0: + # keyword arguments + to_compile = [arg.value for arg in self.stmt.value.keywords] + else: + # positional arguments + to_compile = self.stmt.value.args + args = [Expr(arg, self.context).ir_node for arg in to_compile] topic_ir = [] data_ir = [] diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py index b5292b1dad..809c6532c6 100644 --- a/vyper/semantics/analysis/local.py +++ b/vyper/semantics/analysis/local.py @@ -810,13 +810,17 @@ def visit_Call(self, node: vy_ast.Call, typ: VyperType) -> None: self.visit(kwarg.value, typ) elif is_type_t(func_type, EventT): - # events have no kwargs + # event ctors expected_types = func_type.typedef.arguments.values() # type: ignore - for arg, typ in zip(node.args, expected_types): - self.visit(arg, typ) + # Handle keyword args if present, otherwise use positional args + if len(node.keywords) > 0: + for kwarg, arg_type in zip(node.keywords, expected_types): + self.visit(kwarg.value, arg_type) + else: + for arg, typ in zip(node.args, expected_types): + self.visit(arg, typ) elif is_type_t(func_type, StructT): # struct ctors - # ctors have no kwargs expected_types = func_type.typedef.members.values() # type: ignore for kwarg, arg_type in zip(node.keywords, expected_types): self.visit(kwarg.value, arg_type) diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index 90bb631e14..6816fbed98 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -897,7 +897,7 @@ def _import_to_path(level: int, module_str: str) -> PurePath: base_path = "../" * (level - 1) elif level == 1: base_path = "./" - return PurePath(f"{base_path}{module_str.replace('.','/')}/") + return PurePath(f"{base_path}{module_str.replace('.', '/')}/") # can add more, e.g. "vyper.builtins.interfaces", etc. diff --git a/vyper/semantics/analysis/utils.py b/vyper/semantics/analysis/utils.py index d30eee79e0..9734087fc3 100644 --- a/vyper/semantics/analysis/utils.py +++ b/vyper/semantics/analysis/utils.py @@ -1,9 +1,11 @@ import itertools -from typing import Callable, Iterable, List +from typing import Any, Callable, Iterable, List from vyper import ast as vy_ast from vyper.exceptions import ( CompilerPanic, + InstantiationException, + InvalidAttribute, InvalidLiteral, InvalidOperation, InvalidReference, @@ -694,3 +696,43 @@ def get_expr_writes(node: vy_ast.VyperNode) -> OrderedSet[VarAccess]: ret |= get_expr_writes(c) node._metadata["writes_r"] = ret return ret + + +def validate_kwargs(node: vy_ast.Call, members: dict[str, VyperType], typeclass: str): + # manually validate kwargs for better error messages instead of + # relying on `validate_call_args` + + seen: dict[str, vy_ast.keyword] = {} + membernames = list(members.keys()) + + # check duplicate kwargs + for i, kwarg in enumerate(node.keywords): + # x=5 => kwarg(arg="x", value=Int(5)) + argname = kwarg.arg + if argname in seen: + prev = seen[argname] + raise InvalidAttribute(f"Duplicate {typeclass} argument", prev, kwarg) + seen[argname] = kwarg + + hint: Any # mypy kludge + if argname not in members: + hint = get_levenshtein_error_suggestions(argname, members, 1.0) + raise UnknownAttribute(f"Unknown {typeclass} argument.", kwarg, hint=hint) + + expect_name = membernames[i] + if argname != expect_name: + # out of order key + msg = f"{typeclass} keys are required to be in order, but got" + msg += f" `{argname}` instead of `{expect_name}`." + hint = "as a reminder, the order of the keys in this" + hint += f" {typeclass} are {list(members)}" + raise InvalidAttribute(msg, kwarg, hint=hint) + + expected_type = members[argname] + validate_expected_type(kwarg.value, expected_type) + + missing = OrderedSet(members.keys()) - OrderedSet(seen.keys()) + if len(missing) > 0: + msg = f"{typeclass} instantiation missing fields:" + msg += f" {', '.join(list(missing))}" + raise InstantiationException(msg, node) diff --git a/vyper/semantics/types/user.py b/vyper/semantics/types/user.py index ca8e99bc92..73fa4878c7 100644 --- a/vyper/semantics/types/user.py +++ b/vyper/semantics/types/user.py @@ -7,21 +7,23 @@ from vyper.exceptions import ( EventDeclarationException, FlagDeclarationException, - InvalidAttribute, + InstantiationException, NamespaceCollision, StructureException, UnfoldableNode, - UnknownAttribute, VariableDeclarationException, ) from vyper.semantics.analysis.base import Modifiability -from vyper.semantics.analysis.levenshtein_utils import get_levenshtein_error_suggestions -from vyper.semantics.analysis.utils import check_modifiability, validate_expected_type +from vyper.semantics.analysis.utils import ( + check_modifiability, + validate_expected_type, + validate_kwargs, +) from vyper.semantics.data_locations import DataLocation from vyper.semantics.types.base import VyperType from vyper.semantics.types.subscriptable import HashMapT from vyper.semantics.types.utils import type_from_abi, type_from_annotation -from vyper.utils import keccak256 +from vyper.utils import keccak256, vyper_warn # user defined type @@ -281,6 +283,25 @@ def from_EventDef(cls, base_node: vy_ast.EventDef) -> "EventT": return cls(base_node.name, members, indexed, base_node) def _ctor_call_return(self, node: vy_ast.Call) -> None: + # validate keyword arguments if provided + if len(node.keywords) > 0: + if len(node.args) > 0: + raise InstantiationException( + "Event instantiation requires either all keyword arguments " + "or all positional arguments", + node, + ) + + return validate_kwargs(node, self.arguments, self.typeclass) + + # warn about positional argument depreciation + msg = "Instantiating events with positional arguments is " + msg += "deprecated as of v0.4.1 and will be disallowed " + msg += "in a future release. Use kwargs instead eg. " + msg += "Foo(a=1, b=2)" + + vyper_warn(msg, node) + validate_call_args(node, len(self.arguments)) for arg, expected in zip(node.args, self.arguments.values()): validate_expected_type(arg, expected) @@ -415,31 +436,7 @@ def _ctor_call_return(self, node: vy_ast.Call) -> "StructT": "Struct contains a mapping and so cannot be declared as a literal", node ) - # manually validate kwargs for better error messages instead of - # relying on `validate_call_args` - members = self.member_types.copy() - keys = list(self.member_types.keys()) - for i, kwarg in enumerate(node.keywords): - # x=5 => kwarg(arg="x", value=Int(5)) - argname = kwarg.arg - if argname not in members: - hint = get_levenshtein_error_suggestions(argname, members, 1.0) - raise UnknownAttribute("Unknown or duplicate struct member.", kwarg, hint=hint) - expected = keys[i] - if argname != expected: - raise InvalidAttribute( - "Struct keys are required to be in order, but got " - f"`{argname}` instead of `{expected}`. (Reminder: the " - f"keys in this struct are {list(self.member_types.items())})", - kwarg, - ) - expected_type = members.pop(argname) - validate_expected_type(kwarg.value, expected_type) - - if members: - raise VariableDeclarationException( - f"Struct declaration does not define all fields: {', '.join(list(members))}", node - ) + validate_kwargs(node, self.member_types, self.typeclass) return self diff --git a/vyper/utils.py b/vyper/utils.py index 5307cd115e..d635c78383 100644 --- a/vyper/utils.py +++ b/vyper/utils.py @@ -89,6 +89,7 @@ def update(self, other): def union(self, other): return self | other + # set dunders def __ior__(self, other): self.update(other) return self @@ -101,6 +102,15 @@ def __or__(self, other): def __eq__(self, other): return self._data == other._data + def __isub__(self, other): + self.dropmany(other) + return self + + def __sub__(self, other): + ret = self.copy() + ret.dropmany(other) + return ret + def copy(self): cls = self.__class__ ret = cls.__new__(cls)