diff options
-rw-r--r-- | libsolidity/ast/Types.cpp | 47 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 15 |
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"( |