From bfc238c8d11e118443d373d819deeada9fe1ea3b Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Tue, 12 Apr 2016 12:36:34 -0500 Subject: updated algorithm for bit finding...now to figure out literal value tiny fixups changed location of the check got rid of extra space and fixed a couple of things added binary results bits change back literal value --- libsolidity/analysis/ReferencesResolver.cpp | 6 +- libsolidity/analysis/TypeChecker.cpp | 21 ++- libsolidity/ast/Types.cpp | 203 +++++++++------------ libsolidity/ast/Types.h | 8 +- libsolidity/parsing/Token.cpp | 2 +- test/libsolidity/SolidityNameAndTypeResolution.cpp | 7 +- 6 files changed, 103 insertions(+), 144 deletions(-) diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index f4e0f838..9f83971b 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -104,10 +104,8 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName) if (!length->annotation().type) ConstantEvaluator e(*length); auto const* lengthType = dynamic_cast(length->annotation().type.get()); - if (!lengthType) - fatalTypeError(length->location(), "Invalid array length."); - else if (lengthType->denominator() != 1) - fatalTypeError(length->location(), "Invalid input for array length, expected integer."); + if (!lengthType || lengthType->denominator() != 1) + fatalTypeError(length->location(), "Invalid array length, expected integer literal."); else _typeName.annotation().type = make_shared(DataLocation::Storage, baseType, lengthType->literalValue(nullptr)); } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index fb0c665c..1b37d42e 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -774,9 +774,10 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) solAssert(!var.typeName(), ""); if ( valueComponentType->category() == Type::Category::RationalNumber && - !dynamic_pointer_cast(valueComponentType)->integerType() + !dynamic_pointer_cast(valueComponentType)->integerType() && + !dynamic_pointer_cast(valueComponentType)->fixedPointType() ) - fatalTypeError(_statement.initialValue()->location(), "Invalid integer constant " + valueComponentType->toString() + "."); + fatalTypeError(_statement.initialValue()->location(), "Invalid rational " + valueComponentType->toString() + "."); var.annotation().type = valueComponentType->mobileType(); var.accept(*this); } @@ -800,8 +801,11 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) void TypeChecker::endVisit(ExpressionStatement const& _statement) { if (type(_statement.expression())->category() == Type::Category::RationalNumber) - if (!dynamic_pointer_cast(type(_statement.expression()))->integerType()) - typeError(_statement.expression().location(), "Invalid integer constant."); + if ( + !dynamic_pointer_cast(type(_statement.expression()))->integerType() && + !dynamic_pointer_cast(type(_statement.expression()))->fixedPointType() + ) + typeError(_statement.expression().location(), "Invalid rational number."); } bool TypeChecker::visit(Conditional const& _conditional) @@ -1107,8 +1111,8 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) if (functionType->takesArbitraryParameters()) { if (auto t = dynamic_cast(argType.get())) - if (!t->integerType()) - typeError(arguments[i]->location(), "Integer constant too large."); + if (!t->integerType() && !t->fixedPointType()) + typeError(arguments[i]->location(), "Rational number too large."); } else if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i])) typeError( @@ -1343,8 +1347,7 @@ bool TypeChecker::visit(IndexAccess const& _access) expectType(*index, IntegerType(256)); if (auto numberType = dynamic_cast(type(*index).get())) { - if (numberType->denominator() != 1) - typeError(_access.location(), "Invalid type for array access."); + solAssert(!numberType->denominator() != 1 ,"Invalid type for array access."); if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr)) typeError(_access.location(), "Out of bounds array access."); } @@ -1371,7 +1374,7 @@ bool TypeChecker::visit(IndexAccess const& _access) resultType = make_shared(make_shared(DataLocation::Memory, typeType.actualType())); else { - index->accept(*this); + expectType(*index, IntegerType(256)); if (auto length = dynamic_cast(type(*index).get())) resultType = make_shared(make_shared( DataLocation::Memory, diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 366fb6af..865e5969 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -181,10 +181,13 @@ TypePointer Type::forLiteral(Literal const& _literal) case Token::FalseLiteral: return make_shared(); case Token::Number: - if (RationalNumberType::isValidLiteral(_literal)) - return make_shared(_literal); + { + tuple validLiteral = RationalNumberType::isValidLiteral(_literal); + if (get<0>(validLiteral) == true) + return make_shared(get<1>(validLiteral)); else return TypePointer(); + } case Token::StringLiteral: return make_shared(_literal); default: @@ -272,7 +275,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const else if (_convertTo.category() == Category::FixedPoint) { FixedPointType const& convertTo = dynamic_cast(_convertTo); - if (convertTo.integerBits() < m_bits) + if (convertTo.integerBits() < m_bits || isAddress()) return false; else if (isSigned()) return convertTo.isSigned(); @@ -440,7 +443,8 @@ string FixedPointType::toString(bool) const TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { - if (_other->category() != Category::RationalNumber + if ( + _other->category() != Category::RationalNumber && _other->category() != category() && _other->category() != Category::Integer ) @@ -453,22 +457,29 @@ TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePoi // All fixed types can be compared if (Token::isCompareOp(_operator)) return commonType; - if (Token::isBooleanOp(_operator)) + if (Token::isBitOp(_operator) || Token::isBooleanOp(_operator)) return TypePointer(); return commonType; } -bool RationalNumberType::isValidLiteral(Literal const& _literal) +tuple RationalNumberType::isValidLiteral(Literal const& _literal) { + rational x; try { rational numerator; rational denominator(1); + auto radixPoint = find(_literal.value().begin(), _literal.value().end(), '.'); + if (radixPoint != _literal.value().end()) { - //problem here. If the first digit is a 0 in the string, it won't - //turn it into a integer...Using find if not to count the leading 0s. + if ( + !all_of(radixPoint + 1, _literal.value().end(), ::isdigit) || + !all_of(_literal.value().begin(), radixPoint, ::isdigit) + ) + throw; + //Only decimal notation allowed here, leading zeros would switch to octal. auto leadingZeroes = find_if_not( radixPoint + 1, _literal.value().end(), @@ -476,81 +487,55 @@ bool RationalNumberType::isValidLiteral(Literal const& _literal) ); auto fractionalBegin = leadingZeroes != _literal.value().end() ? leadingZeroes : radixPoint + 1; + denominator = bigint(string(fractionalBegin, _literal.value().end())); denominator /= boost::multiprecision::pow( bigint(10), distance(radixPoint + 1, _literal.value().end()) ); numerator = bigint(string(_literal.value().begin(), radixPoint)); - rational x = numerator + denominator; + x = numerator + denominator; } else - rational x = bigint(_literal.value()); + x = bigint(_literal.value()); + switch (_literal.subDenomination()) + { + case Literal::SubDenomination::None: + case Literal::SubDenomination::Wei: + case Literal::SubDenomination::Second: + break; + case Literal::SubDenomination::Szabo: + x *= bigint("1000000000000"); + break; + case Literal::SubDenomination::Finney: + x *= bigint("1000000000000000"); + break; + case Literal::SubDenomination::Ether: + x *= bigint("1000000000000000000"); + break; + case Literal::SubDenomination::Minute: + x *= bigint("60"); + break; + case Literal::SubDenomination::Hour: + x *= bigint("3600"); + break; + case Literal::SubDenomination::Day: + x *= bigint("86400"); + break; + case Literal::SubDenomination::Week: + x *= bigint("604800"); + break; + case Literal::SubDenomination::Year: + x *= bigint("31536000"); + break; + } + } catch (...) { - return false; - } - return true; -} - -RationalNumberType::RationalNumberType(Literal const& _literal) -{ - rational numerator; - rational denominator = bigint(1); - auto radixPoint = find(_literal.value().begin(), _literal.value().end(), '.'); - if (radixPoint != _literal.value().end()) - { - auto leadingZeroes = find_if_not( - radixPoint + 1, - _literal.value().end(), - [](char const& a) { return a == '0'; } - ); - auto fractionalBegin = leadingZeroes != _literal.value().end() ? - leadingZeroes : radixPoint + 1; - //separatly grabbing the numerator, denominator for conversions - denominator = bigint(string(fractionalBegin, _literal.value().end())); - denominator /= boost::multiprecision::pow( - bigint(10), - distance(radixPoint + 1, _literal.value().end()) - ); - numerator = bigint(string(_literal.value().begin(), radixPoint)); - m_value = numerator + denominator; - } - else - m_value = bigint(_literal.value()); - - switch (_literal.subDenomination()) - { - case Literal::SubDenomination::None: - case Literal::SubDenomination::Wei: - case Literal::SubDenomination::Second: - break; - case Literal::SubDenomination::Szabo: - m_value *= bigint("1000000000000"); - break; - case Literal::SubDenomination::Finney: - m_value *= bigint("1000000000000000"); - break; - case Literal::SubDenomination::Ether: - m_value *= bigint("1000000000000000000"); - break; - case Literal::SubDenomination::Minute: - m_value *= bigint("60"); - break; - case Literal::SubDenomination::Hour: - m_value *= bigint("3600"); - break; - case Literal::SubDenomination::Day: - m_value *= bigint("86400"); - break; - case Literal::SubDenomination::Week: - m_value *= bigint("604800"); - break; - case Literal::SubDenomination::Year: - m_value *= bigint("31536000"); - break; + return make_tuple(false, rational(0)); } + return make_tuple(true, x); } bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const @@ -560,19 +545,20 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const auto targetType = dynamic_cast(&_convertTo); if (m_value == 0) return true; + if (m_value.denominator() != 1) + return false; int forSignBit = (targetType->isSigned() ? 1 : 0); if (m_value > 0) { - if (m_value <= (u256(-1) >> (256 - targetType->numBits() + forSignBit))) + if (integerPart() <= (u256(-1) >> (256 - targetType->numBits() + forSignBit))) return true; } - else if (targetType->isSigned() && -m_value <= (u256(1) << (targetType->numBits() - forSignBit))) + else if (targetType->isSigned() && -integerPart() <= (u256(1) << (targetType->numBits() - forSignBit))) return true; return false; } else if (_convertTo.category() == Category::FixedPoint) { - cout << "hit here?" << endl; if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo)) return true; return false; @@ -583,7 +569,7 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const if (m_value.denominator() == 1) return fixedBytes.numBytes() * 8 >= integerType()->numBits(); else - return fixedBytes.numBytes() * 8 >= fixedPointType()->numBits(); + return false; } return false; } @@ -692,7 +678,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(); @@ -758,9 +744,7 @@ string RationalNumberType::toString(bool) const u256 RationalNumberType::literalValue(Literal const*) const { u256 value; - unsigned uselessBits = 0; - bigint shiftedValue; - tie(shiftedValue, uselessBits) = findFractionNumberAndBits(); + bigint shiftedValue = integerPart(); // we ignore the literal and hope that the type was correctly determined solAssert(shiftedValue <= u256(-1), "Integer constant too large."); solAssert(shiftedValue >= -(bigint(1) << 255), "Number constant too small."); @@ -768,8 +752,7 @@ u256 RationalNumberType::literalValue(Literal const*) const if (m_value >= 0) value = u256(shiftedValue); else - value = s2u(s256(0 - shiftedValue)); - + value = s2u(s256(shiftedValue)); return value; } @@ -789,7 +772,7 @@ TypePointer RationalNumberType::mobileType() const //TODO: combine integerType() and fixedPointType() into one function shared_ptr RationalNumberType::integerType() const { - bigint value = wholeNumbers(); + bigint value = integerPart(); bool negative = (value < 0); if (negative) // convert to positive number of same bit requirements value = ((0 - value) - 1) << 1; @@ -806,26 +789,34 @@ shared_ptr RationalNumberType::fixedPointType() const { bool negative = (m_value < 0); unsigned fractionalBits = 0; - unsigned integerBits = bytesRequired(wholeNumbers()) * 8; + unsigned integerBits = 0; rational value = m_value; - bigint l = bigint(1) << 256; - rational maxValue = rational(l); + bigint transitionValue = bigint(1) << 256; + rational maxValue = rational(transitionValue); + if (!negative) + { maxValue -= 1; + integerBits = bytesRequired(integerPart()) * 8; + } else - value = -value; - cout << "Max value: " << maxValue << endl; - while (value * 0x100 <= maxValue && value.denominator() != 1 && fractionalBits < 256 - integerBits) { + value = abs(value); + if (integerPart() > 0) + transitionValue = ((0 - integerPart()) - 1) << 1; + else + transitionValue = 0; + integerBits = bytesRequired(transitionValue) * 8; + } + + while (value * 0x100 <= maxValue && value.denominator() != 1 && fractionalBits < 256 - integerBits) + { value *= 0x100; fractionalBits += 8; } if (value > maxValue) - { - cout << "value > max value " << endl; return shared_ptr(); - } bigint v = value.denominator() / value.numerator(); if (negative) v = -v; @@ -834,12 +825,7 @@ shared_ptr RationalNumberType::fixedPointType() const //if (negative) // convert to positive number of same bit requirements // value = ((0 - value) - 1) << 1; if (value > u256(-1)) - { - cout << "Too large of a number" << endl; return shared_ptr(); - } - - cout << "integer bits: " << integerBits << ", fractionalBits: " << fractionalBits << endl; //solAssert(integerBits >= fractionalBits, "Invalid bit requirement calculation."); //@todo special handling for integerBits == 0 && fractionalBits == 0? return make_shared( @@ -848,31 +834,6 @@ shared_ptr RationalNumberType::fixedPointType() const ); } -//todo: change name of function -tuple RationalNumberType::findFractionNumberAndBits(unsigned const restrictedBits) const -{ - 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); - 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); -} - - - StringLiteralType::StringLiteralType(Literal const& _literal): m_value(_literal.value()) { diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 03b6563c..5e826684 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -363,9 +363,8 @@ public: virtual Category category() const override { return Category::RationalNumber; } /// @returns true if the literal is a valid integer. - static bool isValidLiteral(Literal const& _literal); - - explicit RationalNumberType(Literal const& _literal); + static std::tuple isValidLiteral(Literal const& _literal); + explicit RationalNumberType(rational _value): m_value(_value) {} @@ -389,9 +388,8 @@ public: /// If the integer part does not fit, returns an empty pointer. std::shared_ptr fixedPointType() const; - std::tuple findFractionNumberAndBits(unsigned const restrictedBits = 0) const; bigint denominator() const { return m_value.denominator(); } - bigint wholeNumbers() const { return m_value.numerator() / m_value.denominator(); } + bigint integerPart() const { return m_value.numerator() / m_value.denominator(); } private: rational m_value; diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp index ef817d5d..0ab97988 100644 --- a/libsolidity/parsing/Token.cpp +++ b/libsolidity/parsing/Token.cpp @@ -158,7 +158,7 @@ tuple Token::fromIdentifierOrKeyword(s int n = parseSize(positionX + 1, _literal.end()); if ( 0 <= m && m <= 256 && - 0 <= n && n <= 256 && + 8 <= n && n <= 256 && m + n > 0 && m + n <= 256 && m % 8 == 0 && diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index a4eec7e6..aea2c688 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -3454,11 +3454,10 @@ BOOST_AUTO_TEST_CASE(inline_array_fixed_rationals) BOOST_CHECK(success(text)); } -BOOST_AUTO_TEST_CASE(zero_and_eight_variants_fixed) +BOOST_AUTO_TEST_CASE(zero_and_eight_variant_fixed) { char const* text = R"( contract A { - ufixed8x0 someInt = 4; ufixed0x8 half = 0.5; } )"; @@ -3471,7 +3470,7 @@ BOOST_AUTO_TEST_CASE(size_capabilities_of_fixed_point_types) contract test { function f() { ufixed0x256 a = 0.12345678; - ufixed24x0 b = 12345678.0; + ufixed24x8 b = 12345678.5; ufixed0x256 c = 0.00000009; } } @@ -3532,7 +3531,7 @@ BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion) } } )"; - BOOST_CHECK(success(text)); + BOOST_CHECK(!success(text)); } BOOST_AUTO_TEST_CASE(fixed_to_bytes_implicit_conversion) -- cgit v1.2.3