diff --git a/Changelog.md b/Changelog.md index d6ae4df67..3c64cbc16 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Breaking changes: * General: Disallow explicit conversions from external function types to ``address`` and add a member called ``address`` to them as replacement. + * Type checker: Resulting type of exponentiation is equal to the type of the base. Also allow signed types for the base. Language Features: diff --git a/docs/060-breaking-changes.rst b/docs/060-breaking-changes.rst index c6dd41124..6c80cc2a7 100644 --- a/docs/060-breaking-changes.rst +++ b/docs/060-breaking-changes.rst @@ -29,6 +29,10 @@ Semantic and Syntactic Changes This section highlights changes that affect syntax and semantics. +* The resulting type of an exponentiation is the type of the base. It used to be the smallest type + that can hold both the type of the base and the type of the exponent, as with symmentric + operations. Additionally, signed types are allowed for the base of the exponetation. + How to update your code ======================= diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 5f7337aaf..d03a4c55f 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -123,8 +123,9 @@ results in the same sign as its left operand (or zero) and ``a % n == -(abs(a) % Exponentiation ^^^^^^^^^^^^^^ -Exponentiation is only available for unsigned types. Please take care that the types -you are using are large enough to hold the result and prepare for potential wrapping behaviour. +Exponentiation is only available for unsigned types in the exponent. The resulting type +of an exponentiation is always equal to the type of the base. Please take care that it is +large enough to hold the result and prepare for potential wrapping behaviour. .. note:: Note that ``0**0`` is defined by the EVM as ``1``. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 553aa0dfb..e0f833493 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1397,6 +1397,23 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) "might overflow. Silence this warning by converting the literal to the " "expected type." ); + if ( + commonType->category() == Type::Category::Integer && + rightType->category() == Type::Category::Integer && + dynamic_cast(*commonType).numBits() < + dynamic_cast(*rightType).numBits() + ) + m_errorReporter.warning( + _operation.location(), + "The result type of the " + + operation + + " operation is equal to the type of the first operand (" + + commonType->toString() + + ") ignoring the (larger) type of the second operand (" + + rightType->toString() + + ") which might be unexpected. Silence this warning by either converting " + "the first or the second operand to the type of the other." + ); } } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 244cfce57..30323c316 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -600,6 +600,17 @@ TypeResult IntegerType::binaryOperatorResult(Token _operator, Type const* _other else return nullptr; } + else if (Token::Exp == _operator) + { + if (auto 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 nullptr; + return this; + } auto commonType = Type::commonType(this, _other); //might be an integer or fixed point if (!commonType) @@ -610,14 +621,6 @@ TypeResult IntegerType::binaryOperatorResult(Token _operator, Type const* _other return commonType; if (TokenTraits::isBooleanOp(_operator)) return nullptr; - if (auto intType = dynamic_cast(commonType)) - { - if (Token::Exp == _operator && intType->isSigned()) - return TypeResult::err("Exponentiation is not allowed for signed integer types."); - } - else if (dynamic_cast(commonType)) - if (Token::Exp == _operator) - return nullptr; return commonType; } diff --git a/test/libsolidity/semanticTests/exponentiation/signed_base.sol b/test/libsolidity/semanticTests/exponentiation/signed_base.sol new file mode 100644 index 000000000..f58c08129 --- /dev/null +++ b/test/libsolidity/semanticTests/exponentiation/signed_base.sol @@ -0,0 +1,14 @@ +contract test { + function f() public pure returns (int, int) { + int32 x = -3; + uint8 y1; + uint8 y2; + assembly { + y1 := 0x102 + y2 := 0x103 + } + return (x**y1, x**y2); + } +} +// ---- +// f() -> 9, -27 diff --git a/test/libsolidity/semanticTests/exponentiation/small_exp.sol b/test/libsolidity/semanticTests/exponentiation/small_exp.sol new file mode 100644 index 000000000..9dfb5599b --- /dev/null +++ b/test/libsolidity/semanticTests/exponentiation/small_exp.sol @@ -0,0 +1,13 @@ +contract test { + function f() public pure returns (uint) { + uint32 x; + uint8 y; + assembly { + x := 0xfffffffffe + y := 0x102 + } + return x**y; + } +} +// ---- +// f() -> 4 diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/199_integer_unsigned_exp_signed.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/199_integer_unsigned_exp_signed.sol index fbeadfb66..9ef74bd8e 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/199_integer_unsigned_exp_signed.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/199_integer_unsigned_exp_signed.sol @@ -1,3 +1,3 @@ contract test { function() external { uint x = 3; int y = -4; x ** y; } } // ---- -// TypeError: (62-68): Operator ** not compatible with types uint256 and int256 +// TypeError: (62-68): Operator ** not compatible with types uint256 and int256. Exponentiation power is not allowed to be a signed integer type. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/200_integer_signed_exp_unsigned.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/200_integer_signed_exp_unsigned.sol index 75e920854..f21e1e86d 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/200_integer_signed_exp_unsigned.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/200_integer_signed_exp_unsigned.sol @@ -1,3 +1,5 @@ -contract test { function() external { uint x = 3; int y = -4; y ** x; } } -// ---- -// TypeError: (62-68): Operator ** not compatible with types int256 and uint256 +contract test { + function() external { uint x = 3; int y = -4; y ** x; } + function f() public pure { int16 x = 3; uint8 y = 4; x ** y; } + function g() public pure { int16 x = 3; uint16 y = 4; x ** y; } +} diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/201_integer_signed_exp_signed.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/201_integer_signed_exp_signed.sol index 9d2951b8b..73580e599 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/201_integer_signed_exp_signed.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/201_integer_signed_exp_signed.sol @@ -1,9 +1,8 @@ contract test { function f() public { int x = 3; int y = 4; x ** y; } - function g() public { int16 x = 3; uint8 y = 4; x ** y; } function h() public { uint8 x = 3; int16 y = 4; x ** y; } } // ---- -// TypeError: (64-70): Operator ** not compatible with types int256 and int256. Exponentiation is not allowed for signed integer types. -// TypeError: (126-132): Operator ** not compatible with types int16 and uint8. Exponentiation is not allowed for signed integer types. -// TypeError: (188-194): Operator ** not compatible with types uint8 and int16. Exponentiation is not allowed for signed integer types. +// TypeError: (64-70): Operator ** not compatible with types int256 and int256. Exponentiation power is not allowed to be a signed integer type. +// TypeError: (126-132): Operator ** not compatible with types uint8 and int16. Exponentiation power is not allowed to be a signed integer type. +// Warning: (126-132): The result type of the exponentiation operation is equal to the type of the first operand (uint8) ignoring the (larger) type of the second operand (int16) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.