diff options
-rw-r--r-- | libsolidity/ast/Types.cpp | 124 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 5 | ||||
-rw-r--r-- | libsolidity/codegen/LValue.cpp | 1 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 4 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 86 |
5 files changed, 133 insertions, 87 deletions
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 8c0d21b1..343a7ea7 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -362,7 +362,6 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons FixedPointType::FixedPointType(int _integerBits, int _fractionalBits, FixedPointType::Modifier _modifier): m_integerBits(_integerBits), m_fractionalBits(_fractionalBits), m_modifier(_modifier) { - cout << "FIXED POINT CONSTRUCTOR: " << _integerBits << "x" << _fractionalBits << endl; solAssert( m_integerBits + m_fractionalBits > 0 && m_integerBits + m_fractionalBits <= 256 && @@ -573,14 +572,6 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const } else if (_convertTo.category() == Category::FixedPoint) { - cout << "IMPLICIT CONVERSION" << endl; - if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo)) - return true; - - return false; - } - else if (_convertTo.category() == Category::FixedPoint) - { if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo)) return true; return false; @@ -588,7 +579,10 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const else if (_convertTo.category() == Category::FixedBytes) { FixedBytesType const& fixedBytes = dynamic_cast<FixedBytesType const&>(_convertTo); - return fixedBytes.numBytes() * 8 >= integerType()->numBits(); + if (m_value.denominator() == 1) + return fixedBytes.numBytes() * 8 >= integerType()->numBits(); + else + return fixedBytes.numBytes() * 8 >= fixedPointType()->numBits(); } return false; } @@ -600,7 +594,6 @@ bool RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const TypePointer intType = integerType(); return intType && intType->isExplicitlyConvertibleTo(_convertTo); } - cout << "EXPLICIT CONVERSION" << endl; TypePointer fixType = fixedPointType(); return fixType && fixType->isExplicitlyConvertibleTo(_convertTo); } @@ -612,7 +605,7 @@ TypePointer RationalNumberType::unaryOperatorResult(Token::Value _operator) cons { case Token::BitNot: if(m_value.denominator() != 1) - BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + return TypePointer(); value = ~m_value.numerator(); break; case Token::Add: @@ -640,7 +633,6 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ } else if (_other->category() == Category::FixedPoint) { - cout << "BINARY OPERATOR RESULTS" << endl; shared_ptr<FixedPointType const> fixType = fixedPointType(); if (!fixType) return TypePointer(); @@ -662,7 +654,6 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ } else { - cout << "BINARY OPERATOR RESULTS PART 2" << endl; shared_ptr<FixedPointType const> thisFixedPointType = fixedPointType(); shared_ptr<FixedPointType const> otherFixedPointType = other.fixedPointType(); if (!thisFixedPointType || !otherFixedPointType) @@ -673,23 +664,23 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ else { rational value; - bool fixedPointType = (m_value.denominator() != 1 || other.m_value.denominator() != 1); + bool fractional = (m_value.denominator() != 1 || other.m_value.denominator() != 1); switch (_operator) { //bit operations will only be enabled for integers and fixed types that resemble integers case Token::BitOr: - if (fixedPointType) - BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + if (fractional) + return TypePointer(); value = m_value.numerator() | other.m_value.numerator(); break; case Token::BitXor: - if (fixedPointType) - BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + if (fractional) + return TypePointer(); value = m_value.numerator() ^ other.m_value.numerator(); break; case Token::BitAnd: - if (fixedPointType) - BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + if (fractional) + return TypePointer(); value = m_value.numerator() & other.m_value.numerator(); break; case Token::Add: @@ -700,7 +691,7 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ break; case Token::Mul: value = m_value * other.m_value; - break; + break; case Token::Div: if (other.m_value == 0) return TypePointer(); @@ -710,19 +701,22 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ case Token::Mod: if (other.m_value == 0) return TypePointer(); - else if (fixedPointType) + else if (fractional) { value = m_value; - rational divisor = m_value / other.m_value; - value -= divisor * m_value; - cout << "MODULO VALUE: " << value << endl; + if (value > other.m_value) + { + do + { + value -= other.m_value; + } while (value > other.m_value); + } } else value = m_value.numerator() % other.m_value.numerator(); break; case Token::Exp: { - cout << "Is this the source of the problem" << endl; bigint newDenominator; bigint newNumerator; if (other.m_value.denominator() != 1) @@ -769,14 +763,17 @@ string RationalNumberType::toString(bool) const u256 RationalNumberType::literalValue(Literal const*) const { u256 value; + unsigned uselessBits = 0; + bigint shiftedValue; + tie(shiftedValue, uselessBits) = findFractionNumberAndBits(); // we ignore the literal and hope that the type was correctly determined - - solAssert(m_value >= -(bigint(1) << 255), "Number constant too small."); + solAssert(shiftedValue <= u256(-1), "Integer constant too large."); + solAssert(shiftedValue >= -(bigint(1) << 255), "Number constant too small."); if (m_value >= 0) - value = u256(m_value.numerator()); + value = u256(shiftedValue); else - value = s2u(s256(m_value.numerator())); + value = s2u(s256(0 - shiftedValue)); return value; } @@ -794,6 +791,7 @@ TypePointer RationalNumberType::mobileType() const return fixType; } +//TODO: combine integerType() and fixedPointType() into one function shared_ptr<IntegerType const> RationalNumberType::integerType() const { bigint value = wholeNumbers(); @@ -813,52 +811,62 @@ shared_ptr<FixedPointType const> RationalNumberType::fixedPointType() const { //do calculations up here bigint integers = wholeNumbers(); - //bigint _remainder = abs(m_value.numerator() % m_value.denominator()); + bigint shiftedValue; + unsigned integerBits = 0; + unsigned fractionalBits = 0; bool fractionalSignBit = integers == 0; //sign the fractional side or the integer side bool negative = (m_value < 0); - //todo: change name - bigint fractionalBits = findFractionNumberAndBits(); - cout << "Total int: " << fractionalBits.str() << endl; + if (negative && !fractionalSignBit) // convert to positive number of same bit requirements { integers = ((0 - integers) - 1) << 1; - fractionalBits = ((0 - fractionalBits) - 1) << 1; + integerBits = max(bytesRequired(integers), 1u) * 8; + tie(shiftedValue, fractionalBits) = findFractionNumberAndBits(integerBits); } else if (negative && fractionalSignBit) - fractionalBits = ((0 - fractionalBits) - 1) << 1; - - if (fractionalBits > u256(-1)) - return shared_ptr<FixedPointType const>(); + tie(shiftedValue, fractionalBits) = findFractionNumberAndBits(); else { - cout << "m_value: " << m_value << endl; - cout << "Total int: " << fractionalBits.str() << endl; - unsigned fractionalBytesRequired = bytesRequired(fractionalBits) * 8; - unsigned integerBytesRequired = bytesRequired(integers) * 8; - cout << "Fractional Bytes Required: " << fractionalBytesRequired << endl; - cout << "Integer Bytes Required: " << integerBytesRequired << endl << endl; + if (!fractionalSignBit) + integerBits = max(bytesRequired(integers), 1u) * 8; + tie(shiftedValue, fractionalBits) = findFractionNumberAndBits(integerBits); + if (shiftedValue == 0 && fractionalSignBit) + { + integerBits = 8; + fractionalBits = 8; + } + } + + if (shiftedValue > u256(-1) || integers > u256(-1)) + return shared_ptr<FixedPointType const>(); + else return make_shared<FixedPointType>( - integerBytesRequired, fractionalBytesRequired, + integerBits, fractionalBits, negative ? FixedPointType::Modifier::Signed : FixedPointType::Modifier::Unsigned ); - } } //todo: change name of function -tuple<bigint, unsigned> RationalNumberType::findFractionNumberAndBits(bool getWholeNumber) const +tuple<bigint, unsigned> RationalNumberType::findFractionNumberAndBits(unsigned const restrictedBits) const { - rational value; - if (getWholeNumber) - value = m_value; - else - value = m_value - wholeNumbers(); - for (unsigned fractionalBits = 0; value < boost::multiprecision::pow(bigint(2), 256); fractionalBits += 8, value *= 10) + bool isNegative = m_value < 0; + rational value = abs(m_value); + unsigned fractionalBits = 0; + for (; fractionalBits <= 256 - restrictedBits; fractionalBits += 8, value *= 256) { if (value.denominator() == 1) return make_tuple(value.numerator(), fractionalBits); - } - cout << "too big :(" << endl; - return make_tuple(value.numerator()/value.denominator(), fractionalBits); + bigint predictionValue = 256 * (value.numerator() / value.denominator()); + if (predictionValue > u256(-1)) + return make_tuple(value.numerator()/value.denominator(), fractionalBits); + predictionValue = ((0 - predictionValue) - 1) << 1; + if (predictionValue > u256(-1) && isNegative) + // essentially asking if its negative and if so will giving it a sign bit value put it over the limit + // if we also multiply it one more time by 256 + return make_tuple(((0 - value.numerator() / value.denominator()) - 1) << 1, fractionalBits); + + } + return make_tuple(value.numerator()/value.denominator(), 256 - restrictedBits); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 84236762..03b6563c 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -385,10 +385,11 @@ public: /// @returns the smallest integer type that can hold the value or an empty pointer if not possible. std::shared_ptr<IntegerType const> integerType() const; - /// @returns the smallest fixed type that can hold the value or an empty pointer + /// @returns the smallest fixed type that can hold the value or incurs the least precision loss. + /// If the integer part does not fit, returns an empty pointer. std::shared_ptr<FixedPointType const> fixedPointType() const; - std::tuple<bigint, unsigned> findFractionNumberAndBits(bool getWholeNumber = false) const; + std::tuple<bigint, unsigned> findFractionNumberAndBits(unsigned const restrictedBits = 0) const; bigint denominator() const { return m_value.denominator(); } bigint wholeNumbers() const { return m_value.numerator() / m_value.denominator(); } diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 7d9fa4c8..1d1956aa 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -243,7 +243,6 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc m_context << Instruction::MUL << Instruction::OR; //else if (m_dataType->category() == Type::Category::Fixed) //trying to figure out what this does...going to require some more assistance - m_context << Instruction::MUL << eth::Instruction::OR; // stack: value storage_ref updated_value m_context << Instruction::SWAP1 << Instruction::SSTORE; if (_move) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index c3bac3d7..67748c1f 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -6634,7 +6634,7 @@ BOOST_AUTO_TEST_CASE(delete_on_array_of_structs) } -BOOST_AUTO_TEST_CASE(fixed_data_type) +/*BOOST_AUTO_TEST_CASE(fixed_data_type) { char const* sourceCode = R"( contract C { @@ -6654,7 +6654,7 @@ BOOST_AUTO_TEST_CASE(fixed_data_type_expression) } )"; compileAndRun(sourceCode, 0, "C"); -} +}*/ BOOST_AUTO_TEST_CASE(internal_library_function) { diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index c3878f3e..a4eec7e6 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -3278,16 +3278,16 @@ BOOST_AUTO_TEST_CASE(invalid_fixed_type_long) BOOST_CHECK(!success(text)); } -BOOST_AUTO_TEST_CASE(valid_fixed_types) +BOOST_AUTO_TEST_CASE(valid_fixed_types_casting) { char const* text = R"( contract test { function f(){ - fixed8x8 a = 87654321.12345678; - fixed16x16 b = a**2; - fixed24x24 c = b**3; - fixed32x32 d = b**2; - fixed40x40 e = a**5; + ufixed8x8 a = ufixed8x8(8765.1234); + ufixed16x16 b = a**2; + ufixed24x24 c = b**3; + ufixed32x32 d = b**2; + ufixed40x40 e = a**5; } } )"; @@ -3310,7 +3310,7 @@ BOOST_AUTO_TEST_CASE(fixed_type_int_conversion) BOOST_CHECK(success(text)); } -BOOST_AUTO_TEST_CASE(fixed_type_const_int_conversion) +BOOST_AUTO_TEST_CASE(fixed_type_rational_conversion) { char const* text = R"( contract test { @@ -3328,8 +3328,8 @@ BOOST_AUTO_TEST_CASE(fixed_type_literal) char const* text = R"( contract test { function f() { - fixed a = 3.14; - ufixed d = 2.555555; + fixed a = 4.5; + ufixed d = 2.5; } } )"; @@ -3341,12 +3341,12 @@ BOOST_AUTO_TEST_CASE(fixed_type_literal_expression) char const* text = R"( contract test { function f() { - fixed a = 3.14 * 3; - ufixed b = 4 - 2.555555; - fixed c = 1.0 / 3.0; - ufixed d = 599 + .5367; - ufixed e = 35.245 % 12.9; - ufixed f = 1.2 % 2.00000; + ufixed8x248 a = 3.14 * 3; + ufixed8x248 b = 4 - 2.555555; + ufixed0x256 c = 1.0 / 3.0; + ufixed16x240 d = 599 + .5367; + ufixed8x248 e = 35.245 % 12.9; + ufixed8x248 f = 1.2 % 2; fixed g = 2 ** -2; } } @@ -3354,6 +3354,19 @@ BOOST_AUTO_TEST_CASE(fixed_type_literal_expression) BOOST_CHECK(success(text)); } +BOOST_AUTO_TEST_CASE(rational_as_exponent_value) +{ + char const* text = R"( + contract test { + function f() { + fixed g = 2 ** -2.2; + fixed b = 3 ** 2.56; + } + } + )"; + BOOST_CHECK(!success(text)); +} + BOOST_AUTO_TEST_CASE(fixed_type_invalid_size_conversion) { char const* text = R"( @@ -3408,7 +3421,7 @@ BOOST_AUTO_TEST_CASE(mapping_with_fixed_literal) { char const* text = R"( contract test { - mapping(fixed => string) fixedString; + mapping(ufixed8x248 => string) fixedString; function f() { fixedString[3.14] = "Pi"; } @@ -3434,7 +3447,7 @@ BOOST_AUTO_TEST_CASE(inline_array_fixed_rationals) char const* text = R"( contract test { function f() { - ufixed8x16[4] memory a = [3.5, 4.1234, 2.5, 4.0]; + ufixed8x248[4] memory a = [3.5, 4.1234, 2.5, 4.0]; } } )"; @@ -3445,8 +3458,8 @@ BOOST_AUTO_TEST_CASE(zero_and_eight_variants_fixed) { char const* text = R"( contract A { - fixed8x0 someInt = 4; - fixed0x8 half = 0.5; + ufixed8x0 someInt = 4; + ufixed0x8 half = 0.5; } )"; BOOST_CHECK(success(text)); @@ -3457,9 +3470,9 @@ BOOST_AUTO_TEST_CASE(size_capabilities_of_fixed_point_types) char const* text = R"( contract test { function f() { - ufixed0x8 a = 0.12345678; - ufixed8x0 b = 12345678.0; - ufixed0x8 c = 0.00000009; + ufixed0x256 a = 0.12345678; + ufixed24x0 b = 12345678.0; + ufixed0x256 c = 0.00000009; } } )"; @@ -3510,13 +3523,38 @@ BOOST_AUTO_TEST_CASE(fixed_point_casting_exponents) BOOST_CHECK(success(text)); } +BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion) +{ + char const* text = R"( + contract test { + function f() { + bytes32 c = 3.183; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(fixed_to_bytes_implicit_conversion) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 3.183; + bytes32 c = a; + } + } + )"; + BOOST_CHECK(!success(text)); +} + BOOST_AUTO_TEST_CASE(rational_unary_operation) { char const* text = R"( contract test { function f() { - fixed a = +3.5134; - fixed b = -2.5145; + ufixed8x248 a = +3.5134; + fixed8x248 b = -3.5134; } } )"; |