From 72917c4f3513a73ae180767b854de8653be9a2f4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 12 Jul 2017 15:44:27 +0200 Subject: Cleanup fixed point type changes --- libsolidity/ast/Types.cpp | 80 +++++++++++++++---------------------------- libsolidity/ast/Types.h | 16 ++++----- libsolidity/parsing/Token.cpp | 2 +- 3 files changed, 37 insertions(+), 61 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 14e948cc..bcfccc3e 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -353,12 +353,10 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const { FixedPointType const& convertTo = dynamic_cast(_convertTo); - if (((u256(1) << m_bits) <= convertTo.numBits() && convertTo.fractionalDigits() == 0) || isAddress()) + if (isAddress()) return false; - else if (isSigned()) - return convertTo.isSigned(); else - return !convertTo.isSigned() || convertTo.numBits() > m_bits; + return maxValue() <= convertTo.maxIntegerValue() && minValue() >= convertTo.minIntegerValue(); } else return false; @@ -501,7 +499,7 @@ FixedPointType::FixedPointType(int _totalBits, int _fractionalDigits, FixedPoint string FixedPointType::identifier() const { - return "t_" + string(isSigned() ? "" : "u") + "fixed" + std::to_string(numBits()) + "x" + std::to_string(fractionalDigits()); + return "t_" + string(isSigned() ? "" : "u") + "fixed" + std::to_string(m_totalBits) + "x" + std::to_string(m_fractionalDigits); } bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const @@ -512,7 +510,7 @@ bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const if (convertTo.numBits() < m_totalBits || convertTo.fractionalDigits() < m_fractionalDigits) return false; else - return convertTo.maximumPossibleInteger() >= maximumPossibleInteger(); + return convertTo.maxIntegerValue() >= maxIntegerValue() && convertTo.minIntegerValue() <= minIntegerValue(); } return false; } @@ -524,31 +522,6 @@ bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const _convertTo.category() == Category::FixedBytes; } -/*bool FixedPointType::canHoldInteger(unsigned const _bits, bool const _signed) const -{ - // If fixed type has 200 bits and 2 fractional digits, integer has 8 bits, then conversion is possible. - // Write helper function that returns max integer number, not necessarily the bits. - // 2^m_bits <= integer - - // REMINDER: The below was a work in progress until better solution thought up, see below: - // add min and max number functions to integer and fixed types, use them when converting types. - if (_signed && isSigned()) - { - u256 maxInteger = (u256(1) << _bits) - 1; - u256 maxFixedInteger = u256(((u256(1) << numBits()) - 1) / (pow(bigint(10), decimalDigits()))); - } - else if (_signed && !isSigned()) - { - - } - else - { - u256 maxInteger = (u256(1) << _bits) - 1; - u256 maxFixedInteger = u256(((u256(1) << numBits()) - 1) / (pow(bigint(10), decimalDigits()))); - return maxInteger <= maxFixedInteger; - } -}*/ - TypePointer FixedPointType::unaryOperatorResult(Token::Value _operator) const { // "delete" is ok for all fixed types @@ -580,6 +553,23 @@ string FixedPointType::toString(bool) const return prefix + dev::toString(m_totalBits) + "x" + dev::toString(m_fractionalDigits); } +bigint FixedPointType::maxIntegerValue() const +{ + bigint maxValue = (bigint(1) << (m_totalBits - (isSigned() ? 1 : 0))) - 1; + return maxValue / pow(bigint(10), m_fractionalDigits); +} + +bigint FixedPointType::minIntegerValue() const +{ + if (isSigned()) + { + bigint minValue = -(bigint(1) << (m_totalBits - (isSigned() ? 1 : 0))); + return minValue / pow(bigint(10), m_fractionalDigits); + } + else + return bigint(0); +} + TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { if ( @@ -765,16 +755,9 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const else if (_convertTo.category() == Category::FixedPoint) { if (auto fixed = fixedPointType()) - { - // We disallow implicit conversion if we would have to truncate (fixedPointType() - // can return a type that requires truncation). - rational value = m_value * boost::multiprecision::pow(bigint(10), fixed->fractionalDigits()); - cout << "value denominator: " << value.denominator() << endl; - cout << "value: " << value << endl; - return value.denominator() == 1 && fixed->isImplicitlyConvertibleTo(_convertTo); - } - cout << "could not convert to fixed type" << endl; - return false; + return fixed->isImplicitlyConvertibleTo(_convertTo); + else + return false; } else if (_convertTo.category() == Category::FixedBytes) { @@ -978,10 +961,9 @@ u256 RationalNumberType::literalValue(Literal const*) const else { auto fixed = fixedPointType(); - solAssert(!!fixed, ""); - // truncate - shiftedValue = m_value.numerator() / m_value.denominator(); - cout << "Shifted value: " << shiftedValue << endl; + solAssert(fixed, ""); + int fractionalDigits = fixed->fractionalDigits(); + shiftedValue = (m_value.numerator() / m_value.denominator()) * pow(bigint(10), fractionalDigits); } // we ignore the literal and hope that the type was correctly determined @@ -1035,14 +1017,9 @@ shared_ptr RationalNumberType::fixedPointType() const } if (value > maxValue) - { - cout << "value > maxValue" << endl; return shared_ptr(); - } - // u256(v) is the actual value that will be put on the stack - // From here on, very similar to integerType() + // This means we round towards zero for positive and negative values. bigint v = value.numerator() / value.denominator(); - cout << "Big int: " << u256(v) << endl; if (negative) // modify value to satisfy bit requirements for negative numbers: // add one bit for sign and decrement because negative numbers can be larger @@ -1054,7 +1031,6 @@ shared_ptr RationalNumberType::fixedPointType() const unsigned totalBits = max(bytesRequired(v), 1u) * 8; solAssert(totalBits <= 256, ""); - cout << "rational turned into " << (negative ? "fixed" : "ufixed") << totalBits << "x" << fractionalDigits << endl; return make_shared( totalBits, fractionalDigits, negative ? FixedPointType::Modifier::Signed : FixedPointType::Modifier::Unsigned diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index d5ef343a..3d7dad16 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -321,10 +321,6 @@ public: int numBits() const { return m_bits; } bool isAddress() const { return m_modifier == Modifier::Address; } bool isSigned() const { return m_modifier == Modifier::Signed; } - u256 maximumPossibleInteger() const { return isSigned() ? - u256((u256(1) << m_bits) - 1): - u256((u256(1) << m_bits)); - } bigint minValue() const; bigint maxValue() const; @@ -365,13 +361,17 @@ public: virtual TypePointer encodingType() const override { return shared_from_this(); } virtual TypePointer interfaceType(bool) const override { return shared_from_this(); } + /// Number of bits used for this type in total. int numBits() const { return m_totalBits; } + /// Number of decimal digits after the radix point. int fractionalDigits() const { return m_fractionalDigits; } bool isSigned() const { return m_modifier == Modifier::Signed; } - u256 maximumPossibleInteger() const { return isSigned() ? - u256(((u256(1) << m_totalBits) - 1) / (pow(bigint(10), m_fractionalDigits))): - u256(((u256(1) << m_totalBits)) / (pow(bigint(10), m_fractionalDigits))); - } + /// @returns the largest integer value this type con hold. Note that this is not the + /// largest value in general. + bigint maxIntegerValue() const; + /// @returns the smallest integer value this type can hold. Note hat this is not the + /// smallest value in general. + bigint minIntegerValue() const; private: int m_totalBits; diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp index d290bedb..9cec0303 100644 --- a/libsolidity/parsing/Token.cpp +++ b/libsolidity/parsing/Token.cpp @@ -70,7 +70,7 @@ void ElementaryTypeNameToken::assertDetails(Token::Value _baseType, unsigned con else if (_baseType == Token::UFixedMxN || _baseType == Token::FixedMxN) { solAssert( - _first <= 256 && _first % 8 == 0 && _second >= 0 && _second <= 80, + _first >= 8 && _first <= 256 && _first % 8 == 0 && _second <= 80, "No elementary type " + string(Token::toString(_baseType)) + to_string(_first) + "x" + to_string(_second) + "." ); } -- cgit