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