diff options
author | chriseth <chris@ethereum.org> | 2018-12-11 01:02:36 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-11 01:02:36 +0800 |
commit | 5355380f80eeb9fac49dd28a32b08ba88e662c87 (patch) | |
tree | e18d162e1b9de2cac75fbebe9658e4ba85e6a4ef | |
parent | 687382ae09106236a97907f72473dc275891f2fc (diff) | |
parent | 81f703427e7b34b5488d452eee9e8246e30421bb (diff) | |
download | dexon-solidity-5355380f80eeb9fac49dd28a32b08ba88e662c87.tar dexon-solidity-5355380f80eeb9fac49dd28a32b08ba88e662c87.tar.gz dexon-solidity-5355380f80eeb9fac49dd28a32b08ba88e662c87.tar.bz2 dexon-solidity-5355380f80eeb9fac49dd28a32b08ba88e662c87.tar.lz dexon-solidity-5355380f80eeb9fac49dd28a32b08ba88e662c87.tar.xz dexon-solidity-5355380f80eeb9fac49dd28a32b08ba88e662c87.tar.zst dexon-solidity-5355380f80eeb9fac49dd28a32b08ba88e662c87.zip |
Merge pull request #5552 from 0yi0/5551-rational-convertible-to-fixed-point
Fix conversions from rational number literals to fixed-point types.
5 files changed, 86 insertions, 55 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 1c9f1956..d41415c0 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -935,30 +935,32 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) var.accept(*this); if (!valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type)) { + auto errorMsg = "Type " + + valueComponentType->toString() + + " is not implicitly convertible to expected type " + + var.annotation().type->toString(); if ( valueComponentType->category() == Type::Category::RationalNumber && dynamic_cast<RationalNumberType const&>(*valueComponentType).isFractional() && valueComponentType->mobileType() ) - m_errorReporter.typeError( - _statement.location(), - "Type " + - valueComponentType->toString() + - " is not implicitly convertible to expected type " + - var.annotation().type->toString() + - ". Try converting to type " + - valueComponentType->mobileType()->toString() + - " or use an explicit conversion." - ); + { + if (var.annotation().type->operator==(*valueComponentType->mobileType())) + m_errorReporter.typeError( + _statement.location(), + errorMsg + ", but it can be explicitly converted." + ); + else + m_errorReporter.typeError( + _statement.location(), + errorMsg + + ". Try converting to type " + + valueComponentType->mobileType()->toString() + + " or use an explicit conversion." + ); + } else - m_errorReporter.typeError( - _statement.location(), - "Type " + - valueComponentType->toString() + - " is not implicitly convertible to expected type " + - var.annotation().type->toString() + - "." - ); + m_errorReporter.typeError(_statement.location(), errorMsg + "."); } } } @@ -2331,30 +2333,32 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte _expression.accept(*this); if (!type(_expression)->isImplicitlyConvertibleTo(_expectedType)) { + auto errorMsg = "Type " + + type(_expression)->toString() + + " is not implicitly convertible to expected type " + + _expectedType.toString(); if ( type(_expression)->category() == Type::Category::RationalNumber && dynamic_pointer_cast<RationalNumberType const>(type(_expression))->isFractional() && type(_expression)->mobileType() ) - m_errorReporter.typeError( - _expression.location(), - "Type " + - type(_expression)->toString() + - " is not implicitly convertible to expected type " + - _expectedType.toString() + - ". Try converting to type " + - type(_expression)->mobileType()->toString() + - " or use an explicit conversion." - ); + { + if (_expectedType.operator==(*type(_expression)->mobileType())) + m_errorReporter.typeError( + _expression.location(), + errorMsg + ", but it can be explicitly converted." + ); + else + m_errorReporter.typeError( + _expression.location(), + errorMsg + + ". Try converting to type " + + type(_expression)->mobileType()->toString() + + " or use an explicit conversion." + ); + } else - m_errorReporter.typeError( - _expression.location(), - "Type " + - type(_expression)->toString() + - " is not implicitly convertible to expected type " + - _expectedType.toString() + - "." - ); + m_errorReporter.typeError(_expression.location(), errorMsg + "."); return false; } return true; diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index f5a38747..621e6513 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -125,6 +125,22 @@ bool fitsPrecisionBase2(bigint const& _mantissa, uint32_t _expBase2) return fitsPrecisionBaseX(_mantissa, 1.0, _expBase2); } +/// Checks whether _value fits into IntegerType _type. +bool fitsIntegerType(bigint const& _value, IntegerType const& _type) +{ + return (_type.minValue() <= _value) && (_value <= _type.maxValue()); +} + +/// Checks whether _value fits into _bits bits when having 1 bit as the sign bit +/// if _signed is true. +bool fitsIntoBits(bigint const& _value, unsigned _bits, bool _signed) +{ + return fitsIntegerType(_value, IntegerType( + _bits, + _signed ? IntegerType::Modifier::Signed : IntegerType::Modifier::Unsigned + )); +} + } void StorageOffsets::computeOffsets(TypePointers const& _types) @@ -963,27 +979,21 @@ BoolResult RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) if (isFractional()) return false; IntegerType const& targetType = dynamic_cast<IntegerType const&>(_convertTo); - if (m_value == rational(0)) - return true; - unsigned forSignBit = (targetType.isSigned() ? 1 : 0); - if (m_value > rational(0)) - { - if (m_value.numerator() <= (u256(-1) >> (256 - targetType.numBits() + forSignBit))) - return true; - return false; - } - if (targetType.isSigned()) - { - if (-m_value.numerator() <= (u256(1) << (targetType.numBits() - forSignBit))) - return true; - } - return false; + return fitsIntegerType(m_value.numerator(), targetType); } case Category::FixedPoint: { - if (auto fixed = fixedPointType()) - return fixed->isImplicitlyConvertibleTo(_convertTo); - return false; + FixedPointType const& targetType = dynamic_cast<FixedPointType const&>(_convertTo); + // Store a negative number into an unsigned. + if (isNegative() && !targetType.isSigned()) + return false; + if (!isFractional()) + return (targetType.minIntegerValue() <= m_value) && (m_value <= targetType.maxIntegerValue()); + rational value = m_value * pow(bigint(10), targetType.fractionalDigits()); + // Need explicit conversion since truncation will occur. + if (value.denominator() != 1) + return false; + return fitsIntoBits(value.numerator(), targetType.numBits(), targetType.isSigned()); } case Category::FixedBytes: return (m_value == rational(0)) || (m_compatibleBytesType && *m_compatibleBytesType == _convertTo); diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/313_fixed_type_size_capabilities.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/313_fixed_type_size_capabilities.sol index 441cf81e..295cf4ea 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/313_fixed_type_size_capabilities.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/313_fixed_type_size_capabilities.sol @@ -10,4 +10,5 @@ contract test { } } // ---- -// Warning: (20-707): Function state mutability can be restricted to pure +// TypeError: (153-250): Type rational_const 9208...(70 digits omitted)...7637 / 1000...(71 digits omitted)...0000 is not implicitly convertible to expected type ufixed256x77, but it can be explicitly converted. +// TypeError: (470-566): Type rational_const -933...(70 digits omitted)...0123 / 1000...(70 digits omitted)...0000 is not implicitly convertible to expected type fixed256x76, but it can be explicitly converted. diff --git a/test/libsolidity/syntaxTests/types/rational_number_literal_to_fixed_implicit.sol b/test/libsolidity/syntaxTests/types/rational_number_literal_to_fixed_implicit.sol new file mode 100644 index 00000000..ca50e03b --- /dev/null +++ b/test/libsolidity/syntaxTests/types/rational_number_literal_to_fixed_implicit.sol @@ -0,0 +1,15 @@ +contract C { + function literalToUFixed() public pure { + ufixed8x2 a = 0.10; + ufixed8x2 b = 0.00; + ufixed8x2 c = 2.55; + a; b; c; + } + function literalToFixed() public pure { + fixed8x1 a = 0.1; + fixed8x1 b = 12.7; + fixed8x1 c = -12.8; + a; b; c; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/types/too_small_negative_numbers.sol b/test/libsolidity/syntaxTests/types/too_small_negative_numbers.sol index 66bd9a8e..f86ffcdd 100644 --- a/test/libsolidity/syntaxTests/types/too_small_negative_numbers.sol +++ b/test/libsolidity/syntaxTests/types/too_small_negative_numbers.sol @@ -2,3 +2,4 @@ contract C { fixed8x80 a = -1e-100; } // ---- +// TypeError: (29-36): Type rational_const -1 / 1000...(93 digits omitted)...0000 is not implicitly convertible to expected type fixed8x80, but it can be explicitly converted. |