Allow exponentials with signed base and unsigned power.

This commit is contained in:
krk 2019-07-07 17:53:03 +02:00 committed by chriseth
parent c499758cd8
commit 33f7f960cf
10 changed files with 72 additions and 18 deletions

View File

@ -2,6 +2,7 @@
Breaking changes:
* General: Disallow explicit conversions from external function types to ``address`` and add a member called ``address`` to them as replacement.
* Type checker: Resulting type of exponentiation is equal to the type of the base. Also allow signed types for the base.
Language Features:

View File

@ -29,6 +29,10 @@ Semantic and Syntactic Changes
This section highlights changes that affect syntax and semantics.
* The resulting type of an exponentiation is the type of the base. It used to be the smallest type
that can hold both the type of the base and the type of the exponent, as with symmentric
operations. Additionally, signed types are allowed for the base of the exponetation.
How to update your code
=======================

View File

@ -123,8 +123,9 @@ results in the same sign as its left operand (or zero) and ``a % n == -(abs(a) %
Exponentiation
^^^^^^^^^^^^^^
Exponentiation is only available for unsigned types. Please take care that the types
you are using are large enough to hold the result and prepare for potential wrapping behaviour.
Exponentiation is only available for unsigned types in the exponent. The resulting type
of an exponentiation is always equal to the type of the base. Please take care that it is
large enough to hold the result and prepare for potential wrapping behaviour.
.. note::
Note that ``0**0`` is defined by the EVM as ``1``.

View File

@ -1397,6 +1397,23 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
"might overflow. Silence this warning by converting the literal to the "
"expected type."
);
if (
commonType->category() == Type::Category::Integer &&
rightType->category() == Type::Category::Integer &&
dynamic_cast<IntegerType const&>(*commonType).numBits() <
dynamic_cast<IntegerType const&>(*rightType).numBits()
)
m_errorReporter.warning(
_operation.location(),
"The result type of the " +
operation +
" operation is equal to the type of the first operand (" +
commonType->toString() +
") ignoring the (larger) type of the second operand (" +
rightType->toString() +
") which might be unexpected. Silence this warning by either converting "
"the first or the second operand to the type of the other."
);
}
}

View File

@ -600,6 +600,17 @@ TypeResult IntegerType::binaryOperatorResult(Token _operator, Type const* _other
else
return nullptr;
}
else if (Token::Exp == _operator)
{
if (auto otherIntType = dynamic_cast<IntegerType const*>(_other))
{
if (otherIntType->isSigned())
return TypeResult::err("Exponentiation power is not allowed to be a signed integer type.");
}
else if (dynamic_cast<FixedPointType const*>(_other))
return nullptr;
return this;
}
auto commonType = Type::commonType(this, _other); //might be an integer or fixed point
if (!commonType)
@ -610,14 +621,6 @@ TypeResult IntegerType::binaryOperatorResult(Token _operator, Type const* _other
return commonType;
if (TokenTraits::isBooleanOp(_operator))
return nullptr;
if (auto intType = dynamic_cast<IntegerType const*>(commonType))
{
if (Token::Exp == _operator && intType->isSigned())
return TypeResult::err("Exponentiation is not allowed for signed integer types.");
}
else if (dynamic_cast<FixedPointType const*>(commonType))
if (Token::Exp == _operator)
return nullptr;
return commonType;
}

View File

@ -0,0 +1,14 @@
contract test {
function f() public pure returns (int, int) {
int32 x = -3;
uint8 y1;
uint8 y2;
assembly {
y1 := 0x102
y2 := 0x103
}
return (x**y1, x**y2);
}
}
// ----
// f() -> 9, -27

View File

@ -0,0 +1,13 @@
contract test {
function f() public pure returns (uint) {
uint32 x;
uint8 y;
assembly {
x := 0xfffffffffe
y := 0x102
}
return x**y;
}
}
// ----
// f() -> 4

View File

@ -1,3 +1,3 @@
contract test { function() external { uint x = 3; int y = -4; x ** y; } }
// ----
// TypeError: (62-68): Operator ** not compatible with types uint256 and int256
// TypeError: (62-68): Operator ** not compatible with types uint256 and int256. Exponentiation power is not allowed to be a signed integer type.

View File

@ -1,3 +1,5 @@
contract test { function() external { uint x = 3; int y = -4; y ** x; } }
// ----
// TypeError: (62-68): Operator ** not compatible with types int256 and uint256
contract test {
function() external { uint x = 3; int y = -4; y ** x; }
function f() public pure { int16 x = 3; uint8 y = 4; x ** y; }
function g() public pure { int16 x = 3; uint16 y = 4; x ** y; }
}

View File

@ -1,9 +1,8 @@
contract test {
function f() public { int x = 3; int y = 4; x ** y; }
function g() public { int16 x = 3; uint8 y = 4; x ** y; }
function h() public { uint8 x = 3; int16 y = 4; x ** y; }
}
// ----
// TypeError: (64-70): Operator ** not compatible with types int256 and int256. Exponentiation is not allowed for signed integer types.
// TypeError: (126-132): Operator ** not compatible with types int16 and uint8. Exponentiation is not allowed for signed integer types.
// TypeError: (188-194): Operator ** not compatible with types uint8 and int16. Exponentiation is not allowed for signed integer types.
// TypeError: (64-70): Operator ** not compatible with types int256 and int256. Exponentiation power is not allowed to be a signed integer type.
// TypeError: (126-132): Operator ** not compatible with types uint8 and int16. Exponentiation power is not allowed to be a signed integer type.
// Warning: (126-132): The result type of the exponentiation operation is equal to the type of the first operand (uint8) ignoring the (larger) type of the second operand (int16) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.