mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Changed occurences of isByteArray() to isByteArrayOrString(). The idea
is to, in a future commit, replace such occurences of isByteArrayOrString() which are required to return True only for Bytes type with a new isByteArray() function.
This commit is contained in:
parent
a05d2b356a
commit
9043621747
@ -441,7 +441,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
|||||||
{
|
{
|
||||||
bool allowed = false;
|
bool allowed = false;
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(type))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(type))
|
||||||
allowed = arrayType->isByteArray();
|
allowed = arrayType->isByteArrayOrString();
|
||||||
if (!allowed)
|
if (!allowed)
|
||||||
m_errorReporter.fatalTypeError(9259_error, _variable.location(), "Only constants of value type and byte array type are implemented.");
|
m_errorReporter.fatalTypeError(9259_error, _variable.location(), "Only constants of value type and byte array type are implemented.");
|
||||||
}
|
}
|
||||||
|
@ -1783,7 +1783,7 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
|
|||||||
(
|
(
|
||||||
(
|
(
|
||||||
resultArrayType->isPointer() ||
|
resultArrayType->isPointer() ||
|
||||||
(argArrayType->isByteArray() && resultArrayType->isByteArray())
|
(argArrayType->isByteArrayOrString() && resultArrayType->isByteArrayOrString())
|
||||||
) &&
|
) &&
|
||||||
resultArrayType->location() == DataLocation::Storage
|
resultArrayType->location() == DataLocation::Storage
|
||||||
),
|
),
|
||||||
@ -1791,7 +1791,7 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
|
|||||||
);
|
);
|
||||||
else
|
else
|
||||||
solAssert(
|
solAssert(
|
||||||
argArrayType->isByteArray() && !argArrayType->isString() && resultType->category() == Type::Category::FixedBytes,
|
argArrayType->isByteArrayOrString() && !argArrayType->isString() && resultType->category() == Type::Category::FixedBytes,
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1206,7 +1206,7 @@ BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo)
|
|||||||
);
|
);
|
||||||
return
|
return
|
||||||
arrayType->location() != DataLocation::CallData &&
|
arrayType->location() != DataLocation::CallData &&
|
||||||
arrayType->isByteArray() &&
|
arrayType->isByteArrayOrString() &&
|
||||||
!(arrayType->dataStoredIn(DataLocation::Storage) && arrayType->isPointer());
|
!(arrayType->dataStoredIn(DataLocation::Storage) && arrayType->isPointer());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1530,7 +1530,7 @@ BoolResult ArrayType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
if (_convertTo.category() != category())
|
if (_convertTo.category() != category())
|
||||||
return false;
|
return false;
|
||||||
auto& convertTo = dynamic_cast<ArrayType const&>(_convertTo);
|
auto& convertTo = dynamic_cast<ArrayType const&>(_convertTo);
|
||||||
if (convertTo.isByteArray() != isByteArray() || convertTo.isString() != isString())
|
if (convertTo.isByteArrayOrString() != isByteArrayOrString() || convertTo.isString() != isString())
|
||||||
return false;
|
return false;
|
||||||
// memory/calldata to storage can be converted, but only to a direct storage reference
|
// memory/calldata to storage can be converted, but only to a direct storage reference
|
||||||
if (convertTo.location() == DataLocation::Storage && location() != DataLocation::Storage && convertTo.isPointer())
|
if (convertTo.location() == DataLocation::Storage && location() != DataLocation::Storage && convertTo.isPointer())
|
||||||
@ -1571,11 +1571,11 @@ BoolResult ArrayType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
return true;
|
return true;
|
||||||
// allow conversion bytes <-> string and bytes -> bytesNN
|
// allow conversion bytes <-> string and bytes -> bytesNN
|
||||||
if (_convertTo.category() != category())
|
if (_convertTo.category() != category())
|
||||||
return isByteArray() && !isString() && _convertTo.category() == Type::Category::FixedBytes;
|
return isByteArrayOrString() && !isString() && _convertTo.category() == Type::Category::FixedBytes;
|
||||||
auto& convertTo = dynamic_cast<ArrayType const&>(_convertTo);
|
auto& convertTo = dynamic_cast<ArrayType const&>(_convertTo);
|
||||||
if (convertTo.location() != location())
|
if (convertTo.location() != location())
|
||||||
return false;
|
return false;
|
||||||
if (!isByteArray() || !convertTo.isByteArray())
|
if (!isByteArrayOrString() || !convertTo.isByteArrayOrString())
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1585,7 +1585,7 @@ string ArrayType::richIdentifier() const
|
|||||||
string id;
|
string id;
|
||||||
if (isString())
|
if (isString())
|
||||||
id = "t_string";
|
id = "t_string";
|
||||||
else if (isByteArray())
|
else if (isByteArrayOrString())
|
||||||
id = "t_bytes";
|
id = "t_bytes";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1608,7 +1608,7 @@ bool ArrayType::operator==(Type const& _other) const
|
|||||||
ArrayType const& other = dynamic_cast<ArrayType const&>(_other);
|
ArrayType const& other = dynamic_cast<ArrayType const&>(_other);
|
||||||
if (
|
if (
|
||||||
!ReferenceType::operator==(other) ||
|
!ReferenceType::operator==(other) ||
|
||||||
other.isByteArray() != isByteArray() ||
|
other.isByteArrayOrString() != isByteArrayOrString() ||
|
||||||
other.isString() != isString() ||
|
other.isString() != isString() ||
|
||||||
other.isDynamicallySized() != isDynamicallySized()
|
other.isDynamicallySized() != isDynamicallySized()
|
||||||
)
|
)
|
||||||
@ -1751,7 +1751,7 @@ string ArrayType::toString(bool _short) const
|
|||||||
string ret;
|
string ret;
|
||||||
if (isString())
|
if (isString())
|
||||||
ret = "string";
|
ret = "string";
|
||||||
else if (isByteArray())
|
else if (isByteArrayOrString())
|
||||||
ret = "bytes";
|
ret = "bytes";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1770,7 +1770,7 @@ string ArrayType::canonicalName() const
|
|||||||
string ret;
|
string ret;
|
||||||
if (isString())
|
if (isString())
|
||||||
ret = "string";
|
ret = "string";
|
||||||
else if (isByteArray())
|
else if (isByteArrayOrString())
|
||||||
ret = "bytes";
|
ret = "bytes";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1784,7 +1784,7 @@ string ArrayType::canonicalName() const
|
|||||||
|
|
||||||
string ArrayType::signatureInExternalFunction(bool _structsByName) const
|
string ArrayType::signatureInExternalFunction(bool _structsByName) const
|
||||||
{
|
{
|
||||||
if (isByteArray())
|
if (isByteArrayOrString())
|
||||||
return canonicalName();
|
return canonicalName();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1899,7 +1899,7 @@ u256 ArrayType::memoryDataSize() const
|
|||||||
{
|
{
|
||||||
solAssert(!isDynamicallySized(), "");
|
solAssert(!isDynamicallySized(), "");
|
||||||
solAssert(m_location == DataLocation::Memory, "");
|
solAssert(m_location == DataLocation::Memory, "");
|
||||||
solAssert(!isByteArray(), "");
|
solAssert(!isByteArrayOrString(), "");
|
||||||
bigint size = bigint(m_length) * m_baseType->memoryHeadSize();
|
bigint size = bigint(m_length) * m_baseType->memoryHeadSize();
|
||||||
solAssert(size <= numeric_limits<u256>::max(), "Array size does not fit u256.");
|
solAssert(size <= numeric_limits<u256>::max(), "Array size does not fit u256.");
|
||||||
return u256(size);
|
return u256(size);
|
||||||
@ -2701,7 +2701,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
|
|||||||
}
|
}
|
||||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType))
|
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType))
|
||||||
{
|
{
|
||||||
if (arrayType->isByteArray())
|
if (arrayType->isByteArrayOrString())
|
||||||
// Return byte arrays as whole.
|
// Return byte arrays as whole.
|
||||||
break;
|
break;
|
||||||
returnType = arrayType->baseType();
|
returnType = arrayType->baseType();
|
||||||
@ -2720,7 +2720,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
|
|||||||
if (member.type->category() != Category::Mapping)
|
if (member.type->category() != Category::Mapping)
|
||||||
{
|
{
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(member.type))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(member.type))
|
||||||
if (!arrayType->isByteArray())
|
if (!arrayType->isByteArrayOrString())
|
||||||
continue;
|
continue;
|
||||||
m_returnParameterTypes.push_back(TypeProvider::withLocationIfReference(
|
m_returnParameterTypes.push_back(TypeProvider::withLocationIfReference(
|
||||||
DataLocation::Memory,
|
DataLocation::Memory,
|
||||||
@ -3813,7 +3813,7 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
|
|||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
auto const* arrayType = dynamic_cast<ArrayType const*>(m_actualType);
|
auto const* arrayType = dynamic_cast<ArrayType const*>(m_actualType);
|
||||||
arrayType && arrayType->isByteArray()
|
arrayType && arrayType->isByteArrayOrString()
|
||||||
)
|
)
|
||||||
members.emplace_back("concat", TypeProvider::function(
|
members.emplace_back("concat", TypeProvider::function(
|
||||||
TypePointers{},
|
TypePointers{},
|
||||||
|
@ -838,7 +838,7 @@ public:
|
|||||||
BoolResult validForLocation(DataLocation _loc) const override;
|
BoolResult validForLocation(DataLocation _loc) const override;
|
||||||
|
|
||||||
/// @returns true if this is a byte array or a string
|
/// @returns true if this is a byte array or a string
|
||||||
bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
|
bool isByteArrayOrString() const { return m_arrayKind != ArrayKind::Ordinary; }
|
||||||
/// @returns true if this is a string
|
/// @returns true if this is a string
|
||||||
bool isString() const { return m_arrayKind == ArrayKind::String; }
|
bool isString() const { return m_arrayKind == ArrayKind::String; }
|
||||||
Type const* baseType() const { solAssert(!!m_baseType, ""); return m_baseType; }
|
Type const* baseType() const { solAssert(!!m_baseType, ""); return m_baseType; }
|
||||||
@ -849,11 +849,11 @@ public:
|
|||||||
std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const override;
|
std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||||
|
|
||||||
/// The offset to advance in calldata to move from one array element to the next.
|
/// The offset to advance in calldata to move from one array element to the next.
|
||||||
unsigned calldataStride() const { return isByteArray() ? 1 : m_baseType->calldataHeadSize(); }
|
unsigned calldataStride() const { return isByteArrayOrString() ? 1 : m_baseType->calldataHeadSize(); }
|
||||||
/// The offset to advance in memory to move from one array element to the next.
|
/// The offset to advance in memory to move from one array element to the next.
|
||||||
unsigned memoryStride() const { return isByteArray() ? 1 : m_baseType->memoryHeadSize(); }
|
unsigned memoryStride() const { return isByteArrayOrString() ? 1 : m_baseType->memoryHeadSize(); }
|
||||||
/// The offset to advance in storage to move from one array element to the next.
|
/// The offset to advance in storage to move from one array element to the next.
|
||||||
unsigned storageStride() const { return isByteArray() ? 1 : m_baseType->storageBytes(); }
|
unsigned storageStride() const { return isByteArrayOrString() ? 1 : m_baseType->storageBytes(); }
|
||||||
|
|
||||||
void clearCache() const override;
|
void clearCache() const override;
|
||||||
|
|
||||||
|
@ -312,7 +312,7 @@ string ABIFunctions::abiEncodingFunction(
|
|||||||
{
|
{
|
||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
if (
|
if (
|
||||||
fromArray->isByteArray() ||
|
fromArray->isByteArrayOrString() ||
|
||||||
*fromArray->baseType() == *TypeProvider::uint256() ||
|
*fromArray->baseType() == *TypeProvider::uint256() ||
|
||||||
*fromArray->baseType() == FixedBytesType(32)
|
*fromArray->baseType() == FixedBytesType(32)
|
||||||
)
|
)
|
||||||
@ -320,7 +320,7 @@ string ABIFunctions::abiEncodingFunction(
|
|||||||
else
|
else
|
||||||
return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options);
|
return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options);
|
||||||
case DataLocation::Memory:
|
case DataLocation::Memory:
|
||||||
if (fromArray->isByteArray())
|
if (fromArray->isByteArrayOrString())
|
||||||
return abiEncodingFunctionMemoryByteArray(*fromArray, *toArray, _options);
|
return abiEncodingFunctionMemoryByteArray(*fromArray, *toArray, _options);
|
||||||
else
|
else
|
||||||
return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options);
|
return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options);
|
||||||
@ -448,7 +448,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
|
|||||||
|
|
||||||
solAssert(fromArrayType.location() == DataLocation::CallData, "");
|
solAssert(fromArrayType.location() == DataLocation::CallData, "");
|
||||||
solAssert(
|
solAssert(
|
||||||
fromArrayType.isByteArray() ||
|
fromArrayType.isByteArrayOrString() ||
|
||||||
*fromArrayType.baseType() == *TypeProvider::uint256() ||
|
*fromArrayType.baseType() == *TypeProvider::uint256() ||
|
||||||
*fromArrayType.baseType() == FixedBytesType(32),
|
*fromArrayType.baseType() == FixedBytesType(32),
|
||||||
""
|
""
|
||||||
@ -468,7 +468,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
|
|||||||
_to.identifier() +
|
_to.identifier() +
|
||||||
_options.toFunctionNameSuffix();
|
_options.toFunctionNameSuffix();
|
||||||
return createFunction(functionName, [&]() {
|
return createFunction(functionName, [&]() {
|
||||||
bool needsPadding = _options.padded && fromArrayType.isByteArray();
|
bool needsPadding = _options.padded && fromArrayType.isByteArrayOrString();
|
||||||
if (fromArrayType.isDynamicallySized())
|
if (fromArrayType.isDynamicallySized())
|
||||||
{
|
{
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
@ -482,7 +482,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
|
|||||||
)");
|
)");
|
||||||
templ("storeLength", arrayStoreLengthForEncodingFunction(toArrayType, _options));
|
templ("storeLength", arrayStoreLengthForEncodingFunction(toArrayType, _options));
|
||||||
templ("functionName", functionName);
|
templ("functionName", functionName);
|
||||||
if (fromArrayType.isByteArray() || fromArrayType.calldataStride() == 1)
|
if (fromArrayType.isByteArrayOrString() || fromArrayType.calldataStride() == 1)
|
||||||
templ("scaleLengthByStride", "");
|
templ("scaleLengthByStride", "");
|
||||||
else
|
else
|
||||||
templ("scaleLengthByStride",
|
templ("scaleLengthByStride",
|
||||||
@ -536,7 +536,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
|
|||||||
|
|
||||||
solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), "");
|
solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), "");
|
||||||
solAssert(_from.length() == _to.length(), "");
|
solAssert(_from.length() == _to.length(), "");
|
||||||
solAssert(!_from.isByteArray(), "");
|
solAssert(!_from.isByteArrayOrString(), "");
|
||||||
if (_from.dataStoredIn(DataLocation::Storage))
|
if (_from.dataStoredIn(DataLocation::Storage))
|
||||||
solAssert(_from.baseType()->storageBytes() > 16, "");
|
solAssert(_from.baseType()->storageBytes() > 16, "");
|
||||||
|
|
||||||
@ -647,10 +647,10 @@ string ABIFunctions::abiEncodingFunctionMemoryByteArray(
|
|||||||
solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), "");
|
solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), "");
|
||||||
solAssert(_from.length() == _to.length(), "");
|
solAssert(_from.length() == _to.length(), "");
|
||||||
solAssert(_from.dataStoredIn(DataLocation::Memory), "");
|
solAssert(_from.dataStoredIn(DataLocation::Memory), "");
|
||||||
solAssert(_from.isByteArray(), "");
|
solAssert(_from.isByteArrayOrString(), "");
|
||||||
|
|
||||||
return createFunction(functionName, [&]() {
|
return createFunction(functionName, [&]() {
|
||||||
solAssert(_to.isByteArray(), "");
|
solAssert(_to.isByteArrayOrString(), "");
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
function <functionName>(value, pos) -> end {
|
function <functionName>(value, pos) -> end {
|
||||||
let length := <lengthFun>(value)
|
let length := <lengthFun>(value)
|
||||||
@ -686,9 +686,9 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
|
|||||||
solAssert(_from.dataStoredIn(DataLocation::Storage), "");
|
solAssert(_from.dataStoredIn(DataLocation::Storage), "");
|
||||||
|
|
||||||
return createFunction(functionName, [&]() {
|
return createFunction(functionName, [&]() {
|
||||||
if (_from.isByteArray())
|
if (_from.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
solAssert(_to.isByteArray(), "");
|
solAssert(_to.isByteArrayOrString(), "");
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
||||||
function <functionName>(value, pos) -> ret {
|
function <functionName>(value, pos) -> ret {
|
||||||
@ -1168,7 +1168,7 @@ string ABIFunctions::abiDecodingFunctionArray(ArrayType const& _type, bool _from
|
|||||||
string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _type, bool _fromMemory)
|
string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _type, bool _fromMemory)
|
||||||
{
|
{
|
||||||
solAssert(_type.dataStoredIn(DataLocation::Memory), "");
|
solAssert(_type.dataStoredIn(DataLocation::Memory), "");
|
||||||
if (_type.isByteArray())
|
if (_type.isByteArrayOrString())
|
||||||
return abiDecodingFunctionByteArrayAvailableLength(_type, _fromMemory);
|
return abiDecodingFunctionByteArrayAvailableLength(_type, _fromMemory);
|
||||||
solAssert(_type.calldataStride() > 0, "");
|
solAssert(_type.calldataStride() > 0, "");
|
||||||
|
|
||||||
@ -1275,7 +1275,7 @@ string ABIFunctions::abiDecodingFunctionCalldataArray(ArrayType const& _type)
|
|||||||
string ABIFunctions::abiDecodingFunctionByteArrayAvailableLength(ArrayType const& _type, bool _fromMemory)
|
string ABIFunctions::abiDecodingFunctionByteArrayAvailableLength(ArrayType const& _type, bool _fromMemory)
|
||||||
{
|
{
|
||||||
solAssert(_type.dataStoredIn(DataLocation::Memory), "");
|
solAssert(_type.dataStoredIn(DataLocation::Memory), "");
|
||||||
solAssert(_type.isByteArray(), "");
|
solAssert(_type.isByteArrayOrString(), "");
|
||||||
|
|
||||||
string functionName =
|
string functionName =
|
||||||
"abi_decode_available_length_" +
|
"abi_decode_available_length_" +
|
||||||
|
@ -50,8 +50,8 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
solAssert(_targetType.location() == DataLocation::Storage, "");
|
solAssert(_targetType.location() == DataLocation::Storage, "");
|
||||||
|
|
||||||
Type const* uint256 = TypeProvider::uint256();
|
Type const* uint256 = TypeProvider::uint256();
|
||||||
Type const* targetBaseType = _targetType.isByteArray() ? uint256 : _targetType.baseType();
|
Type const* targetBaseType = _targetType.isByteArrayOrString() ? uint256 : _targetType.baseType();
|
||||||
Type const* sourceBaseType = _sourceType.isByteArray() ? uint256 : _sourceType.baseType();
|
Type const* sourceBaseType = _sourceType.isByteArrayOrString() ? uint256 : _sourceType.baseType();
|
||||||
|
|
||||||
// TODO unroll loop for small sizes
|
// TODO unroll loop for small sizes
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
// stack: target_ref source_ref source_length target_ref target_length
|
// stack: target_ref source_ref source_length target_ref target_length
|
||||||
if (_targetType.isDynamicallySized())
|
if (_targetType.isDynamicallySized())
|
||||||
// store new target length
|
// store new target length
|
||||||
if (!_targetType.isByteArray())
|
if (!_targetType.isByteArrayOrString())
|
||||||
// Otherwise, length will be stored below.
|
// Otherwise, length will be stored below.
|
||||||
_context << Instruction::DUP3 << Instruction::DUP3 << Instruction::SSTORE;
|
_context << Instruction::DUP3 << Instruction::DUP3 << Instruction::SSTORE;
|
||||||
if (sourceBaseType->category() == Type::Category::Mapping)
|
if (sourceBaseType->category() == Type::Category::Mapping)
|
||||||
@ -126,7 +126,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
evmasm::AssemblyItem copyLoopEndWithoutByteOffset = _context.newTag();
|
evmasm::AssemblyItem copyLoopEndWithoutByteOffset = _context.newTag();
|
||||||
|
|
||||||
// special case for short byte arrays: Store them together with their length.
|
// special case for short byte arrays: Store them together with their length.
|
||||||
if (_targetType.isByteArray())
|
if (_targetType.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
// stack: target_ref target_data_end source_length target_data_pos source_ref
|
// stack: target_ref target_data_end source_length target_data_pos source_ref
|
||||||
_context << Instruction::DUP3;
|
_context << Instruction::DUP3;
|
||||||
@ -141,7 +141,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
_context << Instruction::DUP3 << u256(31) << Instruction::LT;
|
_context << Instruction::DUP3 << u256(31) << Instruction::LT;
|
||||||
evmasm::AssemblyItem longByteArray = _context.appendConditionalJump();
|
evmasm::AssemblyItem longByteArray = _context.appendConditionalJump();
|
||||||
// store the short byte array
|
// store the short byte array
|
||||||
solAssert(_sourceType.isByteArray(), "");
|
solAssert(_sourceType.isByteArrayOrString(), "");
|
||||||
if (_sourceType.location() == DataLocation::Storage)
|
if (_sourceType.location() == DataLocation::Storage)
|
||||||
{
|
{
|
||||||
// just copy the slot, it contains length and data
|
// just copy the slot, it contains length and data
|
||||||
@ -323,7 +323,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
{
|
{
|
||||||
if (!_sourceType.isDynamicallySized())
|
if (!_sourceType.isDynamicallySized())
|
||||||
m_context << _sourceType.length();
|
m_context << _sourceType.length();
|
||||||
if (!_sourceType.isByteArray())
|
if (!_sourceType.isByteArrayOrString())
|
||||||
convertLengthToSize(_sourceType);
|
convertLengthToSize(_sourceType);
|
||||||
|
|
||||||
string routine = "calldatacopy(target, source, len)\n";
|
string routine = "calldatacopy(target, source, len)\n";
|
||||||
@ -375,14 +375,14 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
m_context << Instruction::SWAP1 << u256(32) << Instruction::ADD;
|
m_context << Instruction::SWAP1 << u256(32) << Instruction::ADD;
|
||||||
m_context << Instruction::SWAP1;
|
m_context << Instruction::SWAP1;
|
||||||
}
|
}
|
||||||
if (!_sourceType.isByteArray())
|
if (!_sourceType.isByteArrayOrString())
|
||||||
convertLengthToSize(_sourceType);
|
convertLengthToSize(_sourceType);
|
||||||
// stack: <target> <source> <size>
|
// stack: <target> <source> <size>
|
||||||
m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::DUP4;
|
m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::DUP4;
|
||||||
// We can resort to copying full 32 bytes only if
|
// We can resort to copying full 32 bytes only if
|
||||||
// - the length is known to be a multiple of 32 or
|
// - the length is known to be a multiple of 32 or
|
||||||
// - we will pad to full 32 bytes later anyway.
|
// - we will pad to full 32 bytes later anyway.
|
||||||
if (!_sourceType.isByteArray() || _padToWordBoundaries)
|
if (!_sourceType.isByteArrayOrString() || _padToWordBoundaries)
|
||||||
utils.memoryCopy32();
|
utils.memoryCopy32();
|
||||||
else
|
else
|
||||||
utils.memoryCopy();
|
utils.memoryCopy();
|
||||||
@ -390,7 +390,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||||
// stack: <target> <size>
|
// stack: <target> <size>
|
||||||
|
|
||||||
bool paddingNeeded = _padToWordBoundaries && _sourceType.isByteArray();
|
bool paddingNeeded = _padToWordBoundaries && _sourceType.isByteArrayOrString();
|
||||||
|
|
||||||
if (paddingNeeded)
|
if (paddingNeeded)
|
||||||
{
|
{
|
||||||
@ -446,7 +446,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||||
evmasm::AssemblyItem loopEnd = m_context.appendConditionalJump();
|
evmasm::AssemblyItem loopEnd = m_context.appendConditionalJump();
|
||||||
// Special case for tightly-stored byte arrays
|
// Special case for tightly-stored byte arrays
|
||||||
if (_sourceType.isByteArray())
|
if (_sourceType.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
// stack here: memory_offset storage_offset length
|
// stack here: memory_offset storage_offset length
|
||||||
m_context << Instruction::DUP1 << u256(31) << Instruction::LT;
|
m_context << Instruction::DUP1 << u256(31) << Instruction::LT;
|
||||||
@ -482,14 +482,14 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stack here: memory_end_offset storage_data_offset memory_offset
|
// stack here: memory_end_offset storage_data_offset memory_offset
|
||||||
bool haveByteOffset = !_sourceType.isByteArray() && storageBytes <= 16;
|
bool haveByteOffset = !_sourceType.isByteArrayOrString() && storageBytes <= 16;
|
||||||
if (haveByteOffset)
|
if (haveByteOffset)
|
||||||
m_context << u256(0) << Instruction::SWAP1;
|
m_context << u256(0) << Instruction::SWAP1;
|
||||||
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
|
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
|
||||||
evmasm::AssemblyItem loopStart = m_context.newTag();
|
evmasm::AssemblyItem loopStart = m_context.newTag();
|
||||||
m_context << loopStart;
|
m_context << loopStart;
|
||||||
// load and store
|
// load and store
|
||||||
if (_sourceType.isByteArray())
|
if (_sourceType.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
// Packed both in storage and memory.
|
// Packed both in storage and memory.
|
||||||
m_context << Instruction::DUP2 << Instruction::SLOAD;
|
m_context << Instruction::DUP2 << Instruction::SLOAD;
|
||||||
@ -528,12 +528,12 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
|
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
|
||||||
if (haveByteOffset)
|
if (haveByteOffset)
|
||||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||||
if (!_sourceType.isByteArray())
|
if (!_sourceType.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
solAssert(_sourceType.calldataStride() % 32 == 0, "");
|
solAssert(_sourceType.calldataStride() % 32 == 0, "");
|
||||||
solAssert(_sourceType.memoryStride() % 32 == 0, "");
|
solAssert(_sourceType.memoryStride() % 32 == 0, "");
|
||||||
}
|
}
|
||||||
if (_padToWordBoundaries && _sourceType.isByteArray())
|
if (_padToWordBoundaries && _sourceType.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
// memory_end_offset - start is the actual length (we want to compute the ceil of).
|
// memory_end_offset - start is the actual length (we want to compute the ceil of).
|
||||||
// memory_offset - start is its next multiple of 32, but it might be off by 32.
|
// memory_offset - start is its next multiple of 32, but it might be off by 32.
|
||||||
@ -624,7 +624,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
|
|||||||
m_context << u256(0) << Instruction::DUP3 << Instruction::SSTORE;
|
m_context << u256(0) << Instruction::DUP3 << Instruction::SSTORE;
|
||||||
// Special case: short byte arrays are stored togeher with their length
|
// Special case: short byte arrays are stored togeher with their length
|
||||||
evmasm::AssemblyItem endTag = m_context.newTag();
|
evmasm::AssemblyItem endTag = m_context.newTag();
|
||||||
if (_type.isByteArray())
|
if (_type.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
// stack: ref old_length
|
// stack: ref old_length
|
||||||
m_context << Instruction::DUP1 << u256(31) << Instruction::LT;
|
m_context << Instruction::DUP1 << u256(31) << Instruction::LT;
|
||||||
@ -664,7 +664,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
|||||||
ArrayType const& _type = dynamic_cast<ArrayType const&>(*type);
|
ArrayType const& _type = dynamic_cast<ArrayType const&>(*type);
|
||||||
solAssert(_type.location() == DataLocation::Storage, "");
|
solAssert(_type.location() == DataLocation::Storage, "");
|
||||||
solAssert(_type.isDynamicallySized(), "");
|
solAssert(_type.isDynamicallySized(), "");
|
||||||
if (!_type.isByteArray() && _type.baseType()->storageBytes() < 32)
|
if (!_type.isByteArrayOrString() && _type.baseType()->storageBytes() < 32)
|
||||||
solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type.");
|
solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type.");
|
||||||
|
|
||||||
unsigned stackHeightStart = _context.stackHeight();
|
unsigned stackHeightStart = _context.stackHeight();
|
||||||
@ -677,7 +677,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
|||||||
solAssert(_context.stackHeight() - stackHeightStart == 3 - 2, "2");
|
solAssert(_context.stackHeight() - stackHeightStart == 3 - 2, "2");
|
||||||
|
|
||||||
// Special case for short byte arrays, they are stored together with their length
|
// Special case for short byte arrays, they are stored together with their length
|
||||||
if (_type.isByteArray())
|
if (_type.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
evmasm::AssemblyItem regularPath = _context.newTag();
|
evmasm::AssemblyItem regularPath = _context.newTag();
|
||||||
// We start by a large case-distinction about the old and new length of the byte array.
|
// We start by a large case-distinction about the old and new length of the byte array.
|
||||||
@ -766,7 +766,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
|||||||
// stack: ref new_length old_length
|
// stack: ref new_length old_length
|
||||||
// store new length
|
// store new length
|
||||||
_context << Instruction::DUP2;
|
_context << Instruction::DUP2;
|
||||||
if (_type.isByteArray())
|
if (_type.isByteArrayOrString())
|
||||||
// For a "long" byte array, store length as 2*length+1
|
// For a "long" byte array, store length as 2*length+1
|
||||||
_context << Instruction::DUP1 << Instruction::ADD << u256(1) << Instruction::ADD;
|
_context << Instruction::DUP1 << Instruction::ADD << u256(1) << Instruction::ADD;
|
||||||
_context << Instruction::DUP4 << Instruction::SSTORE;
|
_context << Instruction::DUP4 << Instruction::SSTORE;
|
||||||
@ -806,10 +806,10 @@ void ArrayUtils::incrementDynamicArraySize(ArrayType const& _type) const
|
|||||||
{
|
{
|
||||||
solAssert(_type.location() == DataLocation::Storage, "");
|
solAssert(_type.location() == DataLocation::Storage, "");
|
||||||
solAssert(_type.isDynamicallySized(), "");
|
solAssert(_type.isDynamicallySized(), "");
|
||||||
if (!_type.isByteArray() && _type.baseType()->storageBytes() < 32)
|
if (!_type.isByteArrayOrString() && _type.baseType()->storageBytes() < 32)
|
||||||
solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type.");
|
solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type.");
|
||||||
|
|
||||||
if (_type.isByteArray())
|
if (_type.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
// We almost always just add 2 (length of byte arrays is shifted left by one)
|
// We almost always just add 2 (length of byte arrays is shifted left by one)
|
||||||
// except for the case where we transition from a short byte array
|
// except for the case where we transition from a short byte array
|
||||||
@ -850,10 +850,10 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
|
|||||||
{
|
{
|
||||||
solAssert(_type.location() == DataLocation::Storage, "");
|
solAssert(_type.location() == DataLocation::Storage, "");
|
||||||
solAssert(_type.isDynamicallySized(), "");
|
solAssert(_type.isDynamicallySized(), "");
|
||||||
if (!_type.isByteArray() && _type.baseType()->storageBytes() < 32)
|
if (!_type.isByteArrayOrString() && _type.baseType()->storageBytes() < 32)
|
||||||
solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type.");
|
solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type.");
|
||||||
|
|
||||||
if (_type.isByteArray())
|
if (_type.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
m_context << Instruction::DUP1 << Instruction::SLOAD << Instruction::DUP1;
|
m_context << Instruction::DUP1 << Instruction::SLOAD << Instruction::DUP1;
|
||||||
m_context.callYulFunction(m_context.utilFunctions().extractByteArrayLengthFunction(), 1, 1);
|
m_context.callYulFunction(m_context.utilFunctions().extractByteArrayLengthFunction(), 1, 1);
|
||||||
@ -999,7 +999,7 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!_arrayType.isByteArray())
|
if (!_arrayType.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
if (_arrayType.location() == DataLocation::Memory)
|
if (_arrayType.location() == DataLocation::Memory)
|
||||||
m_context << _arrayType.memoryStride();
|
m_context << _arrayType.memoryStride();
|
||||||
@ -1031,7 +1031,7 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType, unsigned _stackDept
|
|||||||
break;
|
break;
|
||||||
case DataLocation::Storage:
|
case DataLocation::Storage:
|
||||||
m_context << Instruction::SLOAD;
|
m_context << Instruction::SLOAD;
|
||||||
if (_arrayType.isByteArray())
|
if (_arrayType.isByteArrayOrString())
|
||||||
m_context.callYulFunction(m_context.utilFunctions().extractByteArrayLengthFunction(), 1, 1);
|
m_context.callYulFunction(m_context.utilFunctions().extractByteArrayLengthFunction(), 1, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1062,7 +1062,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b
|
|||||||
{
|
{
|
||||||
case DataLocation::Memory:
|
case DataLocation::Memory:
|
||||||
// stack: <base_ref> <index>
|
// stack: <base_ref> <index>
|
||||||
if (!_arrayType.isByteArray())
|
if (!_arrayType.isByteArrayOrString())
|
||||||
m_context << u256(_arrayType.memoryHeadSize()) << Instruction::MUL;
|
m_context << u256(_arrayType.memoryHeadSize()) << Instruction::MUL;
|
||||||
if (_arrayType.isDynamicallySized())
|
if (_arrayType.isDynamicallySized())
|
||||||
m_context << u256(32) << Instruction::ADD;
|
m_context << u256(32) << Instruction::ADD;
|
||||||
@ -1071,7 +1071,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b
|
|||||||
m_context << Instruction::ADD;
|
m_context << Instruction::ADD;
|
||||||
break;
|
break;
|
||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
if (!_arrayType.isByteArray())
|
if (!_arrayType.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
m_context << _arrayType.calldataStride();
|
m_context << _arrayType.calldataStride();
|
||||||
m_context << Instruction::MUL;
|
m_context << Instruction::MUL;
|
||||||
@ -1090,7 +1090,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b
|
|||||||
// stack: [<base_ref>] <index> <base_ref>
|
// stack: [<base_ref>] <index> <base_ref>
|
||||||
|
|
||||||
evmasm::AssemblyItem endTag = m_context.newTag();
|
evmasm::AssemblyItem endTag = m_context.newTag();
|
||||||
if (_arrayType.isByteArray())
|
if (_arrayType.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
// Special case of short byte arrays.
|
// Special case of short byte arrays.
|
||||||
m_context << Instruction::SWAP1;
|
m_context << Instruction::SWAP1;
|
||||||
@ -1153,7 +1153,7 @@ void ArrayUtils::accessCallDataArrayElement(ArrayType const& _arrayType, bool _d
|
|||||||
{
|
{
|
||||||
solAssert(_arrayType.baseType()->storageBytes() <= 32, "");
|
solAssert(_arrayType.baseType()->storageBytes() <= 32, "");
|
||||||
if (
|
if (
|
||||||
!_arrayType.isByteArray() &&
|
!_arrayType.isByteArrayOrString() &&
|
||||||
_arrayType.baseType()->storageBytes() < 32 &&
|
_arrayType.baseType()->storageBytes() < 32 &&
|
||||||
m_context.useABICoderV2()
|
m_context.useABICoderV2()
|
||||||
)
|
)
|
||||||
@ -1165,7 +1165,7 @@ void ArrayUtils::accessCallDataArrayElement(ArrayType const& _arrayType, bool _d
|
|||||||
CompilerUtils(m_context).loadFromMemoryDynamic(
|
CompilerUtils(m_context).loadFromMemoryDynamic(
|
||||||
*_arrayType.baseType(),
|
*_arrayType.baseType(),
|
||||||
true,
|
true,
|
||||||
!_arrayType.isByteArray(),
|
!_arrayType.isByteArrayOrString(),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -970,7 +970,7 @@ void CompilerUtils::convertType(
|
|||||||
else if (targetTypeCategory == Type::Category::Array)
|
else if (targetTypeCategory == Type::Category::Array)
|
||||||
{
|
{
|
||||||
auto const& arrayType = dynamic_cast<ArrayType const&>(_targetType);
|
auto const& arrayType = dynamic_cast<ArrayType const&>(_targetType);
|
||||||
solAssert(arrayType.isByteArray());
|
solAssert(arrayType.isByteArrayOrString());
|
||||||
size_t storageSize = 32 + ((data.size() + 31) / 32) * 32;
|
size_t storageSize = 32 + ((data.size() + 31) / 32) * 32;
|
||||||
allocateMemory(storageSize);
|
allocateMemory(storageSize);
|
||||||
// stack: mempos
|
// stack: mempos
|
||||||
@ -992,7 +992,7 @@ void CompilerUtils::convertType(
|
|||||||
if (_targetType.category() == Type::Category::FixedBytes)
|
if (_targetType.category() == Type::Category::FixedBytes)
|
||||||
{
|
{
|
||||||
solAssert(
|
solAssert(
|
||||||
typeOnStack.isByteArray() && !typeOnStack.isString(),
|
typeOnStack.isByteArrayOrString() && !typeOnStack.isString(),
|
||||||
"Array types other than bytes not convertible to bytesNN."
|
"Array types other than bytes not convertible to bytesNN."
|
||||||
);
|
);
|
||||||
solAssert(typeOnStack.isDynamicallySized());
|
solAssert(typeOnStack.isDynamicallySized());
|
||||||
@ -1019,7 +1019,7 @@ void CompilerUtils::convertType(
|
|||||||
case DataLocation::Storage:
|
case DataLocation::Storage:
|
||||||
// Other cases are done explicitly in LValue::storeValue, and only possible by assignment.
|
// Other cases are done explicitly in LValue::storeValue, and only possible by assignment.
|
||||||
solAssert(
|
solAssert(
|
||||||
(targetType.isPointer() || (typeOnStack.isByteArray() && targetType.isByteArray())) &&
|
(targetType.isPointer() || (typeOnStack.isByteArrayOrString() && targetType.isByteArrayOrString())) &&
|
||||||
typeOnStack.location() == DataLocation::Storage,
|
typeOnStack.location() == DataLocation::Storage,
|
||||||
"Invalid conversion to storage type."
|
"Invalid conversion to storage type."
|
||||||
);
|
);
|
||||||
@ -1105,7 +1105,7 @@ void CompilerUtils::convertType(
|
|||||||
}
|
}
|
||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
solAssert(
|
solAssert(
|
||||||
((targetType.isByteArray() && typeOnStack.isByteArray()) || _typeOnStack == _targetType) &&
|
((targetType.isByteArrayOrString() && typeOnStack.isByteArrayOrString()) || _typeOnStack == _targetType) &&
|
||||||
typeOnStack.location() == DataLocation::CallData,
|
typeOnStack.location() == DataLocation::CallData,
|
||||||
"Invalid conversion to calldata type."
|
"Invalid conversion to calldata type."
|
||||||
);
|
);
|
||||||
@ -1119,7 +1119,7 @@ void CompilerUtils::convertType(
|
|||||||
if (_targetType.category() == Type::Category::FixedBytes)
|
if (_targetType.category() == Type::Category::FixedBytes)
|
||||||
{
|
{
|
||||||
solAssert(
|
solAssert(
|
||||||
typeOnStack.arrayType().isByteArray() && !typeOnStack.arrayType().isString(),
|
typeOnStack.arrayType().isByteArrayOrString() && !typeOnStack.arrayType().isString(),
|
||||||
"Array types other than bytes not convertible to bytesNN."
|
"Array types other than bytes not convertible to bytesNN."
|
||||||
);
|
);
|
||||||
solAssert(typeOnStack.isDynamicallySized());
|
solAssert(typeOnStack.isDynamicallySized());
|
||||||
@ -1142,7 +1142,7 @@ void CompilerUtils::convertType(
|
|||||||
auto const& targetArrayType = dynamic_cast<ArrayType const&>(_targetType);
|
auto const& targetArrayType = dynamic_cast<ArrayType const&>(_targetType);
|
||||||
solAssert(
|
solAssert(
|
||||||
typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType) ||
|
typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType) ||
|
||||||
(typeOnStack.arrayType().isByteArray() && targetArrayType.isByteArray())
|
(typeOnStack.arrayType().isByteArrayOrString() && targetArrayType.isByteArrayOrString())
|
||||||
);
|
);
|
||||||
solAssert(
|
solAssert(
|
||||||
typeOnStack.arrayType().dataStoredIn(DataLocation::CallData) &&
|
typeOnStack.arrayType().dataStoredIn(DataLocation::CallData) &&
|
||||||
|
@ -153,7 +153,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
if (paramTypes[i]->isDynamicallySized())
|
if (paramTypes[i]->isDynamicallySized())
|
||||||
{
|
{
|
||||||
solAssert(
|
solAssert(
|
||||||
dynamic_cast<ArrayType const&>(*paramTypes[i]).isByteArray(),
|
dynamic_cast<ArrayType const&>(*paramTypes[i]).isByteArrayOrString(),
|
||||||
"Expected string or byte array for mapping key type"
|
"Expected string or byte array for mapping key type"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
if (returnTypes[i]->category() == Type::Category::Mapping)
|
if (returnTypes[i]->category() == Type::Category::Mapping)
|
||||||
continue;
|
continue;
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]))
|
||||||
if (!arrayType->isByteArray())
|
if (!arrayType->isByteArrayOrString())
|
||||||
continue;
|
continue;
|
||||||
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
|
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
|
||||||
m_context << Instruction::DUP1 << u256(offsets.first) << Instruction::ADD << u256(offsets.second);
|
m_context << Instruction::DUP1 << u256(offsets.first) << Instruction::ADD << u256(offsets.second);
|
||||||
@ -1047,7 +1047,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
// stack: ArrayReference (newLength-1)
|
// stack: ArrayReference (newLength-1)
|
||||||
ArrayUtils(m_context).accessIndex(*arrayType, false);
|
ArrayUtils(m_context).accessIndex(*arrayType, false);
|
||||||
|
|
||||||
if (arrayType->isByteArray())
|
if (arrayType->isByteArrayOrString())
|
||||||
setLValue<StorageByteArrayElement>(_functionCall);
|
setLValue<StorageByteArrayElement>(_functionCall);
|
||||||
else
|
else
|
||||||
setLValueToStorageItem(_functionCall);
|
setLValueToStorageItem(_functionCall);
|
||||||
@ -1084,7 +1084,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
utils().moveToStackTop(1 + type->sizeOnStack());
|
utils().moveToStackTop(1 + type->sizeOnStack());
|
||||||
utils().moveToStackTop(1 + type->sizeOnStack());
|
utils().moveToStackTop(1 + type->sizeOnStack());
|
||||||
// stack: argValue storageSlot slotOffset
|
// stack: argValue storageSlot slotOffset
|
||||||
if (!arrayType->isByteArray())
|
if (!arrayType->isByteArrayOrString())
|
||||||
StorageItem(m_context, *paramType).storeValue(*type, _functionCall.location(), true);
|
StorageItem(m_context, *paramType).storeValue(*type, _functionCall.location(), true);
|
||||||
else
|
else
|
||||||
StorageByteArrayElement(m_context).storeValue(*type, _functionCall.location(), true);
|
StorageByteArrayElement(m_context).storeValue(*type, _functionCall.location(), true);
|
||||||
@ -1165,7 +1165,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
// update free memory pointer
|
// update free memory pointer
|
||||||
m_context << Instruction::DUP1;
|
m_context << Instruction::DUP1;
|
||||||
// Stack: memptr requested_length requested_length
|
// Stack: memptr requested_length requested_length
|
||||||
if (arrayType.isByteArray())
|
if (arrayType.isByteArrayOrString())
|
||||||
// Round up to multiple of 32
|
// Round up to multiple of 32
|
||||||
m_context << u256(31) << Instruction::ADD << u256(31) << Instruction::NOT << Instruction::AND;
|
m_context << u256(31) << Instruction::ADD << u256(31) << Instruction::NOT << Instruction::AND;
|
||||||
else
|
else
|
||||||
@ -2086,7 +2086,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
|||||||
{
|
{
|
||||||
case DataLocation::Storage:
|
case DataLocation::Storage:
|
||||||
ArrayUtils(m_context).accessIndex(arrayType);
|
ArrayUtils(m_context).accessIndex(arrayType);
|
||||||
if (arrayType.isByteArray())
|
if (arrayType.isByteArrayOrString())
|
||||||
{
|
{
|
||||||
solAssert(!arrayType.isString(), "Index access to string is not allowed.");
|
solAssert(!arrayType.isString(), "Index access to string is not allowed.");
|
||||||
setLValue<StorageByteArrayElement>(_indexAccess);
|
setLValue<StorageByteArrayElement>(_indexAccess);
|
||||||
@ -2096,7 +2096,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
|||||||
break;
|
break;
|
||||||
case DataLocation::Memory:
|
case DataLocation::Memory:
|
||||||
ArrayUtils(m_context).accessIndex(arrayType);
|
ArrayUtils(m_context).accessIndex(arrayType);
|
||||||
setLValue<MemoryItem>(_indexAccess, *_indexAccess.annotation().type, !arrayType.isByteArray());
|
setLValue<MemoryItem>(_indexAccess, *_indexAccess.annotation().type, !arrayType.isByteArrayOrString());
|
||||||
break;
|
break;
|
||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
ArrayUtils(m_context).accessCallDataArrayElement(arrayType);
|
ArrayUtils(m_context).accessCallDataArrayElement(arrayType);
|
||||||
|
@ -1183,8 +1183,8 @@ string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type)
|
|||||||
w("calldata", _type.location() == DataLocation::CallData);
|
w("calldata", _type.location() == DataLocation::CallData);
|
||||||
if (_type.location() == DataLocation::Storage)
|
if (_type.location() == DataLocation::Storage)
|
||||||
{
|
{
|
||||||
w("byteArray", _type.isByteArray());
|
w("byteArray", _type.isByteArrayOrString());
|
||||||
if (_type.isByteArray())
|
if (_type.isByteArrayOrString())
|
||||||
w("extractByteArrayLength", extractByteArrayLengthFunction());
|
w("extractByteArrayLength", extractByteArrayLengthFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1220,7 +1220,7 @@ std::string YulUtilFunctions::resizeArrayFunction(ArrayType const& _type)
|
|||||||
solAssert(_type.location() == DataLocation::Storage, "");
|
solAssert(_type.location() == DataLocation::Storage, "");
|
||||||
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32);
|
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32);
|
||||||
|
|
||||||
if (_type.isByteArray())
|
if (_type.isByteArrayOrString())
|
||||||
return resizeDynamicByteArrayFunction(_type);
|
return resizeDynamicByteArrayFunction(_type);
|
||||||
|
|
||||||
string functionName = "resize_array_" + _type.identifier();
|
string functionName = "resize_array_" + _type.identifier();
|
||||||
@ -1259,7 +1259,7 @@ string YulUtilFunctions::cleanUpStorageArrayEndFunction(ArrayType const& _type)
|
|||||||
{
|
{
|
||||||
solAssert(_type.location() == DataLocation::Storage, "");
|
solAssert(_type.location() == DataLocation::Storage, "");
|
||||||
solAssert(_type.baseType()->category() != Type::Category::Mapping, "");
|
solAssert(_type.baseType()->category() != Type::Category::Mapping, "");
|
||||||
solAssert(!_type.isByteArray(), "");
|
solAssert(!_type.isByteArrayOrString(), "");
|
||||||
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32);
|
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32);
|
||||||
|
|
||||||
string functionName = "cleanup_storage_array_end_" + _type.identifier();
|
string functionName = "cleanup_storage_array_end_" + _type.identifier();
|
||||||
@ -1319,7 +1319,7 @@ string YulUtilFunctions::resizeDynamicByteArrayFunction(ArrayType const& _type)
|
|||||||
|
|
||||||
string YulUtilFunctions::cleanUpDynamicByteArrayEndSlotsFunction(ArrayType const& _type)
|
string YulUtilFunctions::cleanUpDynamicByteArrayEndSlotsFunction(ArrayType const& _type)
|
||||||
{
|
{
|
||||||
solAssert(_type.isByteArray(), "");
|
solAssert(_type.isByteArrayOrString(), "");
|
||||||
solAssert(_type.isDynamicallySized(), "");
|
solAssert(_type.isDynamicallySized(), "");
|
||||||
|
|
||||||
string functionName = "clean_up_bytearray_end_slots_" + _type.identifier();
|
string functionName = "clean_up_bytearray_end_slots_" + _type.identifier();
|
||||||
@ -1479,7 +1479,7 @@ string YulUtilFunctions::storageArrayPopFunction(ArrayType const& _type)
|
|||||||
solAssert(_type.location() == DataLocation::Storage, "");
|
solAssert(_type.location() == DataLocation::Storage, "");
|
||||||
solAssert(_type.isDynamicallySized(), "");
|
solAssert(_type.isDynamicallySized(), "");
|
||||||
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "Base type is not yet implemented.");
|
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "Base type is not yet implemented.");
|
||||||
if (_type.isByteArray())
|
if (_type.isByteArrayOrString())
|
||||||
return storageByteArrayPopFunction(_type);
|
return storageByteArrayPopFunction(_type);
|
||||||
|
|
||||||
string functionName = "array_pop_" + _type.identifier();
|
string functionName = "array_pop_" + _type.identifier();
|
||||||
@ -1509,7 +1509,7 @@ string YulUtilFunctions::storageByteArrayPopFunction(ArrayType const& _type)
|
|||||||
{
|
{
|
||||||
solAssert(_type.location() == DataLocation::Storage, "");
|
solAssert(_type.location() == DataLocation::Storage, "");
|
||||||
solAssert(_type.isDynamicallySized(), "");
|
solAssert(_type.isDynamicallySized(), "");
|
||||||
solAssert(_type.isByteArray(), "");
|
solAssert(_type.isByteArrayOrString(), "");
|
||||||
|
|
||||||
string functionName = "byte_array_pop_" + _type.identifier();
|
string functionName = "byte_array_pop_" + _type.identifier();
|
||||||
return m_functionCollector.createFunction(functionName, [&]() {
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
@ -1566,7 +1566,7 @@ string YulUtilFunctions::storageArrayPushFunction(ArrayType const& _type, Type c
|
|||||||
return m_functionCollector.createFunction(functionName, [&]() {
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>(array <values>) {
|
function <functionName>(array <values>) {
|
||||||
<?isByteArray>
|
<?isByteArrayOrString>
|
||||||
let data := sload(array)
|
let data := sload(array)
|
||||||
let oldLen := <extractByteArrayLength>(data)
|
let oldLen := <extractByteArrayLength>(data)
|
||||||
if iszero(lt(oldLen, <maxArrayLength>)) { <panic>() }
|
if iszero(lt(oldLen, <maxArrayLength>)) { <panic>() }
|
||||||
@ -1598,20 +1598,20 @@ string YulUtilFunctions::storageArrayPushFunction(ArrayType const& _type, Type c
|
|||||||
let slot, offset := <indexAccess>(array, oldLen)
|
let slot, offset := <indexAccess>(array, oldLen)
|
||||||
<storeValue>(slot, offset <values>)
|
<storeValue>(slot, offset <values>)
|
||||||
}
|
}
|
||||||
<!isByteArray>
|
<!isByteArrayOrString>
|
||||||
let oldLen := sload(array)
|
let oldLen := sload(array)
|
||||||
if iszero(lt(oldLen, <maxArrayLength>)) { <panic>() }
|
if iszero(lt(oldLen, <maxArrayLength>)) { <panic>() }
|
||||||
sstore(array, add(oldLen, 1))
|
sstore(array, add(oldLen, 1))
|
||||||
let slot, offset := <indexAccess>(array, oldLen)
|
let slot, offset := <indexAccess>(array, oldLen)
|
||||||
<storeValue>(slot, offset <values>)
|
<storeValue>(slot, offset <values>)
|
||||||
</isByteArray>
|
</isByteArrayOrString>
|
||||||
})")
|
})")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("values", _fromType->sizeOnStack() == 0 ? "" : ", " + suffixedVariableNameList("value", 0, _fromType->sizeOnStack()))
|
("values", _fromType->sizeOnStack() == 0 ? "" : ", " + suffixedVariableNameList("value", 0, _fromType->sizeOnStack()))
|
||||||
("panic", panicFunction(PanicCode::ResourceError))
|
("panic", panicFunction(PanicCode::ResourceError))
|
||||||
("extractByteArrayLength", _type.isByteArray() ? extractByteArrayLengthFunction() : "")
|
("extractByteArrayLength", _type.isByteArrayOrString() ? extractByteArrayLengthFunction() : "")
|
||||||
("dataAreaFunction", arrayDataAreaFunction(_type))
|
("dataAreaFunction", arrayDataAreaFunction(_type))
|
||||||
("isByteArray", _type.isByteArray())
|
("isByteArrayOrString", _type.isByteArrayOrString())
|
||||||
("indexAccess", storageArrayIndexAccessFunction(_type))
|
("indexAccess", storageArrayIndexAccessFunction(_type))
|
||||||
("storeValue", updateStorageValueFunction(*_fromType, *_type.baseType()))
|
("storeValue", updateStorageValueFunction(*_fromType, *_type.baseType()))
|
||||||
("maxArrayLength", (u256(1) << 64).str())
|
("maxArrayLength", (u256(1) << 64).str())
|
||||||
@ -1642,9 +1642,9 @@ string YulUtilFunctions::storageArrayPushZeroFunction(ArrayType const& _type)
|
|||||||
slot, offset := <indexAccess>(array, oldLen)
|
slot, offset := <indexAccess>(array, oldLen)
|
||||||
})")
|
})")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("isBytes", _type.isByteArray())
|
("isBytes", _type.isByteArrayOrString())
|
||||||
("increaseBytesSize", _type.isByteArray() ? increaseByteArraySizeFunction(_type) : "")
|
("increaseBytesSize", _type.isByteArrayOrString() ? increaseByteArraySizeFunction(_type) : "")
|
||||||
("extractLength", _type.isByteArray() ? extractByteArrayLengthFunction() : "")
|
("extractLength", _type.isByteArrayOrString() ? extractByteArrayLengthFunction() : "")
|
||||||
("panic", panicFunction(PanicCode::ResourceError))
|
("panic", panicFunction(PanicCode::ResourceError))
|
||||||
("fetchLength", arrayLengthFunction(_type))
|
("fetchLength", arrayLengthFunction(_type))
|
||||||
("indexAccess", storageArrayIndexAccessFunction(_type))
|
("indexAccess", storageArrayIndexAccessFunction(_type))
|
||||||
@ -1795,7 +1795,7 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType,
|
|||||||
if (!_toType.isDynamicallySized())
|
if (!_toType.isDynamicallySized())
|
||||||
solAssert(!_fromType.isDynamicallySized() && _fromType.length() <= _toType.length(), "");
|
solAssert(!_fromType.isDynamicallySized() && _fromType.length() <= _toType.length(), "");
|
||||||
|
|
||||||
if (_fromType.isByteArray())
|
if (_fromType.isByteArrayOrString())
|
||||||
return copyByteArrayToStorageFunction(_fromType, _toType);
|
return copyByteArrayToStorageFunction(_fromType, _toType);
|
||||||
if (_fromType.dataStoredIn(DataLocation::Storage) && _toType.baseType()->isValueType())
|
if (_fromType.dataStoredIn(DataLocation::Storage) && _toType.baseType()->isValueType())
|
||||||
return copyValueArrayStorageToStorageFunction(_fromType, _toType);
|
return copyValueArrayStorageToStorageFunction(_fromType, _toType);
|
||||||
@ -1902,8 +1902,8 @@ string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _fromTy
|
|||||||
*_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast<ReferenceType const&>(_toType),
|
*_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast<ReferenceType const&>(_toType),
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
solAssert(_fromType.isByteArray(), "");
|
solAssert(_fromType.isByteArrayOrString(), "");
|
||||||
solAssert(_toType.isByteArray(), "");
|
solAssert(_toType.isByteArrayOrString(), "");
|
||||||
|
|
||||||
string functionName = "copy_byte_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier();
|
string functionName = "copy_byte_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier();
|
||||||
return m_functionCollector.createFunction(functionName, [&](){
|
return m_functionCollector.createFunction(functionName, [&](){
|
||||||
@ -1980,8 +1980,8 @@ string YulUtilFunctions::copyValueArrayStorageToStorageFunction(ArrayType const&
|
|||||||
solAssert(_toType.baseType()->isValueType(), "");
|
solAssert(_toType.baseType()->isValueType(), "");
|
||||||
solAssert(_fromType.baseType()->isImplicitlyConvertibleTo(*_toType.baseType()), "");
|
solAssert(_fromType.baseType()->isImplicitlyConvertibleTo(*_toType.baseType()), "");
|
||||||
|
|
||||||
solAssert(!_fromType.isByteArray(), "");
|
solAssert(!_fromType.isByteArrayOrString(), "");
|
||||||
solAssert(!_toType.isByteArray(), "");
|
solAssert(!_toType.isByteArrayOrString(), "");
|
||||||
solAssert(_fromType.dataStoredIn(DataLocation::Storage), "");
|
solAssert(_fromType.dataStoredIn(DataLocation::Storage), "");
|
||||||
solAssert(_toType.dataStoredIn(DataLocation::Storage), "");
|
solAssert(_toType.dataStoredIn(DataLocation::Storage), "");
|
||||||
|
|
||||||
@ -2155,7 +2155,7 @@ string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type)
|
|||||||
})")
|
})")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("stride", to_string(_type.location() == DataLocation::Memory ? _type.memoryStride() : _type.calldataStride()))
|
("stride", to_string(_type.location() == DataLocation::Memory ? _type.memoryStride() : _type.calldataStride()))
|
||||||
("byteArray", _type.isByteArray())
|
("byteArray", _type.isByteArrayOrString())
|
||||||
("mul", overflowCheckedIntMulFunction(*TypeProvider::uint256()))
|
("mul", overflowCheckedIntMulFunction(*TypeProvider::uint256()))
|
||||||
.render();
|
.render();
|
||||||
default:
|
default:
|
||||||
@ -2187,7 +2187,7 @@ string YulUtilFunctions::arrayAllocationSizeFunction(ArrayType const& _type)
|
|||||||
)");
|
)");
|
||||||
w("functionName", functionName);
|
w("functionName", functionName);
|
||||||
w("panic", panicFunction(PanicCode::ResourceError));
|
w("panic", panicFunction(PanicCode::ResourceError));
|
||||||
w("byteArray", _type.isByteArray());
|
w("byteArray", _type.isByteArrayOrString());
|
||||||
w("roundUp", roundUpFunction());
|
w("roundUp", roundUpFunction());
|
||||||
w("dynamic", _type.isDynamicallySized());
|
w("dynamic", _type.isDynamicallySized());
|
||||||
return w.render();
|
return w.render();
|
||||||
@ -2262,7 +2262,7 @@ string YulUtilFunctions::storageArrayIndexAccessFunction(ArrayType const& _type)
|
|||||||
("dataAreaFunc", arrayDataAreaFunction(_type))
|
("dataAreaFunc", arrayDataAreaFunction(_type))
|
||||||
("indexAccessNoChecks", longByteArrayStorageIndexAccessNoCheckFunction())
|
("indexAccessNoChecks", longByteArrayStorageIndexAccessNoCheckFunction())
|
||||||
("multipleItemsPerSlot", _type.baseType()->storageBytes() <= 16)
|
("multipleItemsPerSlot", _type.baseType()->storageBytes() <= 16)
|
||||||
("isBytesArray", _type.isByteArray())
|
("isBytesArray", _type.isByteArrayOrString())
|
||||||
("storageSize", _type.baseType()->storageSize().str())
|
("storageSize", _type.baseType()->storageSize().str())
|
||||||
("storageBytes", toString(_type.baseType()->storageBytes()))
|
("storageBytes", toString(_type.baseType()->storageBytes()))
|
||||||
("itemsPerSlot", to_string(32 / _type.baseType()->storageBytes()))
|
("itemsPerSlot", to_string(32 / _type.baseType()->storageBytes()))
|
||||||
@ -2376,7 +2376,7 @@ string YulUtilFunctions::accessCalldataTailFunction(Type const& _type)
|
|||||||
|
|
||||||
string YulUtilFunctions::nextArrayElementFunction(ArrayType const& _type)
|
string YulUtilFunctions::nextArrayElementFunction(ArrayType const& _type)
|
||||||
{
|
{
|
||||||
solAssert(!_type.isByteArray(), "");
|
solAssert(!_type.isByteArrayOrString(), "");
|
||||||
if (_type.dataStoredIn(DataLocation::Storage))
|
if (_type.dataStoredIn(DataLocation::Storage))
|
||||||
solAssert(_type.baseType()->storageBytes() > 16, "");
|
solAssert(_type.baseType()->storageBytes() > 16, "");
|
||||||
string functionName = "array_nextElement_" + _type.identifier();
|
string functionName = "array_nextElement_" + _type.identifier();
|
||||||
@ -2447,7 +2447,7 @@ string YulUtilFunctions::copyArrayFromStorageToMemoryFunction(ArrayType const& _
|
|||||||
solAssert(_to.memoryStride() == 32, "");
|
solAssert(_to.memoryStride() == 32, "");
|
||||||
solAssert(_to.baseType()->dataStoredIn(DataLocation::Memory), "");
|
solAssert(_to.baseType()->dataStoredIn(DataLocation::Memory), "");
|
||||||
solAssert(_from.baseType()->dataStoredIn(DataLocation::Storage), "");
|
solAssert(_from.baseType()->dataStoredIn(DataLocation::Storage), "");
|
||||||
solAssert(!_from.isByteArray(), "");
|
solAssert(!_from.isByteArrayOrString(), "");
|
||||||
solAssert(*_to.withLocation(DataLocation::Storage, _from.isPointer()) == _from, "");
|
solAssert(*_to.withLocation(DataLocation::Storage, _from.isPointer()) == _from, "");
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>(slot) -> memPtr {
|
function <functionName>(slot) -> memPtr {
|
||||||
@ -2755,7 +2755,7 @@ string YulUtilFunctions::updateStorageValueFunction(
|
|||||||
solAssert(_fromType.category() == Type::Category::StringLiteral, "");
|
solAssert(_fromType.category() == Type::Category::StringLiteral, "");
|
||||||
solAssert(toReferenceType->category() == Type::Category::Array, "");
|
solAssert(toReferenceType->category() == Type::Category::Array, "");
|
||||||
auto const& toArrayType = dynamic_cast<ArrayType const&>(*toReferenceType);
|
auto const& toArrayType = dynamic_cast<ArrayType const&>(*toReferenceType);
|
||||||
solAssert(toArrayType.isByteArray(), "");
|
solAssert(toArrayType.isByteArrayOrString(), "");
|
||||||
|
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>(slot<?dynamicOffset>, offset</dynamicOffset>) {
|
function <functionName>(slot<?dynamicOffset>, offset</dynamicOffset>) {
|
||||||
@ -3216,7 +3216,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
auto const& fromType = dynamic_cast<ArraySliceType const&>(_from);
|
auto const& fromType = dynamic_cast<ArraySliceType const&>(_from);
|
||||||
if (_to.category() == Type::Category::FixedBytes)
|
if (_to.category() == Type::Category::FixedBytes)
|
||||||
{
|
{
|
||||||
solAssert(fromType.arrayType().isByteArray(), "Array types other than bytes not convertible to bytesNN.");
|
solAssert(fromType.arrayType().isByteArrayOrString(), "Array types other than bytes not convertible to bytesNN.");
|
||||||
return bytesToFixedBytesConversionFunction(fromType.arrayType(), dynamic_cast<FixedBytesType const &>(_to));
|
return bytesToFixedBytesConversionFunction(fromType.arrayType(), dynamic_cast<FixedBytesType const &>(_to));
|
||||||
}
|
}
|
||||||
solAssert(_to.category() == Type::Category::Array);
|
solAssert(_to.category() == Type::Category::Array);
|
||||||
@ -3224,7 +3224,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
|
|
||||||
solAssert(
|
solAssert(
|
||||||
fromType.arrayType().isImplicitlyConvertibleTo(targetType) ||
|
fromType.arrayType().isImplicitlyConvertibleTo(targetType) ||
|
||||||
(fromType.arrayType().isByteArray() && targetType.isByteArray())
|
(fromType.arrayType().isByteArrayOrString() && targetType.isByteArrayOrString())
|
||||||
);
|
);
|
||||||
solAssert(
|
solAssert(
|
||||||
fromType.arrayType().dataStoredIn(DataLocation::CallData) &&
|
fromType.arrayType().dataStoredIn(DataLocation::CallData) &&
|
||||||
@ -3256,7 +3256,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
auto const& fromArrayType = dynamic_cast<ArrayType const&>(_from);
|
auto const& fromArrayType = dynamic_cast<ArrayType const&>(_from);
|
||||||
if (_to.category() == Type::Category::FixedBytes)
|
if (_to.category() == Type::Category::FixedBytes)
|
||||||
{
|
{
|
||||||
solAssert(fromArrayType.isByteArray(), "Array types other than bytes not convertible to bytesNN.");
|
solAssert(fromArrayType.isByteArrayOrString(), "Array types other than bytes not convertible to bytesNN.");
|
||||||
return bytesToFixedBytesConversionFunction(fromArrayType, dynamic_cast<FixedBytesType const &>(_to));
|
return bytesToFixedBytesConversionFunction(fromArrayType, dynamic_cast<FixedBytesType const &>(_to));
|
||||||
}
|
}
|
||||||
solAssert(_to.category() == Type::Category::Array, "");
|
solAssert(_to.category() == Type::Category::Array, "");
|
||||||
@ -3460,7 +3460,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
|
|
||||||
string YulUtilFunctions::bytesToFixedBytesConversionFunction(ArrayType const& _from, FixedBytesType const& _to)
|
string YulUtilFunctions::bytesToFixedBytesConversionFunction(ArrayType const& _from, FixedBytesType const& _to)
|
||||||
{
|
{
|
||||||
solAssert(_from.isByteArray() && !_from.isString(), "");
|
solAssert(_from.isByteArrayOrString() && !_from.isString(), "");
|
||||||
solAssert(_from.isDynamicallySized(), "");
|
solAssert(_from.isDynamicallySized(), "");
|
||||||
string functionName = "convert_bytes_to_fixedbytes_from_" + _from.identifier() + "_to_" + _to.identifier();
|
string functionName = "convert_bytes_to_fixedbytes_from_" + _from.identifier() + "_to_" + _to.identifier();
|
||||||
return m_functionCollector.createFunction(functionName, [&](auto& _args, auto& _returnParams) {
|
return m_functionCollector.createFunction(functionName, [&](auto& _args, auto& _returnParams) {
|
||||||
@ -3633,14 +3633,14 @@ string YulUtilFunctions::arrayConversionFunction(ArrayType const& _from, ArrayTy
|
|||||||
{
|
{
|
||||||
if (_to.dataStoredIn(DataLocation::CallData))
|
if (_to.dataStoredIn(DataLocation::CallData))
|
||||||
solAssert(
|
solAssert(
|
||||||
_from.dataStoredIn(DataLocation::CallData) && _from.isByteArray() && _to.isByteArray(),
|
_from.dataStoredIn(DataLocation::CallData) && _from.isByteArrayOrString() && _to.isByteArrayOrString(),
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
|
||||||
// Other cases are done explicitly in LValue::storeValue, and only possible by assignment.
|
// Other cases are done explicitly in LValue::storeValue, and only possible by assignment.
|
||||||
if (_to.location() == DataLocation::Storage)
|
if (_to.location() == DataLocation::Storage)
|
||||||
solAssert(
|
solAssert(
|
||||||
(_to.isPointer() || (_from.isByteArray() && _to.isByteArray())) &&
|
(_to.isPointer() || (_from.isByteArrayOrString() && _to.isByteArrayOrString())) &&
|
||||||
_from.location() == DataLocation::Storage,
|
_from.location() == DataLocation::Storage,
|
||||||
"Invalid conversion to storage type."
|
"Invalid conversion to storage type."
|
||||||
);
|
);
|
||||||
@ -4238,7 +4238,7 @@ string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const
|
|||||||
}
|
}
|
||||||
else if (_to.category() == Type::Category::Array)
|
else if (_to.category() == Type::Category::Array)
|
||||||
{
|
{
|
||||||
solAssert(dynamic_cast<ArrayType const&>(_to).isByteArray(), "");
|
solAssert(dynamic_cast<ArrayType const&>(_to).isByteArrayOrString(), "");
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
function <functionName>() -> converted {
|
function <functionName>() -> converted {
|
||||||
converted := <copyLiteralToMemory>()
|
converted := <copyLiteralToMemory>()
|
||||||
|
@ -677,7 +677,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
|||||||
continue;
|
continue;
|
||||||
if (
|
if (
|
||||||
auto const* arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]);
|
auto const* arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]);
|
||||||
arrayType && !arrayType->isByteArray()
|
arrayType && !arrayType->isByteArrayOrString()
|
||||||
)
|
)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -698,7 +698,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
|||||||
solAssert(returnTypes.size() == 1, "");
|
solAssert(returnTypes.size() == 1, "");
|
||||||
auto const* arrayType = dynamic_cast<ArrayType const*>(returnTypes.front());
|
auto const* arrayType = dynamic_cast<ArrayType const*>(returnTypes.front());
|
||||||
if (arrayType)
|
if (arrayType)
|
||||||
solAssert(arrayType->isByteArray(), "");
|
solAssert(arrayType->isByteArrayOrString(), "");
|
||||||
vector<string> retVars = IRVariable("ret", *returnTypes.front()).stackSlots();
|
vector<string> retVars = IRVariable("ret", *returnTypes.front()).stackSlots();
|
||||||
returnVariables += retVars;
|
returnVariables += retVars;
|
||||||
code += Whiskers(R"(
|
code += Whiskers(R"(
|
||||||
|
@ -2088,7 +2088,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
else if (dynamic_cast<UserDefinedValueType const*>(&actualType))
|
else if (dynamic_cast<UserDefinedValueType const*>(&actualType))
|
||||||
solAssert(member == "wrap" || member == "unwrap");
|
solAssert(member == "wrap" || member == "unwrap");
|
||||||
else if (auto const* arrayType = dynamic_cast<ArrayType const*>(&actualType))
|
else if (auto const* arrayType = dynamic_cast<ArrayType const*>(&actualType))
|
||||||
solAssert(arrayType->isByteArray() && member == "concat");
|
solAssert(arrayType->isByteArrayOrString() && member == "concat");
|
||||||
else
|
else
|
||||||
// The old code generator had a generic "else" case here
|
// The old code generator had a generic "else" case here
|
||||||
// without any specific code being generated,
|
// without any specific code being generated,
|
||||||
@ -2226,7 +2226,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
|||||||
|
|
||||||
setLValue(_indexAccess, IRLValue{
|
setLValue(_indexAccess, IRLValue{
|
||||||
*arrayType.baseType(),
|
*arrayType.baseType(),
|
||||||
IRLValue::Memory{memAddress, arrayType.isByteArray()}
|
IRLValue::Memory{memAddress, arrayType.isByteArrayOrString()}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2240,7 +2240,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
|||||||
", " +
|
", " +
|
||||||
expressionAsType(*_indexAccess.indexExpression(), *TypeProvider::uint256()) +
|
expressionAsType(*_indexAccess.indexExpression(), *TypeProvider::uint256()) +
|
||||||
")";
|
")";
|
||||||
if (arrayType.isByteArray())
|
if (arrayType.isByteArrayOrString())
|
||||||
define(_indexAccess) <<
|
define(_indexAccess) <<
|
||||||
m_utils.cleanupFunction(*arrayType.baseType()) <<
|
m_utils.cleanupFunction(*arrayType.baseType()) <<
|
||||||
"(calldataload(" <<
|
"(calldataload(" <<
|
||||||
|
@ -953,7 +953,7 @@ bool isReturnedFromStructGetter(Type const* _type)
|
|||||||
if (category == Type::Category::Mapping)
|
if (category == Type::Category::Mapping)
|
||||||
return false;
|
return false;
|
||||||
if (category == Type::Category::Array)
|
if (category == Type::Category::Array)
|
||||||
return dynamic_cast<ArrayType const&>(*_type).isByteArray();
|
return dynamic_cast<ArrayType const&>(*_type).isByteArrayOrString();
|
||||||
// default
|
// default
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -990,7 +990,7 @@ void SMTEncoder::visitPublicGetter(FunctionCall const& _funCall)
|
|||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
type->isValueType() ||
|
type->isValueType() ||
|
||||||
(type->category() == Type::Category::Array && dynamic_cast<ArrayType const&>(*type).isByteArray())
|
(type->category() == Type::Category::Array && dynamic_cast<ArrayType const&>(*type).isByteArrayOrString())
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
solAssert(symbArguments.empty(), "");
|
solAssert(symbArguments.empty(), "");
|
||||||
@ -1071,7 +1071,7 @@ void SMTEncoder::visitTypeConversion(FunctionCall const& _funCall)
|
|||||||
if (auto sliceType = dynamic_cast<ArraySliceType const*>(argType))
|
if (auto sliceType = dynamic_cast<ArraySliceType const*>(argType))
|
||||||
arrayType = &sliceType->arrayType();
|
arrayType = &sliceType->arrayType();
|
||||||
|
|
||||||
if (arrayType && arrayType->isByteArray() && smt::isFixedBytes(*funCallType))
|
if (arrayType && arrayType->isByteArrayOrString() && smt::isFixedBytes(*funCallType))
|
||||||
{
|
{
|
||||||
auto array = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.expression(*argument));
|
auto array = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.expression(*argument));
|
||||||
bytesToFixedBytesAssertions(*array, _funCall);
|
bytesToFixedBytesAssertions(*array, _funCall);
|
||||||
@ -2695,14 +2695,14 @@ Expression const* SMTEncoder::cleanExpression(Expression const& _expr)
|
|||||||
auto typeType = dynamic_cast<TypeType const*>(functionCall->expression().annotation().type);
|
auto typeType = dynamic_cast<TypeType const*>(functionCall->expression().annotation().type);
|
||||||
solAssert(typeType, "");
|
solAssert(typeType, "");
|
||||||
if (auto const* arrayType = dynamic_cast<ArrayType const*>(typeType->actualType()))
|
if (auto const* arrayType = dynamic_cast<ArrayType const*>(typeType->actualType()))
|
||||||
if (arrayType->isByteArray())
|
if (arrayType->isByteArrayOrString())
|
||||||
{
|
{
|
||||||
// this is a cast to `bytes`
|
// this is a cast to `bytes`
|
||||||
solAssert(functionCall->arguments().size() == 1, "");
|
solAssert(functionCall->arguments().size() == 1, "");
|
||||||
Expression const& arg = *functionCall->arguments()[0];
|
Expression const& arg = *functionCall->arguments()[0];
|
||||||
if (
|
if (
|
||||||
auto const* argArrayType = dynamic_cast<ArrayType const*>(arg.annotation().type);
|
auto const* argArrayType = dynamic_cast<ArrayType const*>(arg.annotation().type);
|
||||||
argArrayType && argArrayType->isByteArray()
|
argArrayType && argArrayType->isByteArrayOrString()
|
||||||
)
|
)
|
||||||
return cleanExpression(arg);
|
return cleanExpression(arg);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
|||||||
auto sliceArrayType = dynamic_cast<ArraySliceType const*>(&_type);
|
auto sliceArrayType = dynamic_cast<ArraySliceType const*>(&_type);
|
||||||
ArrayType const* arrayType = sliceArrayType ? &sliceArrayType->arrayType() : dynamic_cast<ArrayType const*>(&_type);
|
ArrayType const* arrayType = sliceArrayType ? &sliceArrayType->arrayType() : dynamic_cast<ArrayType const*>(&_type);
|
||||||
if (
|
if (
|
||||||
(arrayType && (arrayType->isString() || arrayType->isByteArray())) ||
|
(arrayType && (arrayType->isString() || arrayType->isByteArrayOrString())) ||
|
||||||
_type.category() == frontend::Type::Category::StringLiteral
|
_type.category() == frontend::Type::Category::StringLiteral
|
||||||
)
|
)
|
||||||
tupleName = "bytes";
|
tupleName = "bytes";
|
||||||
|
@ -176,7 +176,7 @@ Json::Value ABI::formatType(
|
|||||||
ret["type"] = _encodingType.canonicalName() + suffix;
|
ret["type"] = _encodingType.canonicalName() + suffix;
|
||||||
else if (ArrayType const* arrayType = dynamic_cast<ArrayType const*>(&_encodingType))
|
else if (ArrayType const* arrayType = dynamic_cast<ArrayType const*>(&_encodingType))
|
||||||
{
|
{
|
||||||
if (arrayType->isByteArray())
|
if (arrayType->isByteArrayOrString())
|
||||||
ret["type"] = _encodingType.canonicalName() + suffix;
|
ret["type"] = _encodingType.canonicalName() + suffix;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -94,7 +94,7 @@ void StorageLayout::generate(Type const* _type)
|
|||||||
}
|
}
|
||||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(_type))
|
else if (auto arrayType = dynamic_cast<ArrayType const*>(_type))
|
||||||
{
|
{
|
||||||
if (arrayType->isByteArray())
|
if (arrayType->isByteArrayOrString())
|
||||||
typeInfo["encoding"] = "bytes";
|
typeInfo["encoding"] = "bytes";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user