diff --git a/Changelog.md b/Changelog.md index 409569a9d..c97020695 100644 --- a/Changelog.md +++ b/Changelog.md @@ -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: diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 5d7adc7ca..16c371c18 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -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``. diff --git a/libsolidity/ast/TypeProvider.h b/libsolidity/ast/TypeProvider.h index 38f2642eb..40cc4d384 100644 --- a/libsolidity/ast/TypeProvider.h +++ b/libsolidity/ast/TypeProvider.h @@ -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); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index f429bcf6f..e282f967b 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -967,10 +967,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(_other)) + { + if (otherIntType->isSigned()) + return TypeResult::err("Exponentiation power is not allowed to be a signed integer type."); + } + else if (dynamic_cast(_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; diff --git a/test/libsolidity/semanticTests/cleanup/exp_cleanup.sol b/test/libsolidity/semanticTests/cleanup/exp_cleanup.sol index a81e2755e..e6bd08b8f 100644 --- a/test/libsolidity/semanticTests/cleanup/exp_cleanup.sol +++ b/test/libsolidity/semanticTests/cleanup/exp_cleanup.sol @@ -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; } diff --git a/test/libsolidity/semanticTests/exponentiation/literal_base.sol b/test/libsolidity/semanticTests/exponentiation/literal_base.sol new file mode 100644 index 000000000..2c11519d0 --- /dev/null +++ b/test/libsolidity/semanticTests/exponentiation/literal_base.sol @@ -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 diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/113_exp_warn_literal_base_1.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/113_exp_warn_literal_base_1.sol index 0d91fcab1..e80497460 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/113_exp_warn_literal_base_1.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/113_exp_warn_literal_base_1.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/116_shift_warn_literal_base_1.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/116_shift_warn_literal_base_1.sol index c6a4052ec..9de53237d 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/116_shift_warn_literal_base_1.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/116_shift_warn_literal_base_1.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/333_fixed_point_casting_exponents_15.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/333_fixed_point_casting_exponents_15.sol index 0fd5f331f..91454ff24 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/333_fixed_point_casting_exponents_15.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/333_fixed_point_casting_exponents_15.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/334_fixed_point_casting_exponents_neg.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/334_fixed_point_casting_exponents_neg.sol index 03d10f7c0..57dc845f4 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/334_fixed_point_casting_exponents_neg.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/334_fixed_point_casting_exponents_neg.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/shift_warn_literal_large_shift_amount.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/shift_warn_literal_large_shift_amount.sol new file mode 100644 index 000000000..7ba9bf3db --- /dev/null +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/shift_warn_literal_large_shift_amount.sol @@ -0,0 +1,7 @@ +contract test { + function f() pure public returns(uint) { + uint x = 100; + return 10 << x; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/signed_rational_modulus.sol b/test/libsolidity/syntaxTests/signed_rational_modulus.sol index d01d2fabf..f7f5cf138 100644 --- a/test/libsolidity/syntaxTests/signed_rational_modulus.sol +++ b/test/libsolidity/syntaxTests/signed_rational_modulus.sol @@ -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.