aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/ast
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/ast')
-rw-r--r--libsolidity/ast/AST.cpp4
-rw-r--r--libsolidity/ast/AST.h2
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp2
-rw-r--r--libsolidity/ast/ExperimentalFeatures.h2
-rw-r--r--libsolidity/ast/Types.cpp149
-rw-r--r--libsolidity/ast/Types.h4
6 files changed, 109 insertions, 54 deletions
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index 80f5d642..16c9b2d2 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -312,7 +312,7 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
case Declaration::Visibility::External:
return {};
default:
- solAssert(false, "visibility() should not return a Visibility");
+ solAssert(false, "visibility() should return a Visibility");
}
}
else
@@ -328,7 +328,7 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
case Declaration::Visibility::External:
return make_shared<FunctionType>(*this, _internal);
default:
- solAssert(false, "visibility() should not return a Visibility");
+ solAssert(false, "visibility() should return a Visibility");
}
}
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index fa0d6921..d703ae53 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -656,7 +656,7 @@ private:
class VariableDeclaration: public Declaration
{
public:
- enum Location { Default, Storage, Memory };
+ enum Location { Default, Storage, Memory, CallData };
VariableDeclaration(
SourceLocation const& _sourceLocation,
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index b8e00b60..b7855668 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -751,6 +751,8 @@ string ASTJsonConverter::location(VariableDeclaration::Location _location)
return "storage";
case VariableDeclaration::Location::Memory:
return "memory";
+ case VariableDeclaration::Location::CallData:
+ return "calldata";
default:
solAssert(false, "Unknown declaration location.");
}
diff --git a/libsolidity/ast/ExperimentalFeatures.h b/libsolidity/ast/ExperimentalFeatures.h
index 30ea7ec5..c66a3659 100644
--- a/libsolidity/ast/ExperimentalFeatures.h
+++ b/libsolidity/ast/ExperimentalFeatures.h
@@ -29,7 +29,7 @@ namespace solidity
enum class ExperimentalFeature
{
- ABIEncoderV2, // new ABI encoder that makes use of JULIA
+ ABIEncoderV2, // new ABI encoder that makes use of Yul
SMTChecker,
V050, // v0.5.0 breaking changes
Test,
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 60e3183c..69124705 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -33,6 +33,8 @@
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/adaptor/sliced.hpp>
@@ -312,22 +314,34 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
TypePointer Type::fromElementaryTypeName(string const& _name)
{
- string name = _name;
- DataLocation location = DataLocation::Storage;
- if (boost::algorithm::ends_with(name, " memory"))
- {
- name = name.substr(0, name.length() - 7);
- location = DataLocation::Memory;
- }
- unsigned short firstNum;
- unsigned short secondNum;
+ vector<string> nameParts;
+ boost::split(nameParts, _name, boost::is_any_of(" "));
+ solAssert(nameParts.size() == 1 || nameParts.size() == 2, "Cannot parse elementary type: " + _name);
Token::Value token;
- tie(token, firstNum, secondNum) = Token::fromIdentifierOrKeyword(name);
+ unsigned short firstNum, secondNum;
+ tie(token, firstNum, secondNum) = Token::fromIdentifierOrKeyword(nameParts[0]);
auto t = fromElementaryTypeName(ElementaryTypeNameToken(token, firstNum, secondNum));
if (auto* ref = dynamic_cast<ReferenceType const*>(t.get()))
+ {
+ DataLocation location = DataLocation::Storage;
+ if (nameParts.size() == 2)
+ {
+ if (nameParts[1] == "storage")
+ location = DataLocation::Storage;
+ else if (nameParts[1] == "calldata")
+ location = DataLocation::CallData;
+ else if (nameParts[1] == "memory")
+ location = DataLocation::Memory;
+ else
+ solAssert(false, "Unknown data location: " + nameParts[1]);
+ }
return ref->copyForLocation(location, true);
+ }
else
+ {
+ solAssert(nameParts.size() == 1, "Storage location suffix only allowed for reference types");
return t;
+ }
}
TypePointer Type::forLiteral(Literal const& _literal)
@@ -476,7 +490,7 @@ 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 && numBits() == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8) ||
_convertTo.category() == Category::FixedPoint;
}
@@ -664,7 +678,7 @@ string FixedPointType::toString(bool) const
bigint FixedPointType::maxIntegerValue() const
{
bigint maxValue = (bigint(1) << (m_totalBits - (isSigned() ? 1 : 0))) - 1;
- return maxValue / pow(bigint(10), m_fractionalDigits);
+ return maxValue / boost::multiprecision::pow(bigint(10), m_fractionalDigits);
}
bigint FixedPointType::minIntegerValue() const
@@ -672,7 +686,7 @@ bigint FixedPointType::minIntegerValue() const
if (isSigned())
{
bigint minValue = -(bigint(1) << (m_totalBits - (isSigned() ? 1 : 0)));
- return minValue / pow(bigint(10), m_fractionalDigits);
+ return minValue / boost::multiprecision::pow(bigint(10), m_fractionalDigits);
}
else
return bigint(0);
@@ -842,49 +856,58 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal
bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
- if (_convertTo.category() == Category::Integer)
+ switch (_convertTo.category())
+ {
+ case Category::Integer:
{
- if (m_value == rational(0))
- return true;
if (isFractional())
return false;
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_convertTo);
+ if (targetType.isAddress())
+ return false;
+ 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;
}
- else if (targetType.isSigned() && -m_value.numerator() <= (u256(1) << (targetType.numBits() - forSignBit)))
- return true;
return false;
}
- else if (_convertTo.category() == Category::FixedPoint)
+ case Category::FixedPoint:
{
if (auto fixed = fixedPointType())
return fixed->isImplicitlyConvertibleTo(_convertTo);
- else
- return false;
+ return false;
}
- else if (_convertTo.category() == Category::FixedBytes)
+ case Category::FixedBytes:
{
FixedBytesType const& fixedBytes = dynamic_cast<FixedBytesType const&>(_convertTo);
- if (!isFractional())
- {
- if (integerType())
- return fixedBytes.numBytes() * 8 >= integerType()->numBits();
- return false;
- }
- else
+ if (isFractional())
return false;
+ if (integerType())
+ return fixedBytes.numBytes() * 8 >= integerType()->numBits();
+ return false;
+ }
+ default:
+ return false;
}
- return false;
}
bool RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
TypePointer mobType = mobileType();
- return mobType && mobType->isExplicitlyConvertibleTo(_convertTo);
+ return
+ (mobType && mobType->isExplicitlyConvertibleTo(_convertTo)) ||
+ (!isFractional() && _convertTo.category() == Category::FixedBytes)
+ ;
}
TypePointer RationalNumberType::unaryOperatorResult(Token::Value _operator) const
@@ -982,10 +1005,9 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
}
else
value = m_value.numerator() % other.m_value.numerator();
- break;
+ break;
case Token::Exp:
{
- using boost::multiprecision::pow;
if (other.isFractional())
return TypePointer();
solAssert(other.m_value.denominator() == 1, "");
@@ -1019,7 +1041,7 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
else if (_base == -1)
return 1 - 2 * int(_exponent & 1);
else
- return pow(_base, _exponent);
+ return boost::multiprecision::pow(_base, _exponent);
};
bigint numerator = optimizedPow(m_value.numerator(), absExp);
@@ -1035,7 +1057,6 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
}
case Token::SHL:
{
- using boost::multiprecision::pow;
if (fractional)
return TypePointer();
else if (other.m_value < 0)
@@ -1049,7 +1070,7 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
uint32_t exponent = other.m_value.numerator().convert_to<uint32_t>();
if (!fitsPrecisionBase2(abs(m_value.numerator()), exponent))
return TypePointer();
- value = m_value.numerator() * pow(bigint(2), exponent);
+ value = m_value.numerator() * boost::multiprecision::pow(bigint(2), exponent);
}
break;
}
@@ -1057,7 +1078,6 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
// determines the resulting type and the type of shift (SAR or SHR).
case Token::SAR:
{
- namespace mp = boost::multiprecision;
if (fractional)
return TypePointer();
else if (other.m_value < 0)
@@ -1069,10 +1089,22 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
else
{
uint32_t exponent = other.m_value.numerator().convert_to<uint32_t>();
- if (exponent > mostSignificantBit(mp::abs(m_value.numerator())))
- value = 0;
+ if (exponent > mostSignificantBit(boost::multiprecision::abs(m_value.numerator())))
+ value = m_value.numerator() < 0 ? -1 : 0;
else
- value = rational(m_value.numerator() / mp::pow(bigint(2), exponent), 1);
+ {
+ if (m_value.numerator() < 0)
+ // Add 1 to the negative value before dividing to get a result that is strictly too large,
+ // then subtract 1 afterwards to round towards negative infinity.
+ // This is the same algorithm as used in ExpressionCompiler::appendShiftOperatorCode(...).
+ // To see this note that for negative x, xor(x,all_ones) = (-x-1) and
+ // therefore xor(div(xor(x,all_ones), exp(2, shift_amount)), all_ones) is
+ // -(-x - 1) / 2^shift_amount - 1, which is the same as
+ // (x + 1) / 2^shift_amount - 1.
+ value = rational((m_value.numerator() + 1) / boost::multiprecision::pow(bigint(2), exponent) - bigint(1), 1);
+ else
+ value = rational(m_value.numerator() / boost::multiprecision::pow(bigint(2), exponent), 1);
+ }
}
break;
}
@@ -1128,7 +1160,7 @@ u256 RationalNumberType::literalValue(Literal const*) const
// its value.
u256 value;
- bigint shiftedValue;
+ bigint shiftedValue;
if (!isFractional())
shiftedValue = m_value.numerator();
@@ -1137,7 +1169,7 @@ u256 RationalNumberType::literalValue(Literal const*) const
auto fixed = fixedPointType();
solAssert(fixed, "");
int fractionalDigits = fixed->fractionalDigits();
- shiftedValue = m_value.numerator() * pow(bigint(10), fractionalDigits) / m_value.denominator();
+ shiftedValue = m_value.numerator() * boost::multiprecision::pow(bigint(10), fractionalDigits) / m_value.denominator();
}
// we ignore the literal and hope that the type was correctly determined
@@ -1180,7 +1212,7 @@ shared_ptr<FixedPointType const> RationalNumberType::fixedPointType() const
bool negative = (m_value < 0);
unsigned fractionalDigits = 0;
rational value = abs(m_value); // We care about the sign later.
- rational maxValue = negative ?
+ rational maxValue = negative ?
rational(bigint(1) << 255, 1):
rational((bigint(1) << 256) - 1, 1);
@@ -1189,7 +1221,7 @@ shared_ptr<FixedPointType const> RationalNumberType::fixedPointType() const
value *= 10;
fractionalDigits++;
}
-
+
if (value > maxValue)
return shared_ptr<FixedPointType const>();
// This means we round towards zero for positive and negative values.
@@ -1281,7 +1313,7 @@ bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const
bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
- return _convertTo.category() == Category::Integer ||
+ return (_convertTo.category() == Category::Integer && numBytes() * 8 == dynamic_cast<IntegerType const&>(_convertTo).numBits()) ||
_convertTo.category() == Category::FixedPoint ||
_convertTo.category() == category();
}
@@ -1358,7 +1390,7 @@ TypePointer BoolType::binaryOperatorResult(Token::Value _operator, TypePointer c
{
if (category() != _other->category())
return TypePointer();
- if (Token::isCompareOp(_operator) || _operator == Token::And || _operator == Token::Or)
+ if (_operator == Token::Equal || _operator == Token::NotEqual || _operator == Token::And || _operator == Token::Or)
return _other;
else
return TypePointer();
@@ -1452,12 +1484,20 @@ string ReferenceType::stringForReferencePart() const
string ReferenceType::identifierLocationSuffix() const
{
string id;
- if (location() == DataLocation::Storage)
+ switch (location())
+ {
+ case DataLocation::Storage:
id += "_storage";
- else if (location() == DataLocation::Memory)
+ break;
+ case DataLocation::Memory:
id += "_memory";
- else
+ break;
+ case DataLocation::CallData:
id += "_calldata";
+ break;
+ default:
+ solAssert(false, "Unknown location returned by location()");
+ }
if (isPointer())
id += "_ptr";
return id;
@@ -1672,6 +1712,7 @@ MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
{
members.push_back({"length", make_shared<IntegerType>(256)});
if (isDynamicallySized() && location() == DataLocation::Storage)
+ {
members.push_back({"push", make_shared<FunctionType>(
TypePointers{baseType()},
TypePointers{make_shared<IntegerType>(256)},
@@ -1679,6 +1720,14 @@ MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
strings{string()},
isByteArray() ? FunctionType::Kind::ByteArrayPush : FunctionType::Kind::ArrayPush
)});
+ members.push_back({"pop", make_shared<FunctionType>(
+ TypePointers{},
+ TypePointers{},
+ strings{string()},
+ strings{string()},
+ FunctionType::Kind::ArrayPop
+ )});
+ }
}
return members;
}
@@ -2495,6 +2544,7 @@ string FunctionType::richIdentifier() const
case Kind::AddMod: id += "addmod"; break;
case Kind::MulMod: id += "mulmod"; break;
case Kind::ArrayPush: id += "arraypush"; break;
+ case Kind::ArrayPop: id += "arraypop"; break;
case Kind::ByteArrayPush: id += "bytearraypush"; break;
case Kind::ObjectCreation: id += "objectcreation"; break;
case Kind::Assert: id += "assert"; break;
@@ -2649,6 +2699,7 @@ unsigned FunctionType::sizeOnStack() const
case Kind::BareDelegateCall:
case Kind::Internal:
case Kind::ArrayPush:
+ case Kind::ArrayPop:
case Kind::ByteArrayPush:
size = 1;
break;
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 95821634..b2f34dee 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -151,7 +151,8 @@ public:
/// @name Factory functions
/// Factory functions that convert an AST @ref TypeName to a Type.
static TypePointer fromElementaryTypeName(ElementaryTypeNameToken const& _type);
- /// Converts a given elementary type name with optional suffix " memory" to a type pointer.
+ /// Converts a given elementary type name with optional data location
+ /// suffix " storage", " calldata" or " memory" to a type pointer. If suffix not given, defaults to " storage".
static TypePointer fromElementaryTypeName(std::string const& _name);
/// @}
@@ -913,6 +914,7 @@ public:
AddMod, ///< ADDMOD
MulMod, ///< MULMOD
ArrayPush, ///< .push() to a dynamically sized array in storage
+ ArrayPop, ///< .pop() from a dynamically sized array in storage
ByteArrayPush, ///< .push() to a dynamically sized byte array in storage
ObjectCreation, ///< array creation using new
Assert, ///< assert()