aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
authorDaniel Kirchner <daniel@ekpyron.org>2018-08-06 20:59:37 +0800
committerDaniel Kirchner <daniel@ekpyron.org>2018-08-13 20:27:01 +0800
commit7d7abeb1496dddfab7eb8705dbfc3d06284cf25d (patch)
tree2909fe73439256e0f77231ec219b1b9af6fefd5a /libsolidity
parent43db88b8363d73ee2f5ffa094ff506414261bd11 (diff)
downloaddexon-solidity-7d7abeb1496dddfab7eb8705dbfc3d06284cf25d.tar.gz
dexon-solidity-7d7abeb1496dddfab7eb8705dbfc3d06284cf25d.tar.zst
dexon-solidity-7d7abeb1496dddfab7eb8705dbfc3d06284cf25d.zip
Disallow ambiguous conversions between number literals and bytesXX types.
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/analysis/TypeChecker.cpp16
-rw-r--r--libsolidity/ast/Types.cpp55
-rw-r--r--libsolidity/ast/Types.h15
3 files changed, 46 insertions, 40 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index bcc3757a..660bb828 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -2348,22 +2348,6 @@ void TypeChecker::expectType(Expression const& _expression, Type const& _expecte
"."
);
}
-
- if (
- type(_expression)->category() == Type::Category::RationalNumber &&
- _expectedType.category() == Type::Category::FixedBytes
- )
- {
- auto literal = dynamic_cast<Literal const*>(&_expression);
-
- if (literal && !literal->isHexNumber())
- m_errorReporter.warning(
- _expression.location(),
- "Decimal literal assigned to bytesXX variable will be left-aligned. "
- "Use an explicit conversion to silence this warning."
- );
- }
-
}
void TypeChecker::requireLValue(Expression const& _expression)
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 2dcfda42..349e4a02 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -355,13 +355,7 @@ TypePointer Type::forLiteral(Literal const& _literal)
case Token::FalseLiteral:
return make_shared<BoolType>();
case Token::Number:
- {
- tuple<bool, rational> validLiteral = RationalNumberType::isValidLiteral(_literal);
- if (get<0>(validLiteral) == true)
- return make_shared<RationalNumberType>(get<1>(validLiteral));
- else
- return TypePointer();
- }
+ return RationalNumberType::forLiteral(_literal);
case Token::StringLiteral:
return make_shared<StringLiteralType>(_literal);
default:
@@ -779,6 +773,30 @@ tuple<bool, rational> RationalNumberType::parseRational(string const& _value)
}
}
+TypePointer RationalNumberType::forLiteral(Literal const& _literal)
+{
+ solAssert(_literal.token() == Token::Number, "");
+ tuple<bool, rational> validLiteral = isValidLiteral(_literal);
+ if (get<0>(validLiteral))
+ {
+ TypePointer compatibleBytesType;
+ if (_literal.isHexNumber())
+ {
+ size_t digitCount = count_if(
+ _literal.value().begin() + 2, // skip "0x"
+ _literal.value().end(),
+ [](unsigned char _c) -> bool { return isxdigit(_c); }
+ );
+ // require even number of digits
+ if (!(digitCount & 1))
+ compatibleBytesType = make_shared<FixedBytesType>(digitCount / 2);
+ }
+
+ return make_shared<RationalNumberType>(get<1>(validLiteral), compatibleBytesType);
+ }
+ return TypePointer();
+}
+
tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal)
{
rational value;
@@ -918,14 +936,7 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return false;
}
case Category::FixedBytes:
- {
- FixedBytesType const& fixedBytes = dynamic_cast<FixedBytesType const&>(_convertTo);
- if (isFractional())
- return false;
- if (integerType())
- return fixedBytes.numBytes() * 8 >= integerType()->numBits();
- return false;
- }
+ return (m_value == rational(0)) || (m_compatibleBytesType && *m_compatibleBytesType == _convertTo);
default:
return false;
}
@@ -933,11 +944,15 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
bool RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
- TypePointer mobType = mobileType();
- return
- (mobType && mobType->isExplicitlyConvertibleTo(_convertTo)) ||
- (!isFractional() && _convertTo.category() == Category::FixedBytes)
- ;
+ if (isImplicitlyConvertibleTo(_convertTo))
+ return true;
+ else if (_convertTo.category() != Category::FixedBytes)
+ {
+ TypePointer mobType = mobileType();
+ return (mobType && mobType->isExplicitlyConvertibleTo(_convertTo));
+ }
+ else
+ return false;
}
TypePointer RationalNumberType::unaryOperatorResult(Token::Value _operator) const
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 3b57109d..8bae3d41 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -423,12 +423,12 @@ public:
virtual Category category() const override { return Category::RationalNumber; }
- /// @returns true if the literal is a valid integer.
- static std::tuple<bool, rational> isValidLiteral(Literal const& _literal);
+ static TypePointer forLiteral(Literal const& _literal);
- explicit RationalNumberType(rational const& _value):
- m_value(_value)
+ explicit RationalNumberType(rational const& _value, TypePointer const& _compatibleBytesType = TypePointer()):
+ m_value(_value), m_compatibleBytesType(_compatibleBytesType)
{}
+
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
@@ -462,6 +462,13 @@ public:
private:
rational m_value;
+ /// Bytes type to which the rational can be explicitly converted.
+ /// Empty for all rationals that are not directly parsed from hex literals.
+ TypePointer m_compatibleBytesType;
+
+ /// @returns true if the literal is a valid integer.
+ static std::tuple<bool, rational> isValidLiteral(Literal const& _literal);
+
/// @returns true if the literal is a valid rational number.
static std::tuple<bool, rational> parseRational(std::string const& _value);