mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add tests for implcit conversions from literals to fixed-point numbers.
This commit is contained in:
parent
687382ae09
commit
81f703427e
@ -935,30 +935,32 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
var.accept(*this);
|
||||
if (!valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type))
|
||||
{
|
||||
auto errorMsg = "Type " +
|
||||
valueComponentType->toString() +
|
||||
" is not implicitly convertible to expected type " +
|
||||
var.annotation().type->toString();
|
||||
if (
|
||||
valueComponentType->category() == Type::Category::RationalNumber &&
|
||||
dynamic_cast<RationalNumberType const&>(*valueComponentType).isFractional() &&
|
||||
valueComponentType->mobileType()
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
_statement.location(),
|
||||
"Type " +
|
||||
valueComponentType->toString() +
|
||||
" is not implicitly convertible to expected type " +
|
||||
var.annotation().type->toString() +
|
||||
". Try converting to type " +
|
||||
valueComponentType->mobileType()->toString() +
|
||||
" or use an explicit conversion."
|
||||
);
|
||||
{
|
||||
if (var.annotation().type->operator==(*valueComponentType->mobileType()))
|
||||
m_errorReporter.typeError(
|
||||
_statement.location(),
|
||||
errorMsg + ", but it can be explicitly converted."
|
||||
);
|
||||
else
|
||||
m_errorReporter.typeError(
|
||||
_statement.location(),
|
||||
errorMsg +
|
||||
". Try converting to type " +
|
||||
valueComponentType->mobileType()->toString() +
|
||||
" or use an explicit conversion."
|
||||
);
|
||||
}
|
||||
else
|
||||
m_errorReporter.typeError(
|
||||
_statement.location(),
|
||||
"Type " +
|
||||
valueComponentType->toString() +
|
||||
" is not implicitly convertible to expected type " +
|
||||
var.annotation().type->toString() +
|
||||
"."
|
||||
);
|
||||
m_errorReporter.typeError(_statement.location(), errorMsg + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2331,30 +2333,32 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte
|
||||
_expression.accept(*this);
|
||||
if (!type(_expression)->isImplicitlyConvertibleTo(_expectedType))
|
||||
{
|
||||
auto errorMsg = "Type " +
|
||||
type(_expression)->toString() +
|
||||
" is not implicitly convertible to expected type " +
|
||||
_expectedType.toString();
|
||||
if (
|
||||
type(_expression)->category() == Type::Category::RationalNumber &&
|
||||
dynamic_pointer_cast<RationalNumberType const>(type(_expression))->isFractional() &&
|
||||
type(_expression)->mobileType()
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
_expression.location(),
|
||||
"Type " +
|
||||
type(_expression)->toString() +
|
||||
" is not implicitly convertible to expected type " +
|
||||
_expectedType.toString() +
|
||||
". Try converting to type " +
|
||||
type(_expression)->mobileType()->toString() +
|
||||
" or use an explicit conversion."
|
||||
);
|
||||
{
|
||||
if (_expectedType.operator==(*type(_expression)->mobileType()))
|
||||
m_errorReporter.typeError(
|
||||
_expression.location(),
|
||||
errorMsg + ", but it can be explicitly converted."
|
||||
);
|
||||
else
|
||||
m_errorReporter.typeError(
|
||||
_expression.location(),
|
||||
errorMsg +
|
||||
". Try converting to type " +
|
||||
type(_expression)->mobileType()->toString() +
|
||||
" or use an explicit conversion."
|
||||
);
|
||||
}
|
||||
else
|
||||
m_errorReporter.typeError(
|
||||
_expression.location(),
|
||||
"Type " +
|
||||
type(_expression)->toString() +
|
||||
" is not implicitly convertible to expected type " +
|
||||
_expectedType.toString() +
|
||||
"."
|
||||
);
|
||||
m_errorReporter.typeError(_expression.location(), errorMsg + ".");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -125,6 +125,22 @@ bool fitsPrecisionBase2(bigint const& _mantissa, uint32_t _expBase2)
|
||||
return fitsPrecisionBaseX(_mantissa, 1.0, _expBase2);
|
||||
}
|
||||
|
||||
/// Checks whether _value fits into IntegerType _type.
|
||||
bool fitsIntegerType(bigint const& _value, IntegerType const& _type)
|
||||
{
|
||||
return (_type.minValue() <= _value) && (_value <= _type.maxValue());
|
||||
}
|
||||
|
||||
/// Checks whether _value fits into _bits bits when having 1 bit as the sign bit
|
||||
/// if _signed is true.
|
||||
bool fitsIntoBits(bigint const& _value, unsigned _bits, bool _signed)
|
||||
{
|
||||
return fitsIntegerType(_value, IntegerType(
|
||||
_bits,
|
||||
_signed ? IntegerType::Modifier::Signed : IntegerType::Modifier::Unsigned
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void StorageOffsets::computeOffsets(TypePointers const& _types)
|
||||
@ -963,27 +979,21 @@ BoolResult RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo)
|
||||
if (isFractional())
|
||||
return false;
|
||||
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_convertTo);
|
||||
if (m_value == rational(0))
|
||||
return true;
|
||||
unsigned forSignBit = (targetType.isSigned() ? 1 : 0);
|
||||
if (m_value > rational(0))
|
||||
{
|
||||
if (m_value.numerator() <= (u256(-1) >> (256 - targetType.numBits() + forSignBit)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (targetType.isSigned())
|
||||
{
|
||||
if (-m_value.numerator() <= (u256(1) << (targetType.numBits() - forSignBit)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return fitsIntegerType(m_value.numerator(), targetType);
|
||||
}
|
||||
case Category::FixedPoint:
|
||||
{
|
||||
if (auto fixed = fixedPointType())
|
||||
return fixed->isImplicitlyConvertibleTo(_convertTo);
|
||||
return false;
|
||||
FixedPointType const& targetType = dynamic_cast<FixedPointType const&>(_convertTo);
|
||||
// Store a negative number into an unsigned.
|
||||
if (isNegative() && !targetType.isSigned())
|
||||
return false;
|
||||
if (!isFractional())
|
||||
return (targetType.minIntegerValue() <= m_value) && (m_value <= targetType.maxIntegerValue());
|
||||
rational value = m_value * pow(bigint(10), targetType.fractionalDigits());
|
||||
// Need explicit conversion since truncation will occur.
|
||||
if (value.denominator() != 1)
|
||||
return false;
|
||||
return fitsIntoBits(value.numerator(), targetType.numBits(), targetType.isSigned());
|
||||
}
|
||||
case Category::FixedBytes:
|
||||
return (m_value == rational(0)) || (m_compatibleBytesType && *m_compatibleBytesType == _convertTo);
|
||||
|
@ -10,4 +10,5 @@ contract test {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning: (20-707): Function state mutability can be restricted to pure
|
||||
// TypeError: (153-250): Type rational_const 9208...(70 digits omitted)...7637 / 1000...(71 digits omitted)...0000 is not implicitly convertible to expected type ufixed256x77, but it can be explicitly converted.
|
||||
// TypeError: (470-566): Type rational_const -933...(70 digits omitted)...0123 / 1000...(70 digits omitted)...0000 is not implicitly convertible to expected type fixed256x76, but it can be explicitly converted.
|
||||
|
@ -0,0 +1,15 @@
|
||||
contract C {
|
||||
function literalToUFixed() public pure {
|
||||
ufixed8x2 a = 0.10;
|
||||
ufixed8x2 b = 0.00;
|
||||
ufixed8x2 c = 2.55;
|
||||
a; b; c;
|
||||
}
|
||||
function literalToFixed() public pure {
|
||||
fixed8x1 a = 0.1;
|
||||
fixed8x1 b = 12.7;
|
||||
fixed8x1 c = -12.8;
|
||||
a; b; c;
|
||||
}
|
||||
}
|
||||
// ----
|
@ -2,3 +2,4 @@ contract C {
|
||||
fixed8x80 a = -1e-100;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (29-36): Type rational_const -1 / 1000...(93 digits omitted)...0000 is not implicitly convertible to expected type fixed8x80, but it can be explicitly converted.
|
||||
|
Loading…
Reference in New Issue
Block a user