From 28e8f5571b36786b082ded0c8954545aae6b7d89 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 28 Jul 2021 11:30:10 +0200 Subject: [PATCH] Allow explicit conversion from rational to fixed if it fits value range. --- libsolidity/ast/Types.cpp | 37 +++++++++++++++++++++++++++++++------ libsolidity/ast/Types.h | 3 +++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 16dade7d7..3d541401c 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -756,19 +756,31 @@ string FixedPointType::toString(bool) const bigint FixedPointType::maxIntegerValue() const { - bigint maxValue = (bigint(1) << (m_totalBits - (isSigned() ? 1 : 0))) - 1; - return maxValue / boost::multiprecision::pow(bigint(10), m_fractionalDigits); + rational max = maxValue(); + return max.numerator() / max.denominator(); } bigint FixedPointType::minIntegerValue() const +{ + rational min = minValue(); + return min.numerator() / min.denominator(); +} + +rational FixedPointType::maxValue() const +{ + bigint maxValue = (bigint(1) << (m_totalBits - (isSigned() ? 1 : 0))) - 1; + return rational(maxValue) / boost::multiprecision::pow(bigint(10), m_fractionalDigits); +} + +rational FixedPointType::minValue() const { if (isSigned()) { - bigint minValue = -(bigint(1) << (m_totalBits - (isSigned() ? 1 : 0))); - return minValue / boost::multiprecision::pow(bigint(10), m_fractionalDigits); + bigint minValue = -(bigint(1) << (m_totalBits - 1)); + return rational(minValue) / boost::multiprecision::pow(bigint(10), m_fractionalDigits); } else - return bigint(0); + return rational{0}; } TypeResult FixedPointType::binaryOperatorResult(Token _operator, Type const* _other) const @@ -985,11 +997,24 @@ BoolResult RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) else if (category == Category::Integer) return false; else if (auto enumType = dynamic_cast(&_convertTo)) + { if (isNegative() || isFractional() || m_value >= enumType->numberOfMembers()) return false; + } + else if (auto fixedPointType = dynamic_cast(&_convertTo)) + { + if (value() < fixedPointType->minValue()) + return BoolResult::err("Value is too small."); + else if (value() > fixedPointType->maxValue()) + return BoolResult::err("Value is too large."); + else + return true; + } Type const* mobType = mobileType(); - return (mobType && mobType->isExplicitlyConvertibleTo(_convertTo)); + if (!mobType) + return false; + return mobType->isExplicitlyConvertibleTo(_convertTo); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 0e749e9e0..38c9ba663 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -529,6 +529,9 @@ public: /// smallest value in general. bigint minIntegerValue() const; + rational maxValue() const; + rational minValue() const; + /// @returns the smallest integer type that can hold this type with fractional parts shifted to integers. IntegerType const* asIntegerType() const;