Tests/Docs after stricter explicit conversion.

This commit is contained in:
hrkrshnn 2020-11-09 10:12:38 +01:00 committed by chriseth
parent 92ab32e532
commit 40244c5469
25 changed files with 183 additions and 64 deletions

View File

@ -16,6 +16,7 @@ Breaking Changes:
* Code Generator: Use ``revert`` with error signature ``Panic(uint256)`` and error codes instead of invalid opcode on failing assertions.
* Type System: Explicit conversions from literals to integer type is as strict as implicit conversions.
* Type System: Explicit conversions from literals to enums are only allowed if the value fits in the enum.
* Type System: Explicit conversions between two types are disallowed if it changes more than one of sign, width or kind.
* Type System: Declarations with the name ``this``, ``super`` and ``_`` are disallowed, with the exception of public functions and events.
* Type System: Disallow ``type(super)``.
* Command Line Interface: JSON fields `abi`, `devdoc`, `userdoc` and `storage-layout` are now sub-objects rather than strings.

View File

@ -49,6 +49,26 @@ New Restrictions
3. Explicit conversions between literals and enums are only allowed if the literal can
represent a value in the enum.
* There are new restrictions on explicit conversions between two different types. The conversion is
only allowed when there is at most one change in sign, width or 'kind' / different type (``int``,
``address``, ``bytesNN``, etc.) For example, the conversion ``uint16(int8)`` is disallowed since
the conversion changes width (8 bits to 16 bits) and sign (signed integer to unsigned integer.) To
get the previous behaviour, use an intermediate conversion. In the previous example, this would be
``uint16(uint8(int8))`` or ``uint16(int16(int8))``. The following are some examples of conversions
that are disallowed by this rule. Note that, given types ``T`` and ``S``, the notation ``T(S)``
refers to the explicit conversion ``T(x)``, where ``x`` is any arbitrary variable of type ``S``.
- ``address(uint)`` and ``uint(address)``: converting both 'kind' and width. Replace this by
``address(uint160(uint))`` and ``uint(uint160(address))`` respectively.
- ``int80(bytes10)`` and ``bytes10(int80)``: converting both 'kind' and sign. Replace this by
``int80(uint80(bytes10))`` and ``bytes10(uint80(int80)`` respectively.
- ``Contract(uint)``: converting 'kind' and width. Replace this by
``Contract(address(uint160(uint)))``.
These conversions were disallowed since there was ambiguity in such conversions. For example, in
the expression ``uint16 x = uint16(int8(-1))``, the value of ``x`` would depend on whether the sign or
the width conversion was applied first.
* Function call options can only be given once, i.e. ``c.f{gas: 10000}{value: 1}()`` is invalid and has to be changed to ``c.f{gas: 10000, value: 1}()``.
* The global functions ``log0``, ``log1``, ``log2``, ``log3`` and ``log4`` have been removed.

View File

@ -202,7 +202,7 @@ restrictions highly readable.
{
owner = _newOwner;
// just some example condition
if (uint(owner) & 0 == 1)
if (uint160(owner) & 0 == 1)
// This did not refund for Solidity
// before version 0.4.0.
return;

View File

@ -260,7 +260,7 @@ which only need to be created if there is a dispute.
// This complicated expression just tells you how the address
// can be pre-computed. It is just there for illustration.
// You actually only need ``new D{salt: salt}(arg)``.
address predictedAddress = address(uint(keccak256(abi.encodePacked(
address predictedAddress = address(uint160(uint(keccak256(abi.encodePacked(
byte(0xff),
address(this),
salt,
@ -268,7 +268,7 @@ which only need to be created if there is a dispute.
type(D).creationCode,
arg
))
))));
)))));
D d = new D{salt: salt}(arg);
require(address(d) == predictedAddress);

View File

