Fix up fixed point type class.

This commit is contained in:
chriseth 2021-07-27 11:05:57 +02:00
parent ae519c1278
commit e6353c7e28
2 changed files with 29 additions and 9 deletions

View File

@ -553,8 +553,6 @@ BoolResult IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
return (!isSigned() && (numBits() == fixedBytesType->numBytes() * 8)); return (!isSigned() && (numBits() == fixedBytesType->numBytes() * 8));
else if (dynamic_cast<EnumType const*>(&_convertTo)) else if (dynamic_cast<EnumType const*>(&_convertTo))
return true; return true;
else if (auto fixedPointType = dynamic_cast<FixedPointType const*>(&_convertTo))
return (isSigned() == fixedPointType->isSigned()) && (numBits() == fixedPointType->numBits());
return false; return false;
} }
@ -689,7 +687,7 @@ BoolResult FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) con
{ {
FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo); FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo);
if (convertTo.fractionalDigits() < m_fractionalDigits) if (convertTo.fractionalDigits() < m_fractionalDigits)
return BoolResult::err("Too many fractional digits."); return BoolResult::err("Conversion would incur precision loss - use explicit conversion instead.");
if (convertTo.numBits() < m_totalBits) if (convertTo.numBits() < m_totalBits)
return false; return false;
else else
@ -700,7 +698,28 @@ BoolResult FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) con
BoolResult FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const BoolResult FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
return _convertTo.category() == category() || _convertTo.category() == Category::Integer; if (isImplicitlyConvertibleTo(_convertTo))
return true;
if (FixedBytesType const* convertTo = dynamic_cast<FixedBytesType const*>(&_convertTo))
return 8 * convertTo->numBytes() == m_totalBits;
if (FixedPointType const* convertTo = dynamic_cast<FixedPointType const*>(&_convertTo))
{
// It was not implicitly convertible, so we either lose precision or value range (can also be signedness).
size_t changes = 0;
if (convertTo->numBits() != numBits()) changes++;
if (convertTo->isSigned() != isSigned()) changes++;
if (convertTo->fractionalDigits() != fractionalDigits()) changes++;
solAssert(changes != 0, "");
if (changes > 1)
return BoolResult::err("Can only change one of precision, number of bits and signedness at the same time.");
return true;
}
if (IntegerType const* convertTo = dynamic_cast<IntegerType const*>(&_convertTo))
return
maxIntegerValue() <= convertTo->maxValue() &&
minIntegerValue() >= convertTo->minValue();
return false;
} }
TypeResult FixedPointType::unaryOperatorResult(Token _operator) const TypeResult FixedPointType::unaryOperatorResult(Token _operator) const
@ -986,9 +1005,9 @@ TypeResult RationalNumberType::binaryOperatorResult(Token _operator, Type const*
{ {
if (_other->category() == Category::Integer || _other->category() == Category::FixedPoint) if (_other->category() == Category::Integer || _other->category() == Category::FixedPoint)
{ {
if (isFractional()) if (isFractional() && !fixedPointType())
return TypeResult::err("Fractional literals not supported."); return TypeResult::err("Literal too large or cannot be represented without precision loss.");
else if (!integerType()) else if (!isFractional() && !integerType())
return TypeResult::err("Literal too large."); return TypeResult::err("Literal too large.");
// Shift and exp are not symmetric, so it does not make sense to swap // Shift and exp are not symmetric, so it does not make sense to swap

View File

@ -573,9 +573,10 @@ public:
/// @returns the smallest integer type that can hold the value or an empty pointer if not possible. /// @returns the smallest integer type that can hold the value or an empty pointer if not possible.
IntegerType const* integerType() const; IntegerType const* integerType() const;
/// @returns the smallest fixed type that can hold the value or incurs the least precision loss, /// @returns the smallest fixed type that can hold the value or incurs the least precision loss.
/// unless the value was truncated, then a suitable type will be chosen to indicate such event.
/// If the integer part does not fit, returns an empty pointer. /// If the integer part does not fit, returns an empty pointer.
/// The rational number is not always implicitly convertible to the resulting type
/// (for example if precision loss is required).
FixedPointType const* fixedPointType() const; FixedPointType const* fixedPointType() const;
/// @returns true if the value is not an integer. /// @returns true if the value is not an integer.