Merge pull request #8994 from ethereum/fixInvertedBinaryOp

Fix type inversion for shift and exp operators.
This commit is contained in:
chriseth 2020-06-03 14:11:16 +02:00 committed by GitHub
commit d12db7ec52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 66 additions and 10 deletions

View File

@ -6,6 +6,7 @@ Breaking changes:
* Deprecated the identifier `now`.
* JSON AST: Removes members with ``null`` value from JSON output.
* Type Checker: Disallow shifts by signed types.
* Type Checker: Exponentiation and shifts of literals by non-literals will always use ``uint256`` or ``int256`` as a type.
Language Features:
* Yul: Disallow EVM instruction `pc()`.

View File

@ -444,6 +444,11 @@ long as the operands are integers. If any of the two is fractional, bit operatio
and exponentiation is disallowed if the exponent is fractional (because that might result in
a non-rational number).
Shifts and exponentiation with literal numbers as left (or base) operand and integer types
as the right (exponent) operand are always performed
in the ``uint256`` (for non-negative literals) or ``int256`` (for a negative literals) type,
regardless of the type of the right (exponent) operand.
.. warning::
Division on integer literals used to truncate in Solidity prior to version 0.4.0, but it now converts into a rational number, i.e. ``5 / 2`` is not equal to ``2``, but to ``2.5``.

View File

@ -96,6 +96,7 @@ public:
static IntegerType const* uint(unsigned _bits) { return integer(_bits, IntegerType::Modifier::Unsigned); }
static IntegerType const* uint256() { return uint(256); }
static IntegerType const* int256() { return integer(256, IntegerType::Modifier::Signed); }
static FixedPointType const* fixedPoint(unsigned m, unsigned n, FixedPointType::Modifier _modifier);

View File

@ -965,10 +965,38 @@ TypeResult RationalNumberType::binaryOperatorResult(Token _operator, Type const*
{
if (_other->category() == Category::Integer || _other->category() == Category::FixedPoint)
{
auto commonType = Type::commonType(this, _other);
if (!commonType)
return nullptr;
return commonType->binaryOperatorResult(_operator, _other);
if (isFractional())
return TypeResult::err("Fractional literals not supported.");
else if (!integerType())
return TypeResult::err("Literal too large.");
// Shift and exp are not symmetric, so it does not make sense to swap
// the types as below. As an exception, we always use uint here.
if (TokenTraits::isShiftOp(_operator))
{
if (!isValidShiftAndAmountType(_operator, *_other))
return nullptr;
return isNegative() ? TypeProvider::int256() : TypeProvider::uint256();
}
else if (Token::Exp == _operator)
{
if (auto const* otherIntType = dynamic_cast<IntegerType const*>(_other))
{
if (otherIntType->isSigned())
return TypeResult::err("Exponentiation power is not allowed to be a signed integer type.");
}
else if (dynamic_cast<FixedPointType const*>(_other))
return TypeResult::err("Exponent is fractional.");
return isNegative() ? TypeProvider::int256() : TypeProvider::uint256();
}
else
{
auto commonType = Type::commonType(this, _other);
if (!commonType)
return nullptr;
return commonType->binaryOperatorResult(_operator, _other);
}
}
else if (_other->category() != category())
return nullptr;

View File

@ -1,5 +1,5 @@
contract C {
function f() public pure returns (uint8 x) {
function f() public pure returns (uint x) {
uint8 y = uint8(2)**uint8(8);
return 0**y;
}

View File

@ -0,0 +1,16 @@
contract test {
function f(uint x) public pure returns (uint, int) {
uint a = 2 ** x;
int b = -2 ** x;
return (a, b);
}
}
// ----
// f(uint256): 0 -> 1, 1
// f(uint256): 1 -> 2, -2
// f(uint256): 2 -> 4, 4
// f(uint256): 13 -> 0x2000, -8192
// f(uint256): 113 -> 0x020000000000000000000000000000, -10384593717069655257060992658440192
// f(uint256): 114 -> 0x040000000000000000000000000000, 20769187434139310514121985316880384
// f(uint256): 1113 -> 0x00, 0
// f(uint256): 1114 -> 0x00, 0

View File

@ -5,4 +5,3 @@ contract test {
}
}
// ----
// Warning: (99-104): Result of exponentiation has type uint8 and thus might overflow. Silence this warning by converting the literal to the expected type.

View File

@ -5,4 +5,3 @@ contract test {
}
}
// ----
// Warning: (99-106): Result of shift has type uint8 and thus might overflow. Silence this warning by converting the literal to the expected type.

View File

@ -4,4 +4,4 @@ contract test {
}
}
// ----
// TypeError: (61-77): Operator ** not compatible with types int_const 3 and ufixed128x18
// TypeError: (61-77): Operator ** not compatible with types int_const 3 and ufixed128x18. Exponent is fractional.

View File

@ -4,4 +4,4 @@ contract test {
}
}
// ----
// TypeError: (61-78): Operator ** not compatible with types int_const 42 and fixed128x18
// TypeError: (61-78): Operator ** not compatible with types int_const 42 and fixed128x18. Exponent is fractional.

View File

@ -0,0 +1,7 @@
contract test {
function f() pure public returns(uint) {
uint x = 100;
return 10 << x;
}
}
// ----

View File

@ -7,4 +7,4 @@ contract test {
}
}
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// TypeError: (117-123): Operator % not compatible with types rational_const 1 / 2 and fixed128x18. Fractional literals not supported.