aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsolidity/ast/Types.cpp47
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp15
2 files changed, 57 insertions, 5 deletions
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 6b4dd432..896d51fa 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -340,6 +340,28 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
_other->category() != category()
)
return TypePointer();
+ if (Token::isShiftOp(_operator))
+ {
+ // Disable >>> here.
+ if (_operator == Token::SHR)
+ return TypePointer();
+
+ // Shifts are not symmetric with respect to the type
+ if (isAddress())
+ return TypePointer();
+ if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(_other.get()))
+ {
+ if (!otherInt->isAddress())
+ return shared_from_this();
+ }
+ else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(_other.get()))
+ {
+ if (!otherRat->isFractional())
+ return shared_from_this();
+ }
+ return TypePointer();
+ }
+
auto commonType = Type::commonType(shared_from_this(), _other); //might be a integer or fixed point
if (!commonType)
return TypePointer();
@@ -347,11 +369,6 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
// All integer types can be compared
if (Token::isCompareOp(_operator))
return commonType;
- // Disable >>> here.
- if (_operator == Token::SHR)
- return TypePointer();
- if (Token::isShiftOp(_operator) && !isAddress()) // && !_other->isAddress())
- return shared_from_this();
if (Token::isBooleanOp(_operator))
return TypePointer();
if (auto intType = dynamic_pointer_cast<IntegerType const>(commonType))
@@ -959,6 +976,26 @@ TypePointer FixedBytesType::unaryOperatorResult(Token::Value _operator) const
TypePointer FixedBytesType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
{
+ if (Token::isShiftOp(_operator))
+ {
+ // Disable >>> here.
+ if (_operator == Token::SHR)
+ return TypePointer();
+
+ // Shifts are not symmetric with respect to the type
+ if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(_other.get()))
+ {
+ if (!otherInt->isAddress())
+ return shared_from_this();
+ }
+ else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(_other.get()))
+ {
+ if (!otherRat->isFractional())
+ return shared_from_this();
+ }
+ return TypePointer();
+ }
+
auto commonType = dynamic_pointer_cast<FixedBytesType const>(Type::commonType(shared_from_this(), _other));
if (!commonType)
return TypePointer();
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 837caa2d..0ac88a81 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -8505,6 +8505,21 @@ BOOST_AUTO_TEST_CASE(shift_left_uint8)
BOOST_CHECK(callContractFunction("f(uint8,uint8)", u256(0x66), u256(8)) == encodeArgs(u256(0)));
}
+BOOST_AUTO_TEST_CASE(shift_left_larger_type)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f() returns (int8) {
+ uint8 x = 255;
+ int8 y = 1;
+ return a << b;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1) << 255));
+}
+
BOOST_AUTO_TEST_CASE(shift_left_assignment)
{
char const* sourceCode = R"(