@ -61,7 +61,7 @@ contract ScalarEvent is Event {
convertedWinningOutcome = OUTCOME_RANGE;
// Map outcome to outcome range
else
convertedWinningOutcome = uint24(OUTCOME_RANGE * (outcome - lowerBound) / (upperBound - lowerBound));
convertedWinningOutcome = uint24(uint(OUTCOME_RANGE * (outcome - lowerBound) / (upperBound - lowerBound)));
uint factorShort = OUTCOME_RANGE - convertedWinningOutcome;
uint factorLong = OUTCOME_RANGE - factorShort;
uint shortOutcomeTokenCount = outcomeTokens[SHORT].balanceOf(msg.sender);

View File

@ -103,19 +103,19 @@ contract multiowned {
// as well as the selection of addresses capable of confirming them.
constructor(address[] memory _owners, uint _required) {
m_numOwners = _owners.length + 1;
m_owners[1] = uint(msg.sender);
m_ownerIndex[uint(msg.sender)] = 1;
m_owners[1] = uint160(msg.sender);
m_ownerIndex[uint160(msg.sender)] = 1;
for (uint i = 0; i < _owners.length; ++i)
{
m_owners[2 + i] = uint(_owners[i]);
m_ownerIndex[uint(_owners[i])] = 2 + i;
m_owners[2 + i] = uint160(_owners[i]);
m_ownerIndex[uint160(_owners[i])] = 2 + i;
}
m_required = _required;
}
// Revokes a prior confirmation of the given operation
function revoke(bytes32 _operation) external {
uint ownerIndex = m_ownerIndex[uint(msg.sender)];
uint ownerIndex = m_ownerIndex[uint160(msg.sender)];
// make sure they're an owner
if (ownerIndex == 0) return;
uint ownerIndexBit = 2**ownerIndex;
@ -130,13 +130,13 @@ contract multiowned {
// Replaces an owner `_from` with another `_to`.
function changeOwner(address _from, address _to) onlymanyowners(keccak256(msg.data)) public virtual {
if (isOwner(_to)) return;
uint ownerIndex = m_ownerIndex[uint(_from)];
uint ownerIndex = m_ownerIndex[uint160(_from)];
if (ownerIndex == 0) return;
clearPending();
m_owners[ownerIndex] = uint(_to);
m_ownerIndex[uint(_from)] = 0;
m_ownerIndex[uint(_to)] = ownerIndex;
m_owners[ownerIndex] = uint160(_to);
m_ownerIndex[uint160(_from)] = 0;
m_ownerIndex[uint160(_to)] = ownerIndex;
emit OwnerChanged(_from, _to);
}
@ -149,18 +149,18 @@ contract multiowned {
if (m_numOwners >= c_maxOwners)
return;
m_numOwners++;
m_owners[m_numOwners] = uint(_owner);
m_ownerIndex[uint(_owner)] = m_numOwners;
m_owners[m_numOwners] = uint160(_owner);
m_ownerIndex[uint160(_owner)] = m_numOwners;
emit OwnerAdded(_owner);
}
function removeOwner(address _owner) onlymanyowners(keccak256(msg.data)) external {
uint ownerIndex = m_ownerIndex[uint(_owner)];
uint ownerIndex = m_ownerIndex[uint160(_owner)];
if (ownerIndex == 0) return;
if (m_required > m_numOwners - 1) return;
m_owners[ownerIndex] = 0;
m_ownerIndex[uint(_owner)] = 0;
m_ownerIndex[uint160(_owner)] = 0;
clearPending();
reorganizeOwners(); //make sure m_numOwner is equal to the number of owners and always points to the optimal free slot
emit OwnerRemoved(_owner);
@ -174,12 +174,12 @@ contract multiowned {
}
function isOwner(address _addr) public returns (bool) {
return m_ownerIndex[uint(_addr)] > 0;
return m_ownerIndex[uint160(_addr)] > 0;
}
function hasConfirmed(bytes32 _operation, address _owner) public view returns (bool) {
PendingState storage pending = m_pending[_operation];
uint ownerIndex = m_ownerIndex[uint(_owner)];
uint ownerIndex = m_ownerIndex[uint160(_owner)];
// make sure they're an owner
if (ownerIndex == 0) return false;
@ -197,7 +197,7 @@ contract multiowned {
function confirmAndCheck(bytes32 _operation) internal returns (bool) {
// determine what index the present sender is:
uint ownerIndex = m_ownerIndex[uint(msg.sender)];
uint ownerIndex = m_ownerIndex[uint160(msg.sender)];
// make sure they're an owner
if (ownerIndex == 0) return false;

View File

@ -34,7 +34,7 @@ function colony_test
FORCE_ABIv2=false
CONFIG="truffle.js"
truffle_setup https://github.com/solidity-external-tests/colonyNetwork.git develop_070
truffle_setup https://github.com/solidity-external-tests/colonyNetwork.git develop_080
run_install install_fn
cd lib

View File

@ -33,10 +33,10 @@ function gnosis_safe_test
OPTIMIZER_LEVEL=1
CONFIG="truffle.js"
truffle_setup https://github.com/solidity-external-tests/safe-contracts.git development_070
truffle_setup https://github.com/solidity-external-tests/safe-contracts.git development_080
force_truffle_version ^5.0.42
sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_070|g' package.json
sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_080|g' package.json
rm -f package-lock.json
rm -rf node_modules/

View File

@ -33,7 +33,7 @@ function zeppelin_test
OPTIMIZER_LEVEL=1
CONFIG="truffle-config.js"
truffle_setup https://github.com/solidity-external-tests/openzeppelin-contracts.git upgrade-0.7.0
truffle_setup https://github.com/solidity-external-tests/openzeppelin-contracts.git upgrade-0.8.0
run_install install_fn
truffle_run_test compile_fn test_fn

View File

@ -162,10 +162,10 @@ BOOST_AUTO_TEST_CASE(single_callvaluecheck)
a = b;
}
function f1(address b) public pure returns (uint c) {
return uint(b) + 2;
return uint160(b) + 2;
}
function f2(address b) public pure returns (uint) {
return uint(b) + 8;
return uint160(b) + 8;
}
function f3(address, uint c) pure public returns (uint) {
return c - 5;
@ -178,10 +178,10 @@ BOOST_AUTO_TEST_CASE(single_callvaluecheck)
a = b;
}
function f1(address b) public pure returns (uint c) {
return uint(b) + 2;
return uint160(b) + 2;
}
function f2(address b) public pure returns (uint) {
return uint(b) + 8;
return uint160(b) + 8;
}
function f3(address, uint c) payable public returns (uint) {
return c - 5;

View File

@ -673,9 +673,9 @@ BOOST_AUTO_TEST_CASE(sign_extension)
contract test {
function run() public returns(uint256 y) {
unchecked {
int64 x = -int32(0xff);
int64 x = -int32(int64(0xff));
if (x >= 0xff) return 0;
return 0 - uint256(x);
return 0 - uint256(int256(x));
}
}
}
@ -5683,7 +5683,7 @@ BOOST_AUTO_TEST_CASE(dirty_scratch_space_prior_to_constant_optimiser)
return 0x0000000000001234123412431234123412412342112341234124312341234124;
}
function g(address a) internal pure returns (uint) {
unchecked { return uint(a) * 0x0000000000001234123412431234123412412342112341234124312341234124; }
unchecked { return uint(uint160(a)) * 0x0000000000001234123412431234123412412342112341234124312341234124; }
}
function h(uint a) internal pure returns (uint) {
unchecked { return a * 0x0000000000001234123412431234123412412342112341234124312341234124; }

View File

@ -437,7 +437,7 @@ BOOST_AUTO_TEST_CASE(constant_optimization_early_exit)
char const* sourceCode = R"(
contract HexEncoding {
function hexEncodeTest(address addr) public returns (bytes32 ret) {
uint x = uint(addr) / 2**32;
uint x = uint(uint160(addr)) / 2**32;
// Nibble interleave
x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;
@ -457,7 +457,7 @@ BOOST_AUTO_TEST_CASE(constant_optimization_early_exit)
assembly {
mstore(0, x)
}
x = uint(addr) * 2**96;
x = uint160(addr) * 2**96;
// Nibble interleave
x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;

View File

@ -7,7 +7,7 @@ contract c {
for (uint8 i = 0; i <= 40; i++)
data.push(byte(i+1));
for (int8 j = 40; j >= 0; j--) {
require(data[uint8(j)] == byte(j+1));
require(data[uint8(j)] == byte(uint8(j+1)));
require(data.length == uint8(j+1));
data.pop();
}

View File

@ -1,6 +1,6 @@
contract C {
function f(int16[] calldata a) external returns (bool correct) {
uint32 x = uint32(a[1]);
uint32 x = uint32(uint16(a[1]));
uint r;
assembly {
r := x

View File

@ -13,9 +13,9 @@ contract C {
b = (0 - uint8(a)) * 2;
c = a * int8(120) * int8(121);
}
x1 = uint256(a);
x1 = uint256(int256(a));
x2 = b;
x3 = uint256(c);
x3 = uint256(int256(c));
x4 = d;
}
}

View File

@ -1,8 +1,8 @@
contract Test {
function test() public returns (uint ret) { return uint(address(uint128(type(uint200).max))); }
function test() public returns (uint ret) { return uint(uint160(address(uint160(type(uint200).max)))); }
}
// ====
// compileViaYul: also
// compileToEwasm: also
// ----
// test() -> 0xffffffffffffffffffffffffffffffff
// test() -> 0xffffffffffffffffffffffffffffffffffffffff

View File

@ -4,7 +4,7 @@ contract C {
uint16[] m;
}
function f(S calldata s) public pure returns (bool correct) {
int8 x = int8(s.m[0]);
int8 x = int8(int16(s.m[0]));
uint r;
assembly {
r := x

View File

@ -4,7 +4,7 @@ contract C {
assembly {
mstore(m, 0xdeadbeef15dead)
}
int32 x = int32(m[0]);
int32 x = int32(uint32(m[0]));
uint r;
assembly {
r := x

View File

@ -21,19 +21,19 @@ contract C {
assert(x == 255);
// signed <- unsigned
int8 y = int8(type(uint16).max);
int8 y = int8(uint8(type(uint16).max));
assert(y == -1);
y = int8(uint16(100));
y = int8(uint8(uint16(100)));
assert(y == 100);
y = int8(uint16(200));
y = int8(uint8(uint16(200)));
assert(y == -56);
// unsigned <- signed
uint8 v = uint8(type(uint16).max);
assert(v == 255);
v = uint8(int16(300));
v = uint8(int8(int16(300)));
assert(v == 44);
v = uint8(int16(200));
v = uint8(int8(int16(200)));
assert(v == 200);
// fixed bytes

View File

@ -13,16 +13,16 @@ contract C {
assert(y == -(2**255) + 10);
int256 z = int256(uint(2**255 + 10));
assert(z == -(2**255) + 10);
int256 t = int256(bytes32(uint256(200)));
int256 t = int256(uint256(bytes32(uint256(200))));
assert(t == 200);
int256 v = int256(bytes32(uint256(2**255 + 10)));
int256 v = int256(uint256(bytes32(uint256(2**255 + 10))));
assert(v == -(2**255) + 10);
int160 a = int160(address(type(uint160).max));
int160 a = int160(uint160(address(type(uint160).max)));
assert(a == -1);
int160 b = int160(address(uint(2**159 + 10)));
int160 b = int160(uint160(address(uint160(uint(2**159 + 10)))));
assert(b == -(2**159) + 10);
D d;
int160 e = int160(address(d));
int160 e = int160(uint160(address(d)));
assert(e == 0);
}
@ -71,3 +71,5 @@ contract C {
}
}
// ----
// Warning 8364: (1468-1469): Assertion checker does not yet implement type type(enum E)
// Warning 8364: (1468-1469): Assertion checker does not yet implement type type(enum E)

View File

@ -9,28 +9,28 @@ contract C {
assert(x == 65535);
int8 i = int8(-1);
assert(i == -1);
x = uint16(int8(-1));
assert(x == 65535);
x = uint16(uint8(int8(-1)));
assert(x == 255);
x = uint16(int16(i));
assert(x == 65535);
uint z = uint(i);
assert(z == 2**256 - 1);
uint z = uint(uint8(i));
assert(z == 255);
}
function f2() public pure {
// signed <- unsigned
int16 y = int16(uint8(uint(65535)));
int16 y = int16(uint16(uint8(uint(65535))));
assert(y == 255);
int z = int(uint8(type(uint).max));
int z = int(uint(uint8(type(uint).max)));
assert(z == 255);
z = int(uint8(255));
z = int(uint(uint8(255)));
assert(z == 255);
}
function f3() public pure {
// signed <- signed
int16 y = int16(int8(uint(65535)));
assert(y == -1);
int16 y = int16(uint16(uint8(int8(int(uint(65535))))));
assert(y == 255);
int z = int(int8(-1));
assert(z == -1);
z = int(int8(int(255)));
@ -51,9 +51,9 @@ contract C {
assert(y == 65535);
y = uint16(uint8(type(uint16).max));
assert(y == 255);
address a = address(uint8(0));
address a = address(uint160(uint8(0)));
assert(a == address(0));
D d = D(uint8(0));
D d = D(address(uint160(uint8(0))));
assert(a == address(d));
bytes2 b1 = 0xcafe;
bytes4 b2 = bytes4(b1);
@ -67,3 +67,5 @@ contract C {
}
}
// ----
// Warning 8364: (1284-1285): Assertion checker does not yet implement type type(contract D)
// Warning 8364: (1284-1285): Assertion checker does not yet implement type type(contract D)

View File

@ -1,5 +1,5 @@
contract c {
modifier mod1(uint a) { if (msg.sender == address(a)) _; }
modifier mod1(uint a) { if (msg.sender == address(uint160(a))) _; }
modifier mod2 { if (msg.sender == address(2)) _; }
function f() public mod1(7) mod2 { }
}

View File

@ -1,5 +1,5 @@
contract C {
function f(uint x) public pure returns (address payable) {
return address(x);
return address(uint160(x));
}
}

View File

@ -0,0 +1,42 @@
contract B{}
contract C
{
function f() public pure {
uint16 a = uint16(uint8(int8(-1)));
a;
int8 b = -1;
b;
uint16 c = uint16(uint8(b));
c;
int8 d = int8(int16(uint16(type(uint16).max)));
d;
uint16 e = type(uint16).max;
e;
int8 g = int8(uint8(e));
g;
address h = address(uint160(uint(type(uint).max)));
h;
uint i = uint(uint160(address(0)));
i;
uint j = type(uint).max;
j;
address k = address(uint160(j));
k;
int80 l = int80(uint80(bytes10("h")));
l;
bytes10 m = bytes10(uint80(int80(-1)));
m;
B n = B(uint(int(100)));
n;
}
}
// ----

View File

@ -0,0 +1,52 @@
contract B{}
enum E { Zero }
contract C
{
function f() public pure {
uint16 a = uint16(int8(-1));
int8 b = -1;
uint16 c = uint16(b);
int8 d = int8(uint16(type(uint16).max));
uint16 e = type(uint16).max;
int8 g = int8(e);
address h = address(uint(type(uint).max));
uint i = uint(address(0));
uint j = type(uint).max;
address k = address(j);
int80 l = int80(bytes10("h"));
bytes10 m = bytes10(int80(-1));
B n = B(int(100));
int o = int(new B());
B p = B(0x00);
int q = int(E(0));
int r = int(E.Zero);
}
}
// ----
// TypeError 9640: (95-111): Explicit type conversion not allowed from "int8" to "uint16".
// TypeError 9640: (154-163): Explicit type conversion not allowed from "int8" to "uint16".
// TypeError 9640: (183-213): Explicit type conversion not allowed from "uint16" to "int8".
// TypeError 9640: (270-277): Explicit type conversion not allowed from "uint16" to "int8".
// TypeError 9640: (300-329): Explicit type conversion not allowed from "uint256" to "address".
// TypeError 9640: (349-365): Explicit type conversion not allowed from "address payable" to "uint256".
// TypeError 9640: (421-431): Explicit type conversion not allowed from "uint256" to "address".
// TypeError 9640: (452-471): Explicit type conversion not allowed from "bytes10" to "int80".
// TypeError 9640: (493-511): Explicit type conversion not allowed from "int80" to "bytes10".
// TypeError 9640: (528-539): Explicit type conversion not allowed from "int256" to "contract B".
// TypeError 9640: (557-569): Explicit type conversion not allowed from "contract B" to "int256".
// TypeError 9640: (586-593): Explicit type conversion not allowed from "int_const 0" to "contract B".
// TypeError 9640: (612-621): Explicit type conversion not allowed from "enum E" to "int256".
// TypeError 9640: (639-650): Explicit type conversion not allowed from "enum E" to "int256".