mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12708 from nishant-sachdeva/warn_when_rationals_implicitly_converting_to_mobile_type
Document behaviour of ternary operator of literals.
This commit is contained in:
commit
401a0465d7
@ -26,6 +26,23 @@ except for comparison operators where the result is always ``bool``.
|
||||
The operators ``**`` (exponentiation), ``<<`` and ``>>`` use the type of the
|
||||
left operand for the operation and the result.
|
||||
|
||||
Ternary Operator
|
||||
----------------
|
||||
The ternary operator is used in expressions of the form ``<expression> ? <trueExpression> : <falseExpression>``.
|
||||
It evaluates one of the latter two given expressions depending upon the result of the evaluation of the main ``<expression>``.
|
||||
If ``<expression>`` evaluates to ``true``, then ``<trueExpression>`` will be evaluated, otherwise ``<falseExpression>`` is evaluated.
|
||||
|
||||
The result of the ternary operator does not have a rational number type, even if all of its operands are rational number literals.
|
||||
The result type is determined from the types of the two operands in the same way as above, converting to their mobile type first if required.
|
||||
|
||||
As a consequence, ``255 + (true ? 1 : 0)`` will revert due to arithmetic overflow.
|
||||
The reason is that ``(true ? 1 : 0)`` is of ``uint8`` type, which forces the addition to be performed in ``uint8`` as well,
|
||||
and 256 exceeds the range allowed for this type.
|
||||
|
||||
Another consequence is that an expression like ``1.5 + 1.5`` is valid but ``1.5 + (true ? 1.5 : 2.5)`` is not.
|
||||
This is because the former is a rational expression evaluated in unlimited precision and only its final value matters.
|
||||
The latter involves a conversion of a fractional rational number to an integer, which is currently disallowed.
|
||||
|
||||
.. index:: assignment, lvalue, ! compound operators
|
||||
|
||||
Compound and Increment/Decrement Operators
|
||||
|
@ -463,7 +463,7 @@ There is no additional semantic meaning added to a number literal containing und
|
||||
the underscores are ignored.
|
||||
|
||||
Number literal expressions retain arbitrary precision until they are converted to a non-literal type (i.e. by
|
||||
using them together with a non-literal expression or by explicit conversion).
|
||||
using them together with anything else than a number literal expression (like boolean literals) or by explicit conversion).
|
||||
This means that computations do not overflow and divisions do not truncate
|
||||
in number literal expressions.
|
||||
|
||||
@ -471,6 +471,15 @@ For example, ``(2**800 + 1) - 2**800`` results in the constant ``1`` (of type ``
|
||||
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).
|
||||
|
||||
.. warning::
|
||||
While most operators produce a literal expression when applied to literals, there are certain operators that do not follow this pattern:
|
||||
|
||||
- Ternary operator (``... ? ... : ...``),
|
||||
- Array subscript (``<array>[<index>]``).
|
||||
|
||||
You might expect expressions like ``255 + (true ? 1 : 0)`` or ``255 + [1, 2, 3][0]`` to be equivalent to using the literal 256
|
||||
directly, but in fact they are computed within the type ``uint8`` and can overflow.
|
||||
|
||||
Any operator that can be applied to integers can also be applied to number literal expressions as
|
||||
long as the operands 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
|
||||
|
@ -0,0 +1,19 @@
|
||||
contract TestTernary
|
||||
{
|
||||
function h() pure public returns (uint16 b)
|
||||
{
|
||||
b = (true ? 63 : 255) + (false ? 63 : 255);
|
||||
}
|
||||
|
||||
function g() pure public returns (uint16 a)
|
||||
{
|
||||
bool t = true;
|
||||
bool f = false;
|
||||
a = (t ? 63 : 255) + (f ? 63 : 255);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> FAILURE, hex"4e487b71", 0x11
|
||||
// h() -> FAILURE, hex"4e487b71", 0x11
|
@ -0,0 +1,33 @@
|
||||
contract TestTernary
|
||||
{
|
||||
function g() pure public
|
||||
{
|
||||
bool t = true;
|
||||
bool f = false;
|
||||
uint8 v255 = 255;
|
||||
uint8 v63 = 63;
|
||||
uint8 a;
|
||||
|
||||
// Currently none of these should produce errors or warnings.
|
||||
// The result of the operator is always a limited-precision integer, even if all arguments are literals.
|
||||
|
||||
a = (t ? 63 : 255) + (f ? 63 : 255);
|
||||
a = (t ? 0x3f : 0xff) + (f ? 0x3f : 0xff);
|
||||
a = (t ? uint8(63) : 255) + (f ? 63 : uint8(255));
|
||||
a = (t ? v63 : 255) + (f ? 63 : v255);
|
||||
|
||||
a = (true ? 63 : 255) + (false ? 63 : 255);
|
||||
a = (true ? 0x3f : 0xff) + (false ? 0x3f : 0xff);
|
||||
a = (true ? uint8(63) : 255) + (false ? 63 : uint8(255));
|
||||
a = (true ? v63 : 255) + (false ? 63 : v255);
|
||||
|
||||
a = (t ? 63 : 255) - (f ? 63 : 255);
|
||||
a = (t ? 63 : 255) * (f ? 63 : 255);
|
||||
a = (t ? 63 : 255) / (f ? 63 : 255);
|
||||
|
||||
a = (t ? (true ? 63 : 255) : (false ? 63 : 255)) + (f ? (t ? 63 : 255) : (f ? 63 : 255));
|
||||
a = uint8(t ? 63 : 255) + uint8(f ? 63 : 255);
|
||||
|
||||
}
|
||||
}
|
||||
// ----
|
Loading…
Reference in New Issue
Block a user