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)
|
### 0.5.12 (unreleased)
|
||||||
|
|
||||||
Language Features:
|
Language Features:
|
||||||
|
* Type Checker: Allow assignment to external function arguments except for reference types.
|
||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
@ -2515,8 +2515,47 @@ void TypeChecker::requireLValue(Expression const& _expression)
|
|||||||
_expression.annotation().lValueRequested = true;
|
_expression.annotation().lValueRequested = true;
|
||||||
_expression.accept(*this);
|
_expression.accept(*this);
|
||||||
|
|
||||||
if (_expression.annotation().isConstant)
|
if (_expression.annotation().isLValue)
|
||||||
m_errorReporter.typeError(_expression.location(), "Cannot assign to a constant variable.");
|
return;
|
||||||
else if (!_expression.annotation().isLValue)
|
|
||||||
m_errorReporter.typeError(_expression.location(), "Expression has to be an lvalue.");
|
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
|
bool VariableDeclaration::isLValue() const
|
||||||
{
|
{
|
||||||
// External function parameters and constant declared variables are Read-Only
|
// Constant declared variables are Read-Only
|
||||||
return !isExternalCallableParameter() && !m_isConstant;
|
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
|
bool VariableDeclaration::isLocalVariable() const
|
||||||
|
@ -26,3 +26,4 @@ contract D {
|
|||||||
// stateBytes() -> left(0x4200ef)
|
// stateBytes() -> left(0x4200ef)
|
||||||
// internalStateDecimal() -> 0x20
|
// internalStateDecimal() -> 0x20
|
||||||
// update(bool,uint256,bytes32): false, -23, left(0x2300ef) -> false, -23, left(0x2300ef)
|
// 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()
|
||||||
// # g() does not exist #
|
// # g() does not exist #
|
||||||
// -> FAILURE
|
// -> FAILURE
|
||||||
|
|
@ -17,3 +17,4 @@ contract C {
|
|||||||
// 1
|
// 1
|
||||||
// -> 5
|
// -> 5
|
||||||
// # Should return sum of all parameters. #
|
// # 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 {
|
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 {
|
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; }
|
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.
|
// 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.
|
// 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.
|
// 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: (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.
|
// 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/BytesUtils.h>
|
||||||
|
|
||||||
|
#include <test/libsolidity/util/ContractABIUtils.h>
|
||||||
#include <test/libsolidity/util/SoltestErrors.h>
|
#include <test/libsolidity/util/SoltestErrors.h>
|
||||||
|
|
||||||
#include <liblangutil/Common.h>
|
#include <liblangutil/Common.h>
|
||||||
@ -202,22 +203,25 @@ string BytesUtils::formatString(bytes const& _bytes, size_t _cutOff)
|
|||||||
return os.str();
|
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())
|
soltestAssert(_bytes.size() == ContractABIUtils::encodingSize(_parameters), "");
|
||||||
return "[]";
|
|
||||||
|
|
||||||
stringstream os;
|
stringstream os;
|
||||||
auto it = _bytes.begin();
|
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;
|
os << _linePrefix << byteRange;
|
||||||
|
if (¶meter != &_parameters.back())
|
||||||
it += 32;
|
|
||||||
if (it != _bytes.end())
|
|
||||||
os << endl;
|
os << endl;
|
||||||
|
|
||||||
|
it += static_cast<long>(parameter.abiType.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.str();
|
return os.str();
|
||||||
@ -271,6 +275,8 @@ string BytesUtils::formatBytesRange(
|
|||||||
bool _highlight
|
bool _highlight
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
soltestAssert(_bytes.size() == ContractABIUtils::encodingSize(_parameters), "");
|
||||||
|
|
||||||
stringstream os;
|
stringstream os;
|
||||||
auto it = _bytes.begin();
|
auto it = _bytes.begin();
|
||||||
|
|
||||||
@ -287,11 +293,12 @@ string BytesUtils::formatBytesRange(
|
|||||||
else
|
else
|
||||||
os << parameter.rawString;
|
os << parameter.rawString;
|
||||||
|
|
||||||
|
|
||||||
it += static_cast<long>(parameter.abiType.size);
|
|
||||||
if (¶meter != &_parameters.back())
|
if (¶meter != &_parameters.back())
|
||||||
os << ", ";
|
os << ", ";
|
||||||
|
|
||||||
|
it += static_cast<long>(parameter.abiType.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,10 +101,14 @@ public:
|
|||||||
return formatString(_bytes, _bytes.size());
|
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.
|
/// 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.
|
/// Formats given _bytes with type information passed in _abiType.
|
||||||
static std::string formatBytes(bytes const& _bytes, ABIType const& _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())
|
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(
|
_errorReporter.warning(
|
||||||
"Encoding does not match byte range. The call returned " +
|
"Encoding does not match byte range. The call returned " +
|
||||||
to_string(_bytes.size()) + " bytes, but " +
|
to_string(_bytes.size()) + " bytes, but " +
|
||||||
to_string(encodingSize) + " bytes were expected."
|
to_string(encodingSize(_targetParameters)) + " bytes were expected."
|
||||||
);
|
);
|
||||||
return _sourceParameters;
|
return _sourceParameters;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return _targetParameters;
|
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
|
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:
|
private:
|
||||||
/// Parses and translates a single type and returns a list of
|
/// Parses and translates a single type and returns a list of
|
||||||
/// internal type representations of isoltest.
|
/// 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);
|
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)
|
BOOST_AUTO_TEST_CASE(call_expectations_empty_single_line)
|
||||||
{
|
{
|
||||||
char const* source = R"(
|
char const* source = R"(
|
||||||
|
@ -101,7 +101,7 @@ string TestFunctionCall::format(
|
|||||||
{
|
{
|
||||||
bool const isFailure = m_call.expectations.failure;
|
bool const isFailure = m_call.expectations.failure;
|
||||||
result = isFailure ?
|
result = isFailure ?
|
||||||
failure :
|
formatFailure(_errorReporter, m_call, m_rawBytes, _renderResult, highlight) :
|
||||||
formatRawParameters(m_call.expectations.result);
|
formatRawParameters(m_call.expectations.result);
|
||||||
if (!result.empty())
|
if (!result.empty())
|
||||||
AnsiColorized(stream, highlight, {dev::formatting::RED_BACKGROUND}) << ws << result;
|
AnsiColorized(stream, highlight, {dev::formatting::RED_BACKGROUND}) << ws << result;
|
||||||
@ -111,7 +111,7 @@ string TestFunctionCall::format(
|
|||||||
bytes output = m_rawBytes;
|
bytes output = m_rawBytes;
|
||||||
bool const isFailure = m_failure;
|
bool const isFailure = m_failure;
|
||||||
result = isFailure ?
|
result = isFailure ?
|
||||||
failure :
|
formatFailure(_errorReporter, m_call, output, _renderResult, highlight) :
|
||||||
matchesExpectation() ?
|
matchesExpectation() ?
|
||||||
formatRawParameters(m_call.expectations.result) :
|
formatRawParameters(m_call.expectations.result) :
|
||||||
formatBytesParameters(
|
formatBytesParameters(
|
||||||
@ -122,6 +122,29 @@ string TestFunctionCall::format(
|
|||||||
highlight
|
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)
|
if (isFailure)
|
||||||
AnsiColorized(stream, highlight, {dev::formatting::RED_BACKGROUND}) << ws << result;
|
AnsiColorized(stream, highlight, {dev::formatting::RED_BACKGROUND}) << ws << result;
|
||||||
else
|
else
|
||||||
@ -155,49 +178,90 @@ string TestFunctionCall::formatBytesParameters(
|
|||||||
bytes const& _bytes,
|
bytes const& _bytes,
|
||||||
string const& _signature,
|
string const& _signature,
|
||||||
dev::solidity::test::ParameterList const& _parameters,
|
dev::solidity::test::ParameterList const& _parameters,
|
||||||
bool _highlight
|
bool _highlight,
|
||||||
|
bool _failure
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
using ParameterList = dev::solidity::test::ParameterList;
|
using ParameterList = dev::solidity::test::ParameterList;
|
||||||
|
|
||||||
stringstream os;
|
stringstream os;
|
||||||
|
|
||||||
if (_bytes.empty())
|
if (_bytes.empty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
_errorReporter.warning("The call to \"" + _signature + "\" returned \n" + BytesUtils::formatRawBytes(_bytes));
|
if (_failure)
|
||||||
|
|
||||||
boost::optional<ParameterList> abiParams = ContractABIUtils::parametersFromJsonOutputs(
|
|
||||||
_errorReporter,
|
|
||||||
m_contractABI,
|
|
||||||
_signature
|
|
||||||
);
|
|
||||||
|
|
||||||
if (abiParams)
|
|
||||||
{
|
{
|
||||||
boost::optional<ParameterList> preferredParams = ContractABIUtils::preferredParameters(
|
os << BytesUtils::formatBytesRange(
|
||||||
_errorReporter,
|
_bytes,
|
||||||
_parameters,
|
ContractABIUtils::failureParameters(),
|
||||||
abiParams.get(),
|
_highlight
|
||||||
_bytes
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (preferredParams)
|
return os.str();
|
||||||
{
|
|
||||||
ContractABIUtils::overwriteParameters(_errorReporter, preferredParams.get(), abiParams.get());
|
|
||||||
os << BytesUtils::formatBytesRange(_bytes, preferredParams.get(), _highlight);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ParameterList defaultParameters;
|
boost::optional<ParameterList> abiParams = ContractABIUtils::parametersFromJsonOutputs(
|
||||||
fill_n(
|
_errorReporter,
|
||||||
back_inserter(defaultParameters),
|
m_contractABI,
|
||||||
ceil(_bytes.size() / 32),
|
_signature
|
||||||
Parameter{bytes(), "", ABIType{ABIType::Hex}, FormatInfo{}}
|
|
||||||
);
|
);
|
||||||
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();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,8 @@ private:
|
|||||||
bytes const& _bytes,
|
bytes const& _bytes,
|
||||||
std::string const& _signature,
|
std::string const& _signature,
|
||||||
ParameterList const& _params,
|
ParameterList const& _params,
|
||||||
bool highlight = false
|
bool highlight = false,
|
||||||
|
bool failure = false
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/// Formats a given _bytes applying the _abiType.
|
/// Formats a given _bytes applying the _abiType.
|
||||||
@ -104,6 +105,15 @@ private:
|
|||||||
ABIType const& _abiType
|
ABIType const& _abiType
|
||||||
) const;
|
) 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.
|
/// Formats the given parameters using their raw string representation.
|
||||||
std::string formatRawParameters(
|
std::string formatRawParameters(
|
||||||
ParameterList const& _params,
|
ParameterList const& _params,
|
||||||
|
Loading…
Reference in New Issue
Block a user