From 3ba308fb2e4bc910e880431bc708ab4929c7aec2 Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Thu, 12 May 2016 22:10:49 -0500 Subject: current debugging info --- libsolidity/ast/Types.cpp | 22 ++++++++++-- test/libsolidity/SolidityNameAndTypeResolution.cpp | 39 ++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 0df68d3d..ff0db089 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -274,8 +274,18 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const else if (_convertTo.category() == Category::FixedPoint) { FixedPointType const& convertTo = dynamic_cast(_convertTo); + cout << endl; + cout << "Integer bits: " << m_bits << endl; + cout << "Fraction integer bits: " << convertTo.integerBits() << endl; + cout << "Integer signed: " << isSigned() << endl; + cout << "Fractional signed: " << convertTo.isSigned() << endl; + cout << "Unsigned convert?: " << bool(!convertTo.isSigned() || convertTo.integerBits() > m_bits) << endl; + cout << endl; if (convertTo.integerBits() < m_bits || isAddress()) + { + cout << "problem with the integer bits" << endl; return false; + } else if (isSigned()) return convertTo.isSigned(); else @@ -328,13 +338,21 @@ string IntegerType::toString(bool) const TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { - if (_other->category() != Category::RationalNumber && _other->category() != category()) + if ( + _other->category() != Category::RationalNumber && + _other->category() != Category::FixedPoint && + _other->category() != category() + ) return TypePointer(); auto commonType = dynamic_pointer_cast(Type::commonType(shared_from_this(), _other)); if (!commonType) + { + cout << "Not common type" << endl; return TypePointer(); - + } + cout << "Integer binary operator: " << commonType->toString(false) << endl; + cout << "Token: " << string(Token::toString(_operator)) << endl; // All integer types can be compared if (Token::isCompareOp(_operator)) return commonType; diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index d7f7961a..2b67d084 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -3683,6 +3683,45 @@ BOOST_AUTO_TEST_CASE(zero_handling) BOOST_CHECK(success(text)); } +BOOST_AUTO_TEST_CASE(integer_and_fixed_interaction) +{ + char const* text = R"( + contract test { + function f() { + uint128 a = uint128(1) + ufixed(2); + ufixed b = .5 * uint128(7); + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(signed_rational_modulus) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 0.42578125 % -0.4271087646484375; + fixed b = .5 % a; + fixed c = a % b; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(one_divided_by_three_integer_conversion) +{ + char const* text = R"( + contract test { + function f() { + uint a = 1/3; + } + } + )"; + BOOST_CHECK(!success(text)); +} + BOOST_AUTO_TEST_SUITE_END() } -- cgit v1.2.3 From 62894101529fa0ed7c7f566ea02cc805e889c745 Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 13 May 2016 00:38:41 -0500 Subject: explicit conversion and loosening of binary operations on integer and fixed point types...still other problems fixed some spaces and deleted lines from failing test --- libsolidity/ast/Types.cpp | 35 +++++++--------------- test/libsolidity/SolidityNameAndTypeResolution.cpp | 3 +- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index ff0db089..e8ec32dc 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -274,18 +274,8 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const else if (_convertTo.category() == Category::FixedPoint) { FixedPointType const& convertTo = dynamic_cast(_convertTo); - cout << endl; - cout << "Integer bits: " << m_bits << endl; - cout << "Fraction integer bits: " << convertTo.integerBits() << endl; - cout << "Integer signed: " << isSigned() << endl; - cout << "Fractional signed: " << convertTo.isSigned() << endl; - cout << "Unsigned convert?: " << bool(!convertTo.isSigned() || convertTo.integerBits() > m_bits) << endl; - cout << endl; if (convertTo.integerBits() < m_bits || isAddress()) - { - cout << "problem with the integer bits" << endl; return false; - } else if (isSigned()) return convertTo.isSigned(); else @@ -300,7 +290,8 @@ bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const return _convertTo.category() == category() || _convertTo.category() == Category::Contract || _convertTo.category() == Category::Enum || - _convertTo.category() == Category::FixedBytes; + _convertTo.category() == Category::FixedBytes || + _convertTo.category() == Category::FixedPoint; } TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const @@ -344,23 +335,19 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe _other->category() != category() ) return TypePointer(); - auto commonType = dynamic_pointer_cast(Type::commonType(shared_from_this(), _other)); - + auto commonType = Type::commonType(shared_from_this(), _other); //might be a integer or fixed point if (!commonType) - { - cout << "Not common type" << endl; return TypePointer(); - } - cout << "Integer binary operator: " << commonType->toString(false) << endl; - cout << "Token: " << string(Token::toString(_operator)) << endl; + // All integer types can be compared if (Token::isCompareOp(_operator)) return commonType; if (Token::isBooleanOp(_operator)) return TypePointer(); // Nothing else can be done with addresses - if (commonType->isAddress()) - return TypePointer(); + if (auto intType = dynamic_pointer_cast(commonType)) + if (intType->isAddress()) + return TypePointer(); return commonType; } @@ -404,7 +391,6 @@ bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const else return !convertTo.isSigned() || (convertTo.m_integerBits > m_integerBits); } - return false; } @@ -455,7 +441,7 @@ TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePoi && _other->category() != Category::Integer ) return TypePointer(); - auto commonType = dynamic_pointer_cast(Type::commonType(shared_from_this(), _other)); + auto commonType = Type::commonType(shared_from_this(), _other); //might be fixed point or integer if (!commonType) return TypePointer(); @@ -465,8 +451,9 @@ TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePoi return commonType; if (Token::isBitOp(_operator) || Token::isBooleanOp(_operator)) return TypePointer(); - if (Token::Exp == _operator) - return TypePointer(); + if (auto fixType = dynamic_pointer_cast(commonType)) + if (Token::Exp == _operator) + return TypePointer(); return commonType; } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 2b67d084..bbc77d34 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -3688,8 +3688,7 @@ BOOST_AUTO_TEST_CASE(integer_and_fixed_interaction) char const* text = R"( contract test { function f() { - uint128 a = uint128(1) + ufixed(2); - ufixed b = .5 * uint128(7); + ufixed a = uint128(1) + ufixed(2); } } )"; -- cgit v1.2.3 From 919235745263b36bdd7a88374b79f34214b14a5f Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Wed, 18 May 2016 15:53:36 -0500 Subject: updated docs types reference --- docs/types.rst | 56 ++++++++++++++++++++++++++++++++++++++++------- libsolidity/ast/Types.cpp | 17 ++++++++++---- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/docs/types.rst b/docs/types.rst index 93e70ddb..d18a9490 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -52,7 +52,7 @@ Operators: * Arithmetic operators: `+`, `-`, unary `-`, unary `+`, `*`, `/`, `%` (remainder), `**` (exponentiation) Division always truncates (it just maps to the DIV opcode of the EVM), but it does not truncate if both -operators are :ref:`literals` (or literal expressions). +operators are :ref:`literals` (or literal expressions). .. index:: address, balance, send, call, callcode, delegatecall @@ -135,20 +135,60 @@ As a rule of thumb, use `bytes` for arbitrary-length raw byte data and `string` for arbitrary-length string (utf-8) data. If you can limit the length to a certain number of bytes, always use one of `bytes1` to `bytes32` because they are much cheaper. -.. index:: literal, literal;integer +.. index:: ! ufixed, ! fixed, ! fixed point number -.. _integer_literals: +Fixed Point Numbers +------------------- -Integer Literals ------------------ +**bold** COMING SOON... **bold** -Integer Literals are arbitrary precision integers until they are used together with a non-literal. In `var x = 1 - 2;`, for example, the value of `1 - 2` is `-1`, which is assigned to `x` and thus `x` receives the type `int8` -- the smallest type that contains `-1`, although the natural types of `1` and `2` are actually `uint8`. +.. index:: literal, literal;rational -It is even possible to temporarily exceed the maximum of 256 bits as long as only integer literals are used for the computation: `var x = (0xffffffffffffffffffff * 0xffffffffffffffffffff) * 0;` Here, `x` will have the value `0` and thus the type `uint8`. +.. _rational_literals: + +Rational and Integer Literals +----------------------------- + +All number literals retain arbitrary precision until they are converted to a non-literal type (i.e. by +using them together with a non-literal type). This means that computations do not overflow but also +divisions do not truncate. + +For example, `(2**800 + 1) - 2**800` results in the constant `1` (of type `uint8`) +although intermediate results would not even fit the machine word size. Furthermore, `.5 * 8` results +in the integer `4` (although non-integers were used in between). + +If the result is not an integer, +an appropriate `ufixed` or `fixed` type is used whose number of fractional bits is as large as +required (approximating the rational number in the worst case). + +In `var x = 1/4;`, `x` will receive the type `ufixed0x8` while in `var x = 1/3` it will receive +the type `ufixed0x256` because `1/3` is not finitely representable in binary and will thus be +approximated. + +Any operator that can be applied to integers can also be applied to literal expressions as +long as the operators are integers. If any of the two is fractional, bit operations are disallowed +and exponentiation is disallowed if the exponent is fractional (because that might result in +a non-rational number). + +.. note:: + Most finite decimal fractions like `5.3743` are not finitely representable in binary. The correct type + for `5.3743` is `ufixed8x248` because that allows to best approximate the number. If you want to + use the number together with types like `ufixed` (i.e. `ufixed128x128`), you have to explicitly + specify the desired precision: `x + ufixed(5.3743)`. .. warning:: - Divison on integer literals used to truncate in earlier versions, but it will actually convert into a rational number in the future, i.e. `1/2` is not equal to `0`, but to `0.5`. + Division on integer literals used to truncate in earlier versions, but it will now convert into a rational number, i.e. `5 / 2` is not equal to `2`, but to `2.5`. +.. note:: + Literal expressions are converted to a permanent type as soon as they are used with other + expressions. Even though we know that the value of the + expression assigned to `b` in the following example evaluates to an integer, it still + uses fixed point types (and not rational number literals) in between and so the code + does not compile + +:: + uint128 a = 1; + uint128 b = 2.5 + a + 0.5; .. index:: literal, literal;string, string diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index e8ec32dc..d989cb06 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -346,9 +346,13 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe return TypePointer(); // Nothing else can be done with addresses if (auto intType = dynamic_pointer_cast(commonType)) + { if (intType->isAddress()) return TypePointer(); - + } + else if (auto fixType = dynamic_pointer_cast(commonType)) + if (Token::Exp == _operator) + return TypePointer(); return commonType; } @@ -436,9 +440,9 @@ string FixedPointType::toString(bool) const TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { if ( - _other->category() != Category::RationalNumber - && _other->category() != category() - && _other->category() != Category::Integer + _other->category() != Category::RationalNumber && + _other->category() != category() && + _other->category() != Category::Integer ) return TypePointer(); auto commonType = Type::commonType(shared_from_this(), _other); //might be fixed point or integer @@ -452,8 +456,13 @@ TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePoi if (Token::isBitOp(_operator) || Token::isBooleanOp(_operator)) return TypePointer(); if (auto fixType = dynamic_pointer_cast(commonType)) + { if (Token::Exp == _operator) return TypePointer(); + } + else if (auto intType = dynamic_pointer_cast(commonType)) + if (intType->isAddress()) + return TypePointer(); return commonType; } -- cgit v1.2.3