From 78769f3b39bccbfa02edec302a02377e8fa08a8d Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Thu, 22 Dec 2016 12:20:03 -0600 Subject: Change fixed point types to have digit count Signed-off-by: VoR0220 --- libsolidity/ast/Types.cpp | 101 +++++++++++--------- libsolidity/ast/Types.h | 23 +++-- libsolidity/codegen/CompilerUtils.cpp | 2 +- libsolidity/parsing/Token.cpp | 10 +- test/libsolidity/SolidityNameAndTypeResolution.cpp | 104 ++++++++++----------- 5 files changed, 127 insertions(+), 113 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 76bfb1a8..14e948cc 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -196,9 +196,9 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type) case Token::UInt: return make_shared(256, IntegerType::Modifier::Unsigned); case Token::Fixed: - return make_shared(128, 128, FixedPointType::Modifier::Signed); + return make_shared(128, 19, FixedPointType::Modifier::Signed); case Token::UFixed: - return make_shared(128, 128, FixedPointType::Modifier::Unsigned); + return make_shared(128, 19, FixedPointType::Modifier::Unsigned); case Token::Byte: return make_shared(1); case Token::Address: @@ -352,12 +352,13 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const else if (_convertTo.category() == Category::FixedPoint) { FixedPointType const& convertTo = dynamic_cast(_convertTo); - if (convertTo.integerBits() < m_bits || isAddress()) + + if (((u256(1) << m_bits) <= convertTo.numBits() && convertTo.fractionalDigits() == 0) || isAddress()) return false; else if (isSigned()) return convertTo.isSigned(); else - return !convertTo.isSigned() || convertTo.integerBits() > m_bits; + return !convertTo.isSigned() || convertTo.numBits() > m_bits; } else return false; @@ -487,22 +488,20 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons return MemberList::MemberMap(); } -FixedPointType::FixedPointType(int _integerBits, int _fractionalBits, FixedPointType::Modifier _modifier): - m_integerBits(_integerBits), m_fractionalBits(_fractionalBits), m_modifier(_modifier) +FixedPointType::FixedPointType(int _totalBits, int _fractionalDigits, FixedPointType::Modifier _modifier): + m_totalBits(_totalBits), m_fractionalDigits(_fractionalDigits), m_modifier(_modifier) { solAssert( - m_integerBits + m_fractionalBits > 0 && - m_integerBits + m_fractionalBits <= 256 && - m_integerBits % 8 == 0 && - m_fractionalBits % 8 == 0, + 8 <= m_totalBits && m_totalBits <= 256 && m_totalBits % 8 == 0 && + 0 <= m_fractionalDigits && m_fractionalDigits <= 80, "Invalid bit number(s) for fixed type: " + - dev::toString(_integerBits) + "x" + dev::toString(_fractionalBits) - ); + dev::toString(_totalBits) + "x" + dev::toString(_fractionalDigits) + ); } string FixedPointType::identifier() const { - return "t_" + string(isSigned() ? "" : "u") + "fixed" + std::to_string(integerBits()) + "x" + std::to_string(fractionalBits()); + return "t_" + string(isSigned() ? "" : "u") + "fixed" + std::to_string(numBits()) + "x" + std::to_string(fractionalDigits()); } bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const @@ -510,12 +509,10 @@ bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const if (_convertTo.category() == category()) { FixedPointType const& convertTo = dynamic_cast(_convertTo); - if (convertTo.m_integerBits < m_integerBits || convertTo.m_fractionalBits < m_fractionalBits) + if (convertTo.numBits() < m_totalBits || convertTo.fractionalDigits() < m_fractionalDigits) return false; - else if (isSigned()) - return convertTo.isSigned(); else - return !convertTo.isSigned() || (convertTo.m_integerBits > m_integerBits); + return convertTo.maximumPossibleInteger() >= maximumPossibleInteger(); } return false; } @@ -527,6 +524,31 @@ 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 @@ -549,13 +571,13 @@ bool FixedPointType::operator==(Type const& _other) const if (_other.category() != category()) return false; FixedPointType const& other = dynamic_cast(_other); - return other.m_integerBits == m_integerBits && other.m_fractionalBits == m_fractionalBits && other.m_modifier == m_modifier; + return other.m_totalBits == m_totalBits && other.m_fractionalDigits == m_fractionalDigits && other.m_modifier == m_modifier; } string FixedPointType::toString(bool) const { string prefix = isSigned() ? "fixed" : "ufixed"; - return prefix + dev::toString(m_integerBits) + "x" + dev::toString(m_fractionalBits); + return prefix + dev::toString(m_totalBits) + "x" + dev::toString(m_fractionalDigits); } TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const @@ -746,9 +768,12 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const { // We disallow implicit conversion if we would have to truncate (fixedPointType() // can return a type that requires truncation). - rational value = m_value * (bigint(1) << fixed->fractionalBits()); + 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; } else if (_convertTo.category() == Category::FixedBytes) @@ -954,9 +979,9 @@ u256 RationalNumberType::literalValue(Literal const*) const { auto fixed = fixedPointType(); solAssert(!!fixed, ""); - rational shifted = m_value * (bigint(1) << fixed->fractionalBits()); // truncate - shiftedValue = shifted.numerator() / shifted.denominator(); + shiftedValue = m_value.numerator() / m_value.denominator(); + cout << "Shifted value: " << shiftedValue << endl; } // we ignore the literal and hope that the type was correctly determined @@ -997,23 +1022,27 @@ shared_ptr RationalNumberType::integerType() const shared_ptr RationalNumberType::fixedPointType() const { bool negative = (m_value < 0); - unsigned fractionalBits = 0; + unsigned fractionalDigits = 0; rational value = abs(m_value); // We care about the sign later. rational maxValue = negative ? rational(bigint(1) << 255, 1): rational((bigint(1) << 256) - 1, 1); - while (value * 0x100 <= maxValue && value.denominator() != 1 && fractionalBits < 256) + while (value * 10 <= maxValue && value.denominator() != 1 && fractionalDigits < 80) { - value *= 0x100; - fractionalBits += 8; + value *= 10; + fractionalDigits++; } 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() 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 @@ -1022,26 +1051,12 @@ shared_ptr RationalNumberType::fixedPointType() const if (v > u256(-1)) return shared_ptr(); - unsigned totalBits = bytesRequired(v) * 8; + unsigned totalBits = max(bytesRequired(v), 1u) * 8; solAssert(totalBits <= 256, ""); - unsigned integerBits = totalBits >= fractionalBits ? totalBits - fractionalBits : 0; - // Special case: Numbers between -1 and 0 have their sign bit in the fractional part. - if (negative && abs(m_value) < 1 && totalBits > fractionalBits) - { - fractionalBits += 8; - integerBits = 0; - } - - if (integerBits > 256 || fractionalBits > 256 || fractionalBits + integerBits > 256) - return shared_ptr(); - if (integerBits == 0 && fractionalBits == 0) - { - integerBits = 0; - fractionalBits = 8; - } + cout << "rational turned into " << (negative ? "fixed" : "ufixed") << totalBits << "x" << fractionalDigits << endl; return make_shared( - integerBits, fractionalBits, + totalBits, fractionalDigits, negative ? FixedPointType::Modifier::Signed : FixedPointType::Modifier::Unsigned ); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index c24cc11a..d5ef343a 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -321,6 +321,10 @@ 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; @@ -342,7 +346,7 @@ public: }; virtual Category category() const override { return Category::FixedPoint; } - explicit FixedPointType(int _integerBits, int _fractionalBits, Modifier _modifier = Modifier::Unsigned); + explicit FixedPointType(int _totalBits, int _fractionalDigits, Modifier _modifier = Modifier::Unsigned); virtual std::string identifier() const override; virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; @@ -352,8 +356,8 @@ public: virtual bool operator==(Type const& _other) const override; - virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : (m_integerBits + m_fractionalBits) / 8; } - virtual unsigned storageBytes() const override { return (m_integerBits + m_fractionalBits) / 8; } + virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_totalBits / 8; } + virtual unsigned storageBytes() const override { return m_totalBits / 8; } virtual bool isValueType() const override { return true; } virtual std::string toString(bool _short) const override; @@ -361,14 +365,17 @@ public: virtual TypePointer encodingType() const override { return shared_from_this(); } virtual TypePointer interfaceType(bool) const override { return shared_from_this(); } - int numBits() const { return m_integerBits + m_fractionalBits; } - int integerBits() const { return m_integerBits; } - int fractionalBits() const { return m_fractionalBits; } + int numBits() const { return m_totalBits; } + 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))); + } private: - int m_integerBits; - int m_fractionalBits; + int m_totalBits; + int m_fractionalDigits; Modifier m_modifier; }; diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 7067ddd5..782aad9d 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -504,7 +504,7 @@ void CompilerUtils::convertType( //shift all integer bits onto the left side of the fixed type FixedPointType const& targetFixedPointType = dynamic_cast(_targetType); if (auto typeOnStack = dynamic_cast(&_typeOnStack)) - if (targetFixedPointType.integerBits() > typeOnStack->numBits()) + if (targetFixedPointType.numBits() > typeOnStack->numBits()) cleanHigherOrderBits(*typeOnStack); solUnimplemented("Not yet implemented - FixedPointType."); } diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp index 66312f69..d290bedb 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 + _second <= 256 && _first % 8 == 0 && _second % 8 == 0, + _first <= 256 && _first % 8 == 0 && _second >= 0 && _second <= 80, "No elementary type " + string(Token::toString(_baseType)) + to_string(_first) + "x" + to_string(_second) + "." ); } @@ -157,12 +157,8 @@ tuple Token::fromIdentifierOrKeyword(s ) { int n = parseSize(positionX + 1, _literal.end()); if ( - 0 <= m && m <= 256 && - 8 <= n && n <= 256 && - m + n > 0 && - m + n <= 256 && - m % 8 == 0 && - n % 8 == 0 + 8 <= m && m <= 256 && m % 8 == 0 && + 0 <= n && n <= 80 ) { if (keyword == Token::UFixed) return make_tuple(Token::UFixedMxN, m, n); diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 2a5613c0..d511ca02 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -4145,20 +4145,8 @@ BOOST_AUTO_TEST_CASE(rational_unary_operation) char const* text = R"( contract test { function f() { - ufixed8x16 a = 3.25; - fixed8x16 b = -3.25; - a; - b; - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract test { - function f() { - ufixed8x16 a = +3.25; - fixed8x16 b = -3.25; - a; b; + ufixed16x2 a = +3.25; + fixed16x2 b = -3.25; } } )"; @@ -4179,11 +4167,10 @@ BOOST_AUTO_TEST_CASE(leading_zero_rationals_convert) char const* text = R"( contract A { function f() { - ufixed0x8 a = 0.5; - ufixed0x56 b = 0.0000000000000006661338147750939242541790008544921875; - fixed0x8 c = -0.5; - fixed0x56 d = -0.0000000000000006661338147750939242541790008544921875; - a; b; c; d; + ufixed16x8 a = 0.5; + ufixed256x56 b = 0.0000000000000006661338147750939242541790008544921875; + fixed16x8 c = -0.5; + fixed256x56 d = -0.0000000000000006661338147750939242541790008544921875; } } )"; @@ -4195,13 +4182,25 @@ BOOST_AUTO_TEST_CASE(size_capabilities_of_fixed_point_types) char const* text = R"( contract test { function f() { - ufixed248x8 a = 123456781234567979695948382928485849359686494864095409282048094275023098123.5; - ufixed0x256 b = 0.920890746623327805482905058466021565416131529487595827354393978494366605267637829135688384325135165352082715782143655824815685807141335814463015972119819459298455224338812271036061391763384038070334798471324635050876128428143374549108557403087615966796875; - ufixed0x256 c = 0.0000000000015198847363997979984922685411315294875958273543939784943666052676464653042434787697605517039455161817147718251801220885263595179331845639229818863564267318422845592626219390573301877339317935702714669975697814319204326238832436501979827880859375; - fixed248x8 d = -123456781234567979695948382928485849359686494864095409282048094275023098123.5; - fixed0x256 e = -0.93322335481643744342575580035176794825198893968114429702091846411734101080123092162893656820177312738451291806995868682861328125; - fixed0x256 g = -0.00011788606643744342575580035176794825198893968114429702091846411734101080123092162893656820177312738451291806995868682861328125; - a; b; c; d; e; g; + ufixed256x1 a = 123456781234567979695948382928485849359686494864095409282048094275023098123.5; + ufixed256x77 b = 0.920890746623327805482905058466021565416131529487595827354393978494366605267637; + ufixed224x78 c = 0.000000000001519884736399797998492268541131529487595827354393978494366605267646; + fixed256x1 d = -123456781234567979695948382928485849359686494864095409282048094275023098123.5; + fixed256x76 e = -0.93322335481643744342575580035176794825198893968114429702091846411734101080123; + fixed256x79 g = -0.0001178860664374434257558003517679482519889396811442970209184641173410108012309; + } + } + )"; + CHECK_SUCCESS(text); +} + +BOOST_AUTO_TEST_CASE(zero_handling) +{ + char const* text = R"( + contract test { + function f() { + fixed16x8 a = 0; + ufixed8x8 b = 0; } } )"; @@ -4226,7 +4225,7 @@ BOOST_AUTO_TEST_CASE(fixed_type_invalid_implicit_conversion_lost_data) char const* text = R"( contract test { function f() { - ufixed0x256 a = 1/3; + ufixed256x1 a = 1/3; } } )"; @@ -4238,10 +4237,9 @@ BOOST_AUTO_TEST_CASE(fixed_type_valid_explicit_conversions) char const* text = R"( contract test { function f() { - ufixed0x256 a = ufixed0x256(1/3); - ufixed0x248 b = ufixed0x248(1/3); - ufixed0x8 c = ufixed0x8(1/3); - a; b; c; + ufixed256x80 a = ufixed256x80(1/3); + ufixed248x80 b = ufixed248x80(1/3); + ufixed8x1 c = ufixed8x1(1/3); } } )"; @@ -4260,7 +4258,7 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_rational) BOOST_CHECK(!success(text)); } -BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_fixed_type) +BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_signed_fixed_type) { char const* text = R"( contract test { @@ -4272,6 +4270,18 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_fixed_type) BOOST_CHECK(!success(text)); } +BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type) +{ + char const* text = R"( + contract test { + function f() { + uint[ufixed(3.5)] a; + } + } + )"; + BOOST_CHECK(!success(text)); +} + BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion) { char const* text = R"( @@ -4301,7 +4311,7 @@ BOOST_AUTO_TEST_CASE(mapping_with_fixed_literal) { char const* text = R"( contract test { - mapping(ufixed8x248 => string) fixedString; + mapping(ufixed8x1 => string) fixedString; function f() { fixedString[0.5] = "Half"; } @@ -4341,7 +4351,7 @@ BOOST_AUTO_TEST_CASE(inline_array_rationals) char const* text = R"( contract test { function f() { - ufixed8x8[4] memory a = [3.5, 4.125, 2.5, 4.0]; + ufixed16x3[4] memory a = [3.5, 4.125, 2.5, 4.0]; } } )"; @@ -4368,10 +4378,10 @@ BOOST_AUTO_TEST_CASE(rational_to_fixed_literal_expression) function f() { ufixed8x8 a = 3.5 * 3; ufixed8x8 b = 4 - 2.5; - ufixed8x8 c = 11 / 4; - ufixed16x240 d = 599 + 0.21875; - ufixed8x248 e = ufixed8x248(35.245 % 12.9); - ufixed8x248 f = ufixed8x248(1.2 % 2); + ufixed16x8 c = 11 / 4; + ufixed240x5 d = 599 + 0.21875; + ufixed256x80 e = ufixed256x80(35.245 % 12.9); + ufixed256x80 f = ufixed256x80(1.2 % 2); fixed g = 2 ** -2; a; b; c; d; e; f; g; } @@ -4380,7 +4390,7 @@ BOOST_AUTO_TEST_CASE(rational_to_fixed_literal_expression) CHECK_SUCCESS(text); } -BOOST_AUTO_TEST_CASE(rational_as_exponent_value_neg_decimal) +BOOST_AUTO_TEST_CASE(rational_as_exponent_value_signed) { char const* text = R"( contract test { @@ -4392,7 +4402,7 @@ BOOST_AUTO_TEST_CASE(rational_as_exponent_value_neg_decimal) BOOST_CHECK(!success(text)); } -BOOST_AUTO_TEST_CASE(rational_as_exponent_value_pos_decimal) +BOOST_AUTO_TEST_CASE(rational_as_exponent_value_unsigned) { char const* text = R"( contract test { @@ -4564,20 +4574,6 @@ BOOST_AUTO_TEST_CASE(rational_bitand_binary_operation) BOOST_CHECK(!success(text)); } -BOOST_AUTO_TEST_CASE(zero_handling) -{ - char const* text = R"( - contract test { - function f() { - fixed8x8 a = 0; - ufixed8x8 b = 0; - a; b; - } - } - )"; - CHECK_SUCCESS(text); -} - BOOST_AUTO_TEST_CASE(missing_bool_conversion) { char const* text = R"( -- cgit v1.2.3 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 +- test/libsolidity/SolidityNameAndTypeResolution.cpp | 154 ++++++++++----------- 4 files changed, 110 insertions(+), 142 deletions(-) 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) + "." ); } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index d511ca02..4b29243a 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -2290,6 +2290,9 @@ BOOST_AUTO_TEST_CASE(test_fromElementaryTypeName) BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::BytesM, 30, 0)) == *make_shared(30)); BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::BytesM, 31, 0)) == *make_shared(31)); BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::BytesM, 32, 0)) == *make_shared(32)); + + BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::Fixed, 0, 0)) == *make_shared(128, 19, FixedPointType::Modifier::Signed)); + BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixed, 0, 0)) == *make_shared(128, 19, FixedPointType::Modifier::Unsigned)); } BOOST_AUTO_TEST_CASE(test_byte_is_alias_of_byte1) @@ -4033,7 +4036,7 @@ BOOST_AUTO_TEST_CASE(invalid_fixed_types_0x7_mxn) fixed0x7 a = .3; } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, DeclarationError, "Identifier not found"); } BOOST_AUTO_TEST_CASE(invalid_fixed_types_long_invalid_identifier) @@ -4043,7 +4046,7 @@ BOOST_AUTO_TEST_CASE(invalid_fixed_types_long_invalid_identifier) fixed99999999999999999999999999999999999999x7 b = 9.5; } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, DeclarationError, "Identifier not found"); } BOOST_AUTO_TEST_CASE(invalid_fixed_types_7x8_mxn) @@ -4053,7 +4056,7 @@ BOOST_AUTO_TEST_CASE(invalid_fixed_types_7x8_mxn) fixed7x8 c = 3.12345678; } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, DeclarationError, "Identifier not found"); } BOOST_AUTO_TEST_CASE(library_instances_cannot_be_used) @@ -4067,7 +4070,7 @@ BOOST_AUTO_TEST_CASE(library_instances_cannot_be_used) } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "Member \"l\" not found or not visible after argument-dependent lookup in library L"); } BOOST_AUTO_TEST_CASE(invalid_fixed_type_long) @@ -4079,7 +4082,7 @@ BOOST_AUTO_TEST_CASE(invalid_fixed_type_long) } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, DeclarationError, "Identifier not found"); } BOOST_AUTO_TEST_CASE(fixed_type_int_conversion) @@ -4087,8 +4090,8 @@ BOOST_AUTO_TEST_CASE(fixed_type_int_conversion) char const* text = R"( contract test { function f() { - uint128 a = 3; - int128 b = 4; + uint64 a = 3; + int64 b = 4; fixed c = b; ufixed d = a; c; d; @@ -4137,20 +4140,31 @@ BOOST_AUTO_TEST_CASE(invalid_int_implicit_conversion_from_fixed) } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "Type fixed128x19 is not implicitly convertible to expected type int256"); } BOOST_AUTO_TEST_CASE(rational_unary_operation) { char const* text = R"( + contract test { + function f() { + ufixed16x2 a = 3.25; + fixed16x2 b = -3.25; + a; b; + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); + text = R"( contract test { function f() { ufixed16x2 a = +3.25; fixed16x2 b = -3.25; + a; b; } } )"; - CHECK_WARNING(text,"Use of unary + is deprecated"); + CHECK_WARNING(text, "Use of unary + is deprecated"); text = R"( contract test { function f(uint x) { @@ -4167,10 +4181,11 @@ BOOST_AUTO_TEST_CASE(leading_zero_rationals_convert) char const* text = R"( contract A { function f() { - ufixed16x8 a = 0.5; - ufixed256x56 b = 0.0000000000000006661338147750939242541790008544921875; - fixed16x8 c = -0.5; - fixed256x56 d = -0.0000000000000006661338147750939242541790008544921875; + ufixed16x2 a = 0.5; + ufixed256x52 b = 0.0000000000000006661338147750939242541790008544921875; + fixed16x2 c = -0.5; + fixed256x52 d = -0.0000000000000006661338147750939242541790008544921875; + a; b; c; d; } } )"; @@ -4188,6 +4203,7 @@ BOOST_AUTO_TEST_CASE(size_capabilities_of_fixed_point_types) fixed256x1 d = -123456781234567979695948382928485849359686494864095409282048094275023098123.5; fixed256x76 e = -0.93322335481643744342575580035176794825198893968114429702091846411734101080123; fixed256x79 g = -0.0001178860664374434257558003517679482519889396811442970209184641173410108012309; + a; b; c; d; e; g; } } )"; @@ -4199,8 +4215,8 @@ BOOST_AUTO_TEST_CASE(zero_handling) char const* text = R"( contract test { function f() { - fixed16x8 a = 0; - ufixed8x8 b = 0; + fixed16x2 a = 0; a; + ufixed32x1 b = 0; b; } } )"; @@ -4213,11 +4229,11 @@ BOOST_AUTO_TEST_CASE(fixed_type_invalid_implicit_conversion_size) contract test { function f() { ufixed a = 11/4; - ufixed248x8 b = a; + ufixed248x8 b = a; b; } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "Type ufixed128x19 is not implicitly convertible to expected type ufixed248x8"); } BOOST_AUTO_TEST_CASE(fixed_type_invalid_implicit_conversion_lost_data) @@ -4225,11 +4241,11 @@ BOOST_AUTO_TEST_CASE(fixed_type_invalid_implicit_conversion_lost_data) char const* text = R"( contract test { function f() { - ufixed256x1 a = 1/3; + ufixed256x1 a = 1/3; a; } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "is not implicitly convertible to expected type ufixed256x1"); } BOOST_AUTO_TEST_CASE(fixed_type_valid_explicit_conversions) @@ -4237,9 +4253,9 @@ BOOST_AUTO_TEST_CASE(fixed_type_valid_explicit_conversions) char const* text = R"( contract test { function f() { - ufixed256x80 a = ufixed256x80(1/3); - ufixed248x80 b = ufixed248x80(1/3); - ufixed8x1 c = ufixed8x1(1/3); + ufixed256x80 a = ufixed256x80(1/3); a; + ufixed248x80 b = ufixed248x80(1/3); b; + ufixed8x1 c = ufixed8x1(1/3); c; } } )"; @@ -4251,11 +4267,11 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_rational) char const* text = R"( contract test { function f() { - uint[3.5] a; + uint[3.5] a; a; } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal"); } BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_signed_fixed_type) @@ -4263,11 +4279,11 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_signed_fixed_type) char const* text = R"( contract test { function f() { - uint[fixed(3.5)] a; + uint[fixed(3.5)] a; a; } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal"); } BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type) @@ -4275,11 +4291,11 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type) char const* text = R"( contract test { function f() { - uint[ufixed(3.5)] a; + uint[ufixed(3.5)] a; a; } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal"); } BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion) @@ -4287,11 +4303,11 @@ BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion) char const* text = R"( contract test { function f() { - bytes32 c = 3.2; + bytes32 c = 3.2; c; } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "is not implicitly convertible to expected type bytes32"); } BOOST_AUTO_TEST_CASE(fixed_to_bytes_implicit_conversion) @@ -4300,11 +4316,11 @@ BOOST_AUTO_TEST_CASE(fixed_to_bytes_implicit_conversion) contract test { function f() { fixed a = 3.25; - bytes32 c = a; + bytes32 c = a; c; } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "fixed128x19 is not implicitly convertible to expected type bytes32"); } BOOST_AUTO_TEST_CASE(mapping_with_fixed_literal) @@ -4351,7 +4367,7 @@ BOOST_AUTO_TEST_CASE(inline_array_rationals) char const* text = R"( contract test { function f() { - ufixed16x3[4] memory a = [3.5, 4.125, 2.5, 4.0]; + ufixed128x3[4] memory a = [ufixed128x3(3.5), 4.125, 2.5, 4.0]; } } )"; @@ -4368,7 +4384,7 @@ BOOST_AUTO_TEST_CASE(rational_index_access) } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "rational_const 1/2 is not implicitly convertible to expected type uint256"); } BOOST_AUTO_TEST_CASE(rational_to_fixed_literal_expression) @@ -4376,9 +4392,9 @@ BOOST_AUTO_TEST_CASE(rational_to_fixed_literal_expression) char const* text = R"( contract test { function f() { - ufixed8x8 a = 3.5 * 3; - ufixed8x8 b = 4 - 2.5; - ufixed16x8 c = 11 / 4; + ufixed64x8 a = 3.5 * 3; + ufixed64x8 b = 4 - 2.5; + ufixed64x8 c = 11 / 4; ufixed240x5 d = 599 + 0.21875; ufixed256x80 e = ufixed256x80(35.245 % 12.9); ufixed256x80 f = ufixed256x80(1.2 % 2); @@ -4399,7 +4415,7 @@ BOOST_AUTO_TEST_CASE(rational_as_exponent_value_signed) } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "not compatible with types"); } BOOST_AUTO_TEST_CASE(rational_as_exponent_value_unsigned) @@ -4411,7 +4427,7 @@ BOOST_AUTO_TEST_CASE(rational_as_exponent_value_unsigned) } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "not compatible with types"); } BOOST_AUTO_TEST_CASE(rational_as_exponent_half) @@ -4419,11 +4435,11 @@ BOOST_AUTO_TEST_CASE(rational_as_exponent_half) char const* text = R"( contract test { function f() { - ufixed24x24 b = 2 ** (1/2); + 2 ** (1/2); } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "not compatible with types"); } BOOST_AUTO_TEST_CASE(rational_as_exponent_value_neg_quarter) @@ -4431,11 +4447,11 @@ BOOST_AUTO_TEST_CASE(rational_as_exponent_value_neg_quarter) char const* text = R"( contract test { function f() { - fixed40x40 c = 42 ** (-1/4); + 42 ** (-1/4); } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "not compatible with types"); } BOOST_AUTO_TEST_CASE(fixed_point_casting_exponents_15) @@ -4443,23 +4459,11 @@ BOOST_AUTO_TEST_CASE(fixed_point_casting_exponents_15) char const* text = R"( contract test { function f() { - ufixed a = 3 ** ufixed(1.5); - } - } - )"; - BOOST_CHECK(!success(text)); -} - -BOOST_AUTO_TEST_CASE(fixed_point_casting_exponents_half) -{ - char const* text = R"( - contract test { - function f() { - ufixed b = 2 ** ufixed(1/2); + var a = 3 ** ufixed(1.5); } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "not compatible with types"); } BOOST_AUTO_TEST_CASE(fixed_point_casting_exponents_neg) @@ -4467,23 +4471,11 @@ BOOST_AUTO_TEST_CASE(fixed_point_casting_exponents_neg) char const* text = R"( contract test { function f() { - fixed c = 42 ** fixed(-1/4); - } - } - )"; - BOOST_CHECK(!success(text)); -} - -BOOST_AUTO_TEST_CASE(fixed_point_casting_exponents_neg_decimal) -{ - char const* text = R"( - contract test { - function f() { - fixed d = 16 ** fixed(-0.5); + var c = 42 ** fixed(-1/4); } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "not compatible with types"); } BOOST_AUTO_TEST_CASE(var_capable_of_holding_constant_rationals) @@ -4531,11 +4523,11 @@ BOOST_AUTO_TEST_CASE(rational_bitnot_unary_operation) char const* text = R"( contract test { function f() { - fixed a = ~3.5; + ~fixed(3.5); } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "cannot be applied"); } BOOST_AUTO_TEST_CASE(rational_bitor_binary_operation) @@ -4543,11 +4535,11 @@ BOOST_AUTO_TEST_CASE(rational_bitor_binary_operation) char const* text = R"( contract test { function f() { - fixed a = 1.5 | 3; + fixed(1.5) | 3; } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "not compatible with types"); } BOOST_AUTO_TEST_CASE(rational_bitxor_binary_operation) @@ -4555,11 +4547,11 @@ BOOST_AUTO_TEST_CASE(rational_bitxor_binary_operation) char const* text = R"( contract test { function f() { - fixed a = 1.75 ^ 3; + fixed(1.75) ^ 3; } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "not compatible with types"); } BOOST_AUTO_TEST_CASE(rational_bitand_binary_operation) @@ -4567,11 +4559,11 @@ BOOST_AUTO_TEST_CASE(rational_bitand_binary_operation) char const* text = R"( contract test { function f() { - fixed a = 1.75 & 3; + fixed(1.75) & 3; } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "not compatible with types"); } BOOST_AUTO_TEST_CASE(missing_bool_conversion) @@ -4591,7 +4583,7 @@ BOOST_AUTO_TEST_CASE(integer_and_fixed_interaction) char const* text = R"( contract test { function f() { - ufixed a = uint128(1) + ufixed(2); + ufixed a = uint64(1) + ufixed(2); } } )"; @@ -4621,7 +4613,7 @@ BOOST_AUTO_TEST_CASE(one_divided_by_three_integer_conversion) } } )"; - BOOST_CHECK(!success(text)); + CHECK_ERROR(text, TypeError, "is not implicitly convertible to expected type uint256. Try converting to type ufixed256x77"); } BOOST_AUTO_TEST_CASE(unused_return_value) -- cgit v1.2.3