mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/develop' into develop_060
This commit is contained in:
		
						commit
						acd4a1e3a6
					
				| @ -15,6 +15,7 @@ Bugfixes: | ||||
| ### 0.5.12 (unreleased) | ||||
| 
 | ||||
| Language Features: | ||||
|  * Type Checker: Allow assignment to external function arguments except for reference types. | ||||
| 
 | ||||
| 
 | ||||
| Compiler Features: | ||||
|  | ||||
| @ -2515,8 +2515,47 @@ void TypeChecker::requireLValue(Expression const& _expression) | ||||
| 	_expression.annotation().lValueRequested = true; | ||||
| 	_expression.accept(*this); | ||||
| 
 | ||||
| 	if (_expression.annotation().isConstant) | ||||
| 		m_errorReporter.typeError(_expression.location(), "Cannot assign to a constant variable."); | ||||
| 	else if (!_expression.annotation().isLValue) | ||||
| 		m_errorReporter.typeError(_expression.location(), "Expression has to be an lvalue."); | ||||
| 	if (_expression.annotation().isLValue) | ||||
| 		return; | ||||
| 
 | ||||
| 	return m_errorReporter.typeError(_expression.location(), [&]() { | ||||
| 		if (_expression.annotation().isConstant) | ||||
| 			return "Cannot assign to a constant variable."; | ||||
| 
 | ||||
| 		if (auto indexAccess = dynamic_cast<IndexAccess const*>(&_expression)) | ||||
| 		{ | ||||
| 			if (type(indexAccess->baseExpression())->category() == Type::Category::FixedBytes) | ||||
| 				return "Single bytes in fixed bytes arrays cannot be modified."; | ||||
| 			else if (auto arrayType = dynamic_cast<ArrayType const*>(type(indexAccess->baseExpression()))) | ||||
| 				if (arrayType->dataStoredIn(DataLocation::CallData)) | ||||
| 					return "Calldata arrays are read-only."; | ||||
| 		} | ||||
| 
 | ||||
| 		if (auto memberAccess = dynamic_cast<MemberAccess const*>(&_expression)) | ||||
| 		{ | ||||
| 			if (auto structType = dynamic_cast<StructType const*>(type(memberAccess->expression()))) | ||||
| 			{ | ||||
| 				if (structType->dataStoredIn(DataLocation::CallData)) | ||||
| 					return "Calldata structs are read-only."; | ||||
| 			} | ||||
| 			else if (auto arrayType = dynamic_cast<ArrayType const*>(type(memberAccess->expression()))) | ||||
| 				if (memberAccess->memberName() == "length") | ||||
| 					switch (arrayType->location()) | ||||
| 					{ | ||||
| 						case DataLocation::Memory: | ||||
| 							return "Memory arrays cannot be resized."; | ||||
| 						case DataLocation::CallData: | ||||
| 							return "Calldata arrays cannot be resized."; | ||||
| 						case DataLocation::Storage: | ||||
| 							break; | ||||
| 					} | ||||
| 		} | ||||
| 
 | ||||
| 		if (auto identifier = dynamic_cast<Identifier const*>(&_expression)) | ||||
| 			if (auto varDecl = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration)) | ||||
| 				if (varDecl->isExternalCallableParameter() && dynamic_cast<ReferenceType const*>(identifier->annotation().type)) | ||||
| 					return "External function arguments of reference type are read-only."; | ||||
| 
 | ||||
| 		return "Expression has to be an lvalue."; | ||||
| 	}()); | ||||
| } | ||||
|  | ||||
| @ -432,8 +432,13 @@ string Scopable::sourceUnitName() const | ||||
| 
 | ||||
| bool VariableDeclaration::isLValue() const | ||||
| { | ||||
| 	// External function parameters and constant declared variables are Read-Only
 | ||||
| 	return !isExternalCallableParameter() && !m_isConstant; | ||||
| 	// Constant declared variables are Read-Only
 | ||||
| 	if (m_isConstant) | ||||
| 		return false; | ||||
| 	// External function arguments of reference type are Read-Only
 | ||||
| 	if (isExternalCallableParameter() && dynamic_cast<ReferenceType const*>(type())) | ||||
| 		return false; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool VariableDeclaration::isLocalVariable() const | ||||
|  | ||||
| @ -26,3 +26,4 @@ contract D { | ||||
| // stateBytes() -> left(0x4200ef) | ||||
| // internalStateDecimal() -> 0x20 | ||||
| // update(bool,uint256,bytes32): false, -23, left(0x2300ef) -> false, -23, left(0x2300ef) | ||||
| 
 | ||||
							
								
								
									
										44
									
								
								test/libsolidity/semanticTests/smoke/arrays.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								test/libsolidity/semanticTests/smoke/arrays.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| contract C { | ||||
|     struct T { | ||||
|         uint a; | ||||
|         uint b; | ||||
|         string s; | ||||
|     } | ||||
|     bool[2][] flags; | ||||
|     function r() public returns (bool[3] memory) { | ||||
|         return [true, false, true]; | ||||
|     } | ||||
|     function s() public returns (uint[2] memory, uint) { | ||||
|         return ([uint(123), 456], 789); | ||||
|     } | ||||
|     function u() public returns (T[2] memory) { | ||||
|         return [T(23, 42, "any"), T(555, 666, "any")]; | ||||
|     } | ||||
|     function v() public returns (bool[2][] memory) { | ||||
|         return flags; | ||||
|     } | ||||
|     function w1() public returns (string[1] memory) { | ||||
|         return ["any"]; | ||||
|     } | ||||
|     function w2() public returns (string[2] memory) { | ||||
|         return ["any", "any"]; | ||||
|     } | ||||
|     function w3() public returns (string[3] memory) { | ||||
|         return ["any", "any", "any"]; | ||||
|     } | ||||
|     function x() public returns (string[2] memory, string[3] memory) { | ||||
|         return (["any", "any"], ["any", "any", "any"]); | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // r() -> true, false, true | ||||
| // s() -> 123, 456, 789 | ||||
| // u() -> 0x20, 0x40, 0xE0, 23, 42, 0x60, 3, "any", 555, 666, 0x60, 3, "any" | ||||
| // v() -> 0x20, 0 | ||||
| // w1() -> 0x20, 0x20, 3, "any" | ||||
| // w2() -> 0x20, 0x40, 0x80, 3, "any", 3, "any" | ||||
| // w3() -> 0x20, 0x60, 0xa0, 0xe0, 3, "any", 3, "any", 3, "any" | ||||
| // x() -> 0x40, 0x0100, 0x40, 0x80, 3, "any", 3, "any", 0x60, 0xa0, 0xe0, 3, "any", 3, "any", 3, "any" | ||||
| 
 | ||||
							
								
								
									
										40
									
								
								test/libsolidity/semanticTests/smoke/basic.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								test/libsolidity/semanticTests/smoke/basic.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| contract C { | ||||
|     function d() public { | ||||
|     } | ||||
|     function e() public payable returns (uint) { | ||||
|         return msg.value; | ||||
|     } | ||||
|     function f(uint a) public pure returns (uint, uint) { | ||||
|         return (a, a); | ||||
|     } | ||||
|     function g() public  pure returns (uint, uint) { | ||||
|         return (2, 3); | ||||
|     } | ||||
|     function h(uint x, uint y) public  pure returns (uint) { | ||||
|         return x - y; | ||||
|     } | ||||
|     function i(bool b) public  pure returns (bool) { | ||||
|         return !b; | ||||
|     } | ||||
|     function j(bytes32 b) public pure returns (bytes32, bytes32) { | ||||
|         return (b, b); | ||||
|     } | ||||
|     function k() public pure returns (uint) { | ||||
|         return msg.data.length; | ||||
|     } | ||||
|     function l(uint a) public pure returns (uint d) { | ||||
|         return a * 7; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // d() -> | ||||
| // e(), 1 ether -> 1 | ||||
| // f(uint256): 3 -> 3, 3 | ||||
| // g() -> 2, 3 | ||||
| // h(uint256,uint256): 1, -2 -> 3 | ||||
| // i(bool): true -> false | ||||
| // j(bytes32): 0x10001 -> 0x10001, 0x10001 | ||||
| // k(): hex"4200efef" -> 8 | ||||
| // l(uint256): 99 -> 693 | ||||
							
								
								
									
										22
									
								
								test/libsolidity/semanticTests/smoke/bytes_and_strings.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								test/libsolidity/semanticTests/smoke/bytes_and_strings.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| contract C { | ||||
|     function e(bytes memory b) public pure returns (bytes memory) { | ||||
|         return b; | ||||
|     } | ||||
|     function f() public pure returns (string memory, string memory) { | ||||
|         return ("any", "any"); | ||||
|     } | ||||
|     function g() public pure returns (string memory, uint, string memory) { | ||||
|         return ("any", 42, "any"); | ||||
|     } | ||||
|     function h() public pure returns (string memory) { | ||||
|         return "any"; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // e(bytes): 32, 3, hex"AB33BB" -> 32, 3, left(0xAB33BB) | ||||
| // e(bytes): 32, 32, 0x20 -> 32, 32, 0x20 | ||||
| // e(bytes): 32, 3, hex"AB33FF" -> 32, 3, hex"ab33ff0000000000000000000000000000000000000000000000000000000000" | ||||
| // f() -> 0x40, 0x80, 3, "any", 3, "any" | ||||
| // g() -> 0x60, 0x2a, 0xa0, 3, "any", 3, "any" | ||||
| // h() -> 0x20, 3, "any" | ||||
| 
 | ||||
							
								
								
									
										18
									
								
								test/libsolidity/semanticTests/smoke/constructor.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								test/libsolidity/semanticTests/smoke/constructor.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| contract C { | ||||
|     uint public state = 0; | ||||
|     constructor(uint _state) public payable { | ||||
|         state = _state; | ||||
|     } | ||||
|     function balance() public payable returns (uint256) { | ||||
|         return address(this).balance; | ||||
|     } | ||||
|     function update(uint _state) public { | ||||
|         state = _state; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // constructor(), 2 ether: 3 -> | ||||
| // state() -> 3 | ||||
| // balance() -> 2 | ||||
| // update(uint256): 4 | ||||
| // state() -> 4 | ||||
							
								
								
									
										10
									
								
								test/libsolidity/semanticTests/smoke/failure.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								test/libsolidity/semanticTests/smoke/failure.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| contract C { | ||||
|     function e() public { | ||||
|         revert("Transaction failed."); | ||||
|     } | ||||
| } | ||||
| // ==== | ||||
| // EVMVersion: >homestead | ||||
| // ---- | ||||
| // _() -> FAILURE | ||||
| // e() -> FAILURE, hex"08c379a0", 0x20, 19, "Transaction failed." | ||||
| @ -11,3 +11,4 @@ contract C { | ||||
| // g() | ||||
| // # g() does not exist # | ||||
| // -> FAILURE | ||||
| 
 | ||||
| @ -17,3 +17,4 @@ contract C { | ||||
| // 1 | ||||
| // -> 5 | ||||
| // # Should return sum of all parameters. # | ||||
| 
 | ||||
							
								
								
									
										22
									
								
								test/libsolidity/semanticTests/smoke/structs.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								test/libsolidity/semanticTests/smoke/structs.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| contract C { | ||||
|     struct S { | ||||
|         uint a; | ||||
|         uint b; | ||||
|     } | ||||
|     struct T { | ||||
|         uint a; | ||||
|         uint b; | ||||
|         string s; | ||||
|     } | ||||
|     function s() public returns (S memory) { | ||||
|         return S(23, 42); | ||||
|     } | ||||
|     function t() public returns (T memory) { | ||||
|         return T(23, 42, "any"); | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // s() -> 23, 42 | ||||
| // t() -> 0x20, 23, 42, 0x60, 3, "any" | ||||
| @ -1,121 +0,0 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| contract C { | ||||
|     struct S { | ||||
|         uint a; | ||||
|         uint b; | ||||
|     } | ||||
|     struct T { | ||||
|         uint a; | ||||
|         uint b; | ||||
|         string s; | ||||
|     } | ||||
|     uint public state = 0; | ||||
|     bool[2][] flags; | ||||
|     constructor(uint _state) public payable { | ||||
|         state = _state; | ||||
|     } | ||||
|     function balance() payable public returns (uint256) { | ||||
|         return address(this).balance; | ||||
|     } | ||||
|     function e(uint a) public { | ||||
|         state = a; | ||||
|     } | ||||
|     function f() payable public returns (uint) { | ||||
|         return 2; | ||||
|     } | ||||
|     function f(uint a) public returns (uint, uint) { | ||||
|         return (a, a); | ||||
|     } | ||||
|     function g() public returns (uint, uint) { | ||||
|         return (2, 3); | ||||
|     } | ||||
|     function h(uint x, uint y) public returns (uint) { | ||||
|         return x - y; | ||||
|     } | ||||
|     function j(bool b) public returns (bool) { | ||||
|         return !b; | ||||
|     } | ||||
|     function k(bytes32 b) public returns (bytes32, bytes32) { | ||||
|         return (b, b); | ||||
|     } | ||||
|     function l() public returns (uint256) { | ||||
|         return msg.data.length; | ||||
|     } | ||||
|     function m(bytes memory b) public returns (bytes memory) { | ||||
|         return b; | ||||
|     } | ||||
|     function n() public returns (string memory) { | ||||
|         return "any"; | ||||
|     } | ||||
|     function o() public returns (string memory, string memory) { | ||||
|         return ("any", "any"); | ||||
|     } | ||||
|     function p() public returns (string memory, uint, string memory) { | ||||
|         return ("any", 42, "any"); | ||||
|     } | ||||
|     function q(uint a) public returns (uint d) { | ||||
|         return a * 7; | ||||
|     } | ||||
|     function r() public returns (bool[3] memory) { | ||||
|         return [true, false, true]; | ||||
|     } | ||||
|     function s() public returns (uint[2] memory, uint) { | ||||
|         return ([uint(123), 456], 789); | ||||
|     } | ||||
|     function t1() public returns (S memory) { | ||||
|         return S(23, 42); | ||||
|     } | ||||
|     function t2() public returns (T memory) { | ||||
|         return T(23, 42, "any"); | ||||
|     } | ||||
|     function u() public returns (T[2] memory) { | ||||
|         return [T(23, 42, "any"), T(555, 666, "any")]; | ||||
|     } | ||||
|     function v() public returns (bool[2][] memory) { | ||||
|         return flags; | ||||
|     } | ||||
|     function w1() public returns (string[1] memory) { | ||||
|         return ["any"]; | ||||
|     } | ||||
|     function w2() public returns (string[2] memory) { | ||||
|         return ["any", "any"]; | ||||
|     } | ||||
|     function w3() public returns (string[3] memory) { | ||||
|         return ["any", "any", "any"]; | ||||
|     } | ||||
|     function x() public returns (string[2] memory, string[3] memory) { | ||||
|         return (["any", "any"], ["any", "any", "any"]); | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // constructor(), 2 ether: 3 -> | ||||
| // state() -> 3 | ||||
| // balance() -> 2 | ||||
| // _() -> FAILURE | ||||
| // e(uint256): 4 | ||||
| // f() -> 2 | ||||
| // f(uint256): 3 -> 3, 3 | ||||
| // f(), 1 ether -> 2 | ||||
| // g() -> 2, 3 | ||||
| // g1() -> FAILURE | ||||
| // h(uint256,uint256): 1, -2 -> 3 | ||||
| // j(bool): true -> false | ||||
| // k(bytes32): 0x10001 -> 0x10001, 0x10001 | ||||
| // l(): hex"4200efef" -> 8 | ||||
| // m(bytes): 32, 32, 0x20 -> 32, 32, 0x20 | ||||
| // m(bytes): 32, 3, hex"AB33BB" -> 32, 3, left(0xAB33BB) | ||||
| // m(bytes): 32, 3, hex"AB33FF" -> 32, 3, hex"ab33ff0000000000000000000000000000000000000000000000000000000000" | ||||
| // n() -> 0x20, 3, "any" | ||||
| // o() -> 0x40, 0x80, 3, "any", 3, "any" | ||||
| // p() -> 0x60, 0x2a, 0xa0, 3, "any", 3, "any" | ||||
| // q(uint256): 99 -> 693 | ||||
| // r() -> true, false, true | ||||
| // s() -> 123, 456, 789 | ||||
| // t1() -> 23, 42 | ||||
| // t2() -> 0x20, 23, 42, 0x60, 3, "any" | ||||
| // v() -> 32, 0 | ||||
| // w1() -> 0x20, 0x20, 3, "any" | ||||
| // w2() -> 0x20, 0x40, 0x80, 3, "any", 3, "any" | ||||
| // w3() -> 0x20, 0x60, 0xa0, 0xe0, 3, "any", 3, "any", 3, "any" | ||||
| // x() -> 0x40, 0x0100, 0x40, 0x80, 3, "any", 3, "any", 0x60, 0xa0, 0xe0, 3, "any", 3, "any", 3, "any" | ||||
| @ -0,0 +1,9 @@ | ||||
| contract C { | ||||
|     function f(uint256 x) public pure returns (uint256, uint256) { | ||||
|         uint256 b = x; | ||||
|         x = 42; | ||||
|         return (x, b); | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // f(uint256): 23 -> 42, 23 | ||||
							
								
								
									
										7
									
								
								test/libsolidity/syntaxTests/array/calldata_assign.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/libsolidity/syntaxTests/array/calldata_assign.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| contract Test { | ||||
|     function f(uint256[] calldata s) external { s[0] = 4; } | ||||
| } | ||||
| // ---- | ||||
| // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. | ||||
| // TypeError: (98-102): Calldata arrays are read-only. | ||||
							
								
								
									
										7
									
								
								test/libsolidity/syntaxTests/array/calldata_resize.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/libsolidity/syntaxTests/array/calldata_resize.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| contract C { | ||||
|     function f (uint256[] calldata x) external pure { | ||||
|         x.length = 42; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // TypeError: (75-83): Calldata arrays cannot be resized. | ||||
| @ -0,0 +1,7 @@ | ||||
| contract C { | ||||
|     function f(uint256[] calldata x) external pure { | ||||
|         x[0] = 42; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // TypeError: (74-78): Calldata arrays are read-only. | ||||
| @ -0,0 +1,10 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| contract C { | ||||
|     struct S { uint256 x; } | ||||
|     function f(S calldata s) external pure { | ||||
|         s.x = 42; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. | ||||
| // TypeError: (128-131): Calldata structs are read-only. | ||||
| @ -0,0 +1,7 @@ | ||||
| contract C { | ||||
|     function f(uint256[] calldata x, uint256[] calldata y) external pure { | ||||
|         x = y; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // TypeError: (96-97): External function arguments of reference type are read-only. | ||||
							
								
								
									
										15
									
								
								test/libsolidity/syntaxTests/lvalues/functions.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								test/libsolidity/syntaxTests/lvalues/functions.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| contract C { | ||||
|     function f() internal { | ||||
|     } | ||||
|     function g() internal { | ||||
|         g = f; | ||||
|     } | ||||
|     function h() external { | ||||
|     } | ||||
|     function i() external { | ||||
|         this.i = this.h; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // TypeError: (83-84): Expression has to be an lvalue. | ||||
| // TypeError: (166-172): Expression has to be an lvalue. | ||||
							
								
								
									
										7
									
								
								test/libsolidity/syntaxTests/lvalues/library_mapping.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/libsolidity/syntaxTests/lvalues/library_mapping.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| library L { | ||||
|     function f(mapping(uint=>uint) storage x, mapping(uint=>uint) storage y) external { | ||||
|         x = y; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // TypeError: (108-109): Mappings cannot be assigned to. | ||||
							
								
								
									
										31
									
								
								test/libsolidity/syntaxTests/lvalues/valid_lvalues.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								test/libsolidity/syntaxTests/lvalues/valid_lvalues.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| contract C { | ||||
|     struct S { uint256 x; } | ||||
| 	function i() internal pure {} | ||||
| 	function e() external pure {} | ||||
| 	uint[] s1; | ||||
|     function f(uint x, bytes32 y) external { | ||||
|         x = 42; | ||||
|         y = bytes32(0); | ||||
|         (x, y) = (23, bytes32(0)); | ||||
|         S memory ms1; | ||||
|         S memory ms2; | ||||
|         ms1 = ms2; | ||||
|         ms1.x = x; | ||||
|         uint256[] memory a = new uint256[](2); | ||||
|         uint256[] memory b = new uint256[](3); | ||||
|         a = b; | ||||
|         a[0] = x; | ||||
|         s1[0] = x; | ||||
|         s1 = a; | ||||
|     } | ||||
|     function g(function() internal pure x) internal view { | ||||
|         x = i; | ||||
|         function(uint, bytes32) external y; | ||||
|         y = this.f; | ||||
|     } | ||||
|     function g(function() external pure x) external view { | ||||
|         x = this.e; | ||||
|         function(function() internal pure) internal view y; | ||||
|         y = g; | ||||
|     } | ||||
| } | ||||
| @ -1,5 +1,4 @@ | ||||
| contract c { | ||||
|     function f(uint a) external { a = 1; } | ||||
|     function f(uint a) external pure { a = 1; } | ||||
| } | ||||
| // ---- | ||||
| // TypeError: (47-48): Expression has to be an lvalue. | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| contract c { | ||||
|     function f(uint a) external { a++; } | ||||
|     function f(uint a) external pure { a++; } | ||||
| } | ||||
| // ---- | ||||
| // TypeError: (47-48): Expression has to be an lvalue. | ||||
|  | ||||
| @ -2,4 +2,4 @@ contract c { | ||||
|     function f(uint a) external { delete a; } | ||||
| } | ||||
| // ---- | ||||
| // TypeError: (54-55): Expression has to be an lvalue. | ||||
| // Warning: (17-58): Function state mutability can be restricted to pure | ||||
|  | ||||
| @ -5,4 +5,4 @@ contract C { | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // TypeError: (72-80): Expression has to be an lvalue. | ||||
| // TypeError: (72-80): Memory arrays cannot be resized. | ||||
|  | ||||
| @ -7,4 +7,4 @@ contract Test { | ||||
| } | ||||
| // ---- | ||||
| // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. | ||||
| // TypeError: (144-147): Expression has to be an lvalue. | ||||
| // TypeError: (144-147): Calldata structs are read-only. | ||||
|  | ||||
| @ -5,4 +5,4 @@ contract Test { | ||||
| } | ||||
| // ---- | ||||
| // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. | ||||
| // TypeError: (114-117): Expression has to be an lvalue. | ||||
| // TypeError: (114-117): Calldata structs are read-only. | ||||
|  | ||||
| @ -6,7 +6,7 @@ contract Test { | ||||
| } | ||||
| // ---- | ||||
| // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. | ||||
| // TypeError: (114-115): Expression has to be an lvalue. | ||||
| // TypeError: (114-115): External function arguments of reference type are read-only. | ||||
| // TypeError: (118-122): Type struct Test.S memory is not implicitly convertible to expected type struct Test.S calldata. | ||||
| // TypeError: (178-179): Expression has to be an lvalue. | ||||
| // TypeError: (178-179): External function arguments of reference type are read-only. | ||||
| // TypeError: (182-183): Type struct Test.S memory is not implicitly convertible to expected type struct Test.S calldata. | ||||
|  | ||||
| @ -0,0 +1,8 @@ | ||||
| contract C { | ||||
|     function f() public pure { | ||||
|         bytes32 x; | ||||
|         x[0] = 0x42; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // TypeError: (71-75): Single bytes in fixed bytes arrays cannot be modified. | ||||
| @ -17,6 +17,7 @@ | ||||
| 
 | ||||
| #include <test/libsolidity/util/BytesUtils.h> | ||||
| 
 | ||||
| #include <test/libsolidity/util/ContractABIUtils.h> | ||||
| #include <test/libsolidity/util/SoltestErrors.h> | ||||
| 
 | ||||
| #include <liblangutil/Common.h> | ||||
| @ -202,22 +203,25 @@ string BytesUtils::formatString(bytes const& _bytes, size_t _cutOff) | ||||
| 	return os.str(); | ||||
| } | ||||
| 
 | ||||
| string BytesUtils::formatRawBytes(bytes const& _bytes) | ||||
| string BytesUtils::formatRawBytes( | ||||
| 	bytes const& _bytes, | ||||
| 	dev::solidity::test::ParameterList const& _parameters, | ||||
| 	string _linePrefix) | ||||
| { | ||||
| 	if (_bytes.empty()) | ||||
| 		return "[]"; | ||||
| 	soltestAssert(_bytes.size() == ContractABIUtils::encodingSize(_parameters), ""); | ||||
| 
 | ||||
| 	stringstream os; | ||||
| 	auto it = _bytes.begin(); | ||||
| 	for (size_t i = 0; i < _bytes.size(); i += 32) | ||||
| 
 | ||||
| 	for (auto const& parameter: _parameters) | ||||
| 	{ | ||||
| 		bytes byteRange{it, it + 32}; | ||||
| 		bytes byteRange{it, it + static_cast<long>(parameter.abiType.size)}; | ||||
| 
 | ||||
| 		os << "  " << byteRange; | ||||
| 
 | ||||
| 		it += 32; | ||||
| 		if (it != _bytes.end()) | ||||
| 		os << _linePrefix << byteRange; | ||||
| 		if (¶meter != &_parameters.back()) | ||||
| 			os << endl; | ||||
| 
 | ||||
| 		it += static_cast<long>(parameter.abiType.size); | ||||
| 	} | ||||
| 
 | ||||
| 	return os.str(); | ||||
| @ -271,6 +275,8 @@ string BytesUtils::formatBytesRange( | ||||
| 	bool _highlight | ||||
| ) | ||||
| { | ||||
| 	soltestAssert(_bytes.size() == ContractABIUtils::encodingSize(_parameters), ""); | ||||
| 
 | ||||
| 	stringstream os; | ||||
| 	auto it = _bytes.begin(); | ||||
| 
 | ||||
| @ -287,11 +293,12 @@ string BytesUtils::formatBytesRange( | ||||
| 		else | ||||
| 			os << parameter.rawString; | ||||
| 
 | ||||
| 
 | ||||
| 		it += static_cast<long>(parameter.abiType.size); | ||||
| 		if (¶meter != &_parameters.back()) | ||||
| 			os << ", "; | ||||
| 
 | ||||
| 		it += static_cast<long>(parameter.abiType.size); | ||||
| 	} | ||||
| 
 | ||||
| 	return os.str(); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -101,10 +101,14 @@ public: | ||||
| 		return formatString(_bytes, _bytes.size()); | ||||
| 	} | ||||
| 
 | ||||
| 	/// Returns a string representation of given _bytes. Adds a newline
 | ||||
| 	/// every 32 bytes to increase readability.
 | ||||
| 	/// Used to print returned bytes from function calls to the commandline.
 | ||||
| 	static std::string formatRawBytes(bytes const& _bytes); | ||||
| 	/// Returns a string representation of given _bytes in ranges of 32 bytes.
 | ||||
| 	/// If _withSignature is true, the first 4 bytes will be formatted separately.
 | ||||
| 	static std::string formatRawBytes( | ||||
| 		bytes const& _bytes, | ||||
| 		ParameterList const& _parameters, | ||||
| 		std::string _linePrefix = "" | ||||
| 	); | ||||
| 
 | ||||
| 	/// Formats given _bytes with type information passed in _abiType.
 | ||||
| 	static std::string formatBytes(bytes const& _bytes, ABIType const& _abiType); | ||||
|  | ||||
| @ -289,16 +289,47 @@ dev::solidity::test::ParameterList ContractABIUtils::preferredParameters( | ||||
| { | ||||
| 	if (_targetParameters.size() != _sourceParameters.size()) | ||||
| 	{ | ||||
| 		auto sizeFold = [](size_t const _a, Parameter const& _b) { return _a + _b.abiType.size; }; | ||||
| 		size_t encodingSize = accumulate(_targetParameters.begin(), _targetParameters.end(), size_t{0}, sizeFold); | ||||
| 
 | ||||
| 		_errorReporter.warning( | ||||
| 			"Encoding does not match byte range. The call returned " + | ||||
| 			to_string(_bytes.size()) + " bytes, but " + | ||||
| 			to_string(encodingSize) + " bytes were expected." | ||||
| 			to_string(encodingSize(_targetParameters)) + " bytes were expected." | ||||
| 		); | ||||
| 		return _sourceParameters; | ||||
| 	} | ||||
| 	else | ||||
| 		return _targetParameters; | ||||
| } | ||||
| 
 | ||||
| dev::solidity::test::ParameterList ContractABIUtils::defaultParameters(size_t count) | ||||
| { | ||||
| 	ParameterList parameters; | ||||
| 
 | ||||
| 	fill_n( | ||||
| 		back_inserter(parameters), | ||||
| 		count, | ||||
| 		Parameter{bytes(), "", ABIType{ABIType::UnsignedDec}, FormatInfo{}} | ||||
| 	); | ||||
| 
 | ||||
| 	return parameters; | ||||
| } | ||||
| 
 | ||||
| dev::solidity::test::ParameterList ContractABIUtils::failureParameters() | ||||
| { | ||||
| 	ParameterList parameters; | ||||
| 
 | ||||
| 	parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::HexString, ABIType::AlignNone, 4}, FormatInfo{}}); | ||||
| 	parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::Hex}, FormatInfo{}}); | ||||
| 	parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::UnsignedDec}, FormatInfo{}}); | ||||
| 	parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::String}, FormatInfo{}}); | ||||
| 
 | ||||
| 	return parameters; | ||||
| } | ||||
| 
 | ||||
| size_t ContractABIUtils::encodingSize( | ||||
| 	dev::solidity::test::ParameterList const& _parameters | ||||
| ) | ||||
| { | ||||
| 	auto sizeFold = [](size_t const _a, Parameter const& _b) { return _a + _b.abiType.size; }; | ||||
| 
 | ||||
| 	return accumulate(_parameters.begin(), _parameters.end(), size_t{0}, sizeFold); | ||||
| } | ||||
|  | ||||
| @ -65,6 +65,18 @@ public: | ||||
| 		bytes const& _bytes | ||||
| 	); | ||||
| 
 | ||||
| 	/// Returns a list of parameters corresponding to the encoding of
 | ||||
| 	/// returned values in case of a failure.
 | ||||
| 	static ParameterList failureParameters(); | ||||
| 
 | ||||
| 	/// Returns _count parameters with their type set to ABIType::UnsignedDec
 | ||||
| 	/// and their size set to 32 bytes.
 | ||||
| 	static ParameterList defaultParameters(size_t count = 0); | ||||
| 
 | ||||
| 	/// Calculates the encoding size of given _parameters based
 | ||||
| 	/// on the size of their types.
 | ||||
| 	static size_t encodingSize(ParameterList const& _paremeters); | ||||
| 
 | ||||
| private: | ||||
| 	/// Parses and translates a single type and returns a list of
 | ||||
| 	/// internal type representations of isoltest.
 | ||||
|  | ||||
| @ -219,6 +219,23 @@ BOOST_AUTO_TEST_CASE(non_existent_call_revert) | ||||
| 	testFunctionCall(calls.at(0), Mode::MultiLine, "i_am_not_there()", true); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_revert_message) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f() -> FAILURE, hex"08c379a0", 0x20, 6, "Revert"
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall( | ||||
| 		calls.at(0), | ||||
| 		Mode::SingleLine, | ||||
| 		"f()", | ||||
| 		true, | ||||
| 		fmt::encodeArgs(), | ||||
| 		fromHex("08c379a0") + fmt::encodeDyn(string{"Revert"}) | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_expectations_empty_single_line) | ||||
| { | ||||
| 	char const* source = R"( | ||||
|  | ||||
| @ -101,7 +101,7 @@ string TestFunctionCall::format( | ||||
| 		{ | ||||
| 			bool const isFailure = m_call.expectations.failure; | ||||
| 			result = isFailure ? | ||||
| 				failure : | ||||
| 				formatFailure(_errorReporter, m_call, m_rawBytes, _renderResult, highlight) : | ||||
| 				formatRawParameters(m_call.expectations.result); | ||||
| 			if (!result.empty()) | ||||
| 				AnsiColorized(stream, highlight, {dev::formatting::RED_BACKGROUND}) << ws << result; | ||||
| @ -111,7 +111,7 @@ string TestFunctionCall::format( | ||||
| 			bytes output = m_rawBytes; | ||||
| 			bool const isFailure = m_failure; | ||||
| 			result = isFailure ? | ||||
| 				failure : | ||||
| 				formatFailure(_errorReporter, m_call, output, _renderResult, highlight) : | ||||
| 				matchesExpectation() ? | ||||
| 					formatRawParameters(m_call.expectations.result) : | ||||
| 					formatBytesParameters( | ||||
| @ -122,6 +122,29 @@ string TestFunctionCall::format( | ||||
| 						highlight | ||||
| 					); | ||||
| 
 | ||||
| 			if (!matchesExpectation()) | ||||
| 			{ | ||||
| 				boost::optional<ParameterList> abiParams; | ||||
| 
 | ||||
| 				if (isFailure && !output.empty()) | ||||
| 					abiParams = boost::make_optional(ContractABIUtils::failureParameters()); | ||||
| 				else | ||||
| 					abiParams = ContractABIUtils::parametersFromJsonOutputs( | ||||
| 						_errorReporter, | ||||
| 						m_contractABI, | ||||
| 						m_call.signature | ||||
| 					); | ||||
| 
 | ||||
| 				string bytesOutput = abiParams ? | ||||
| 					BytesUtils::formatRawBytes(output, abiParams.get(), _linePrefix) : | ||||
| 					_linePrefix + "[]"; | ||||
| 
 | ||||
| 				_errorReporter.warning( | ||||
| 					"The call to \"" + m_call.signature + "\" returned \n" + | ||||
| 					bytesOutput | ||||
| 				); | ||||
| 			} | ||||
| 
 | ||||
| 			if (isFailure) | ||||
| 				AnsiColorized(stream, highlight, {dev::formatting::RED_BACKGROUND}) << ws << result; | ||||
| 			else | ||||
| @ -155,49 +178,90 @@ string TestFunctionCall::formatBytesParameters( | ||||
| 	bytes const& _bytes, | ||||
| 	string const& _signature, | ||||
| 	dev::solidity::test::ParameterList const& _parameters, | ||||
| 	bool _highlight | ||||
| 	bool _highlight, | ||||
| 	bool _failure | ||||
| ) const | ||||
| { | ||||
| 	using ParameterList = dev::solidity::test::ParameterList; | ||||
| 
 | ||||
| 	stringstream os; | ||||
| 
 | ||||
| 	if (_bytes.empty()) | ||||
| 		return {}; | ||||
| 
 | ||||
| 	_errorReporter.warning("The call to \"" + _signature + "\" returned \n" + BytesUtils::formatRawBytes(_bytes)); | ||||
| 
 | ||||
| 	boost::optional<ParameterList> abiParams = ContractABIUtils::parametersFromJsonOutputs( | ||||
| 		_errorReporter, | ||||
| 		m_contractABI, | ||||
| 		_signature | ||||
| 	); | ||||
| 
 | ||||
| 	if (abiParams) | ||||
| 	if (_failure) | ||||
| 	{ | ||||
| 		boost::optional<ParameterList> preferredParams = ContractABIUtils::preferredParameters( | ||||
| 			_errorReporter, | ||||
| 			_parameters, | ||||
| 			abiParams.get(), | ||||
| 			_bytes | ||||
| 		os << BytesUtils::formatBytesRange( | ||||
| 			_bytes, | ||||
| 			ContractABIUtils::failureParameters(), | ||||
| 			_highlight | ||||
| 		); | ||||
| 
 | ||||
| 		if (preferredParams) | ||||
| 		{ | ||||
| 			ContractABIUtils::overwriteParameters(_errorReporter, preferredParams.get(), abiParams.get()); | ||||
| 			os << BytesUtils::formatBytesRange(_bytes, preferredParams.get(), _highlight); | ||||
| 		} | ||||
| 		return os.str(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		ParameterList defaultParameters; | ||||
| 		fill_n( | ||||
| 			back_inserter(defaultParameters), | ||||
| 			ceil(_bytes.size() / 32), | ||||
| 			Parameter{bytes(), "", ABIType{ABIType::Hex}, FormatInfo{}} | ||||
| 		boost::optional<ParameterList> abiParams = ContractABIUtils::parametersFromJsonOutputs( | ||||
| 			_errorReporter, | ||||
| 			m_contractABI, | ||||
| 			_signature | ||||
| 		); | ||||
| 		ContractABIUtils::overwriteParameters(_errorReporter, defaultParameters, _parameters); | ||||
| 		os << BytesUtils::formatBytesRange(_bytes, defaultParameters, _highlight); | ||||
| 
 | ||||
| 		if (abiParams) | ||||
| 		{ | ||||
| 			boost::optional<ParameterList> preferredParams = ContractABIUtils::preferredParameters( | ||||
| 				_errorReporter, | ||||
| 				_parameters, | ||||
| 				abiParams.get(), | ||||
| 				_bytes | ||||
| 			); | ||||
| 
 | ||||
| 			if (preferredParams) | ||||
| 			{ | ||||
| 				ContractABIUtils::overwriteParameters(_errorReporter, preferredParams.get(), abiParams.get()); | ||||
| 				os << BytesUtils::formatBytesRange(_bytes, preferredParams.get(), _highlight); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			ParameterList defaultParameters = ContractABIUtils::defaultParameters(ceil(_bytes.size() / 32)); | ||||
| 
 | ||||
| 			ContractABIUtils::overwriteParameters(_errorReporter, defaultParameters, _parameters); | ||||
| 			os << BytesUtils::formatBytesRange(_bytes, defaultParameters, _highlight); | ||||
| 		} | ||||
| 		return os.str(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| string TestFunctionCall::formatFailure( | ||||
| 	ErrorReporter& _errorReporter, | ||||
| 	dev::solidity::test::FunctionCall const& _call, | ||||
| 	bytes const& _output, | ||||
| 	bool _renderResult, | ||||
| 	bool _highlight | ||||
| ) const | ||||
| { | ||||
| 	using Token = soltest::Token; | ||||
| 
 | ||||
| 	stringstream os; | ||||
| 
 | ||||
| 	os << formatToken(Token::Failure); | ||||
| 
 | ||||
| 	if (!_output.empty()) | ||||
| 		os << ", "; | ||||
| 
 | ||||
| 	if (_renderResult) | ||||
| 		os << formatBytesParameters( | ||||
| 			_errorReporter, | ||||
| 			_output, | ||||
| 			_call.signature, | ||||
| 			_call.expectations.result, | ||||
| 			_highlight, | ||||
| 			true | ||||
| 		); | ||||
| 	else | ||||
| 		os << formatRawParameters(_call.expectations.result); | ||||
| 
 | ||||
| 	return os.str(); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -95,7 +95,8 @@ private: | ||||
| 		bytes const& _bytes, | ||||
| 		std::string const& _signature, | ||||
| 		ParameterList const& _params, | ||||
| 		bool highlight = false | ||||
| 		bool highlight = false, | ||||
| 		bool failure = false | ||||
| 	) const; | ||||
| 
 | ||||
| 	/// Formats a given _bytes applying the _abiType.
 | ||||
| @ -104,6 +105,15 @@ private: | ||||
| 		ABIType const& _abiType | ||||
| 	) const; | ||||
| 
 | ||||
| 	/// Formats a FAILURE plus additional parameters, if e.g. a revert message was returned.
 | ||||
| 	std::string formatFailure( | ||||
| 		ErrorReporter& _errorReporter, | ||||
| 		FunctionCall const& _call, | ||||
| 		bytes const& _output, | ||||
| 		bool _renderResult, | ||||
| 		bool _highlight | ||||
| 	) const; | ||||
| 
 | ||||
| 	/// Formats the given parameters using their raw string representation.
 | ||||
| 	std::string formatRawParameters( | ||||
| 		ParameterList const& _params, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user