mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12628 from nishant-sachdeva/adding_functiontype_string_and_allow_string_concat_operations
Added support for FunctionType::Kind::StringConcat
This commit is contained in:
commit
1210c3e60f
@ -17,6 +17,7 @@ Bugfixes:
|
||||
* Code Generator: Fix ICE when accessing the members of external functions occupying more than two stack slots.
|
||||
* Code Generator: Fix ICE when doing an explicit conversion from ``string calldata`` to ``bytes``.
|
||||
* Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis.
|
||||
* General: ``string.concat`` now properly takes strings as arguments and returns ``string memory``. It was accidentally introduced as a copy of ``bytes.concat`` before.
|
||||
* Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the derived contract contains immutable variables.
|
||||
* IR Generator: Add missing cleanup during the conversion of fixed bytes types to smaller fixed bytes types.
|
||||
* IR Generator: Add missing cleanup for indexed event arguments of value type.
|
||||
|
@ -86,6 +86,8 @@ Global Variables
|
||||
to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature)), ...)``
|
||||
- ``bytes.concat(...) returns (bytes memory)``: :ref:`Concatenates variable number of
|
||||
arguments to one byte array<bytes-concat>`
|
||||
- ``string.concat(...) returns (string memory)``: :ref:`Concatenates variable number of
|
||||
arguments to one string array<string-concat>`
|
||||
- ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 <https://eips.ethereum.org/EIPS/eip-3198>`_ and `EIP-1559 <https://eips.ethereum.org/EIPS/eip-1559>`_)
|
||||
- ``block.chainid`` (``uint``): current chain id
|
||||
- ``block.coinbase`` (``address payable``): current block miner's address
|
||||
|
@ -150,7 +150,7 @@ length or index access.
|
||||
Solidity does not have string manipulation functions, but there are
|
||||
third-party string libraries. You can also compare two strings by their keccak256-hash using
|
||||
``keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))`` and
|
||||
concatenate two strings using ``bytes.concat(bytes(s1), bytes(s2))``.
|
||||
concatenate two strings using ``string.concat(s1, s2)``.
|
||||
|
||||
You should use ``bytes`` over ``bytes1[]`` because it is cheaper,
|
||||
since using ``bytes1[]`` in ``memory`` adds 31 padding bytes between the elements. Note that in ``storage``, the
|
||||
@ -165,31 +165,40 @@ always use one of the value types ``bytes1`` to ``bytes32`` because they are muc
|
||||
that you are accessing the low-level bytes of the UTF-8 representation,
|
||||
and not the individual characters.
|
||||
|
||||
.. index:: ! bytes-concat
|
||||
.. index:: ! bytes-concat, ! string-concat
|
||||
|
||||
.. _bytes-concat:
|
||||
.. _string-concat:
|
||||
|
||||
``bytes.concat`` function
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The functions ``bytes.concat`` and ``string.concat``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can concatenate a variable number of ``bytes`` or ``bytes1 ... bytes32`` using ``bytes.concat``.
|
||||
You can concatenate an arbitrary number of ``string`` values using ``string.concat``.
|
||||
The function returns a single ``string memory`` array that contains the contents of the arguments without padding.
|
||||
If you want to use parameters of other types that are not implicitly convertible to ``string``, you need to convert them to ``string`` first.
|
||||
|
||||
Analogously, the ``bytes.concat`` function can concatenate an arbitrary number of ``bytes`` or ``bytes1 ... bytes32`` values.
|
||||
The function returns a single ``bytes memory`` array that contains the contents of the arguments without padding.
|
||||
If you want to use string parameters or other types, you need to convert them to ``bytes`` or ``bytes1``/.../``bytes32`` first.
|
||||
If you want to use string parameters or other types that are not implicitly convertible to ``bytes``, you need to convert them to ``bytes`` or ``bytes1``/.../``bytes32`` first.
|
||||
|
||||
|
||||
.. code-block:: solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
pragma solidity ^0.8.12;
|
||||
|
||||
contract C {
|
||||
bytes s = "Storage";
|
||||
function f(bytes calldata c, string memory m, bytes16 b) public view {
|
||||
bytes memory a = bytes.concat(s, c, c[:2], "Literal", bytes(m), b);
|
||||
assert((s.length + c.length + 2 + 7 + bytes(m).length + 16) == a.length);
|
||||
string s = "Storage";
|
||||
function f(bytes calldata bc, string memory sm, bytes16 b) public view {
|
||||
string memory concat_string = string.concat(s, string(bc), "Literal", sm);
|
||||
assert((bytes(s).length + bc.length + 7 + bytes(sm).length) == bytes(concat_string).length);
|
||||
|
||||
bytes memory concat_bytes = bytes.concat(bytes(s), bc, bc[:2], "Literal", bytes(sm), b);
|
||||
assert((bytes(s).length + bc.length + 2 + 7 + bytes(sm).length + b.length) == concat_bytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
If you call ``bytes.concat`` without arguments it will return an empty ``bytes`` array.
|
||||
If you call ``string.concat`` or ``bytes.concat`` without arguments they return an empty array.
|
||||
|
||||
.. index:: ! array;allocating, new
|
||||
|
||||
|
@ -154,6 +154,14 @@ Members of bytes
|
||||
|
||||
- ``bytes.concat(...) returns (bytes memory)``: :ref:`Concatenates variable number of bytes and bytes1, ..., bytes32 arguments to one byte array<bytes-concat>`
|
||||
|
||||
.. index:: string members
|
||||
|
||||
Members of string
|
||||
-----------------
|
||||
|
||||
- ``string.concat(...) returns (string memory)``: :ref:`Concatenates variable number of string arguments to one string array<string-concat>`
|
||||
|
||||
|
||||
.. index:: assert, revert, require
|
||||
|
||||
Error Handling
|
||||
|
@ -2207,14 +2207,42 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TypeChecker::typeCheckStringConcatFunction(
|
||||
FunctionCall const& _functionCall,
|
||||
FunctionType const* _functionType
|
||||
)
|
||||
{
|
||||
solAssert(_functionType);
|
||||
solAssert(_functionType->kind() == FunctionType::Kind::StringConcat);
|
||||
solAssert(_functionCall.names().empty());
|
||||
|
||||
typeCheckFunctionGeneralChecks(_functionCall, _functionType);
|
||||
|
||||
for (shared_ptr<Expression const> const& argument: _functionCall.arguments())
|
||||
{
|
||||
Type const* argumentType = type(*argument);
|
||||
bool notConvertibleToString = !argumentType->isImplicitlyConvertibleTo(*TypeProvider::stringMemory());
|
||||
|
||||
if (notConvertibleToString)
|
||||
m_errorReporter.typeError(
|
||||
9977_error,
|
||||
argument->location(),
|
||||
"Invalid type for argument in the string.concat function call. "
|
||||
"string type is required, but " +
|
||||
argumentType->identifier() + " provided."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeChecker::typeCheckBytesConcatFunction(
|
||||
FunctionCall const& _functionCall,
|
||||
FunctionType const* _functionType
|
||||
)
|
||||
{
|
||||
solAssert(_functionType, "");
|
||||
solAssert(_functionType->kind() == FunctionType::Kind::BytesConcat, "");
|
||||
solAssert(_functionCall.names().empty(), "");
|
||||
solAssert(_functionType);
|
||||
solAssert(_functionType->kind() == FunctionType::Kind::BytesConcat);
|
||||
solAssert(_functionCall.names().empty());
|
||||
|
||||
typeCheckFunctionGeneralChecks(_functionCall, _functionType);
|
||||
|
||||
@ -2651,6 +2679,12 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
returnTypes = functionType->returnParameterTypes();
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::StringConcat:
|
||||
{
|
||||
typeCheckStringConcatFunction(_functionCall, functionType);
|
||||
returnTypes = functionType->returnParameterTypes();
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::Wrap:
|
||||
case FunctionType::Kind::Unwrap:
|
||||
{
|
||||
|
@ -113,6 +113,12 @@ private:
|
||||
/// Performs checks specific to the ABI encode functions of type ABIEncodeCall
|
||||
void typeCheckABIEncodeCallFunction(FunctionCall const& _functionCall);
|
||||
|
||||
/// Performs general checks and checks specific to string concat function call
|
||||
void typeCheckStringConcatFunction(
|
||||
FunctionCall const& _functionCall,
|
||||
FunctionType const* _functionType
|
||||
);
|
||||
|
||||
/// Performs general checks and checks specific to bytes concat function call
|
||||
void typeCheckBytesConcatFunction(
|
||||
FunctionCall const& _functionCall,
|
||||
|
@ -2928,6 +2928,7 @@ string FunctionType::richIdentifier() const
|
||||
case Kind::ArrayPush: id += "arraypush"; break;
|
||||
case Kind::ArrayPop: id += "arraypop"; break;
|
||||
case Kind::BytesConcat: id += "bytesconcat"; break;
|
||||
case Kind::StringConcat: id += "stringconcat"; break;
|
||||
case Kind::ObjectCreation: id += "objectcreation"; break;
|
||||
case Kind::Assert: id += "assert"; break;
|
||||
case Kind::Require: id += "require"; break;
|
||||
@ -3817,15 +3818,14 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
|
||||
)
|
||||
members.emplace_back("concat", TypeProvider::function(
|
||||
TypePointers{},
|
||||
TypePointers{TypeProvider::bytesMemory()},
|
||||
TypePointers{arrayType->isString() ? TypeProvider::stringMemory() : TypeProvider::bytesMemory()},
|
||||
strings{},
|
||||
strings{string()},
|
||||
FunctionType::Kind::BytesConcat,
|
||||
strings{string{}},
|
||||
arrayType->isString() ? FunctionType::Kind::StringConcat : FunctionType::Kind::BytesConcat,
|
||||
StateMutability::Pure,
|
||||
nullptr,
|
||||
FunctionType::Options::withArbitraryParameters()
|
||||
));
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
|
@ -1228,6 +1228,7 @@ public:
|
||||
ArrayPush, ///< .push() to a dynamically sized array in storage
|
||||
ArrayPop, ///< .pop() from a dynamically sized array in storage
|
||||
BytesConcat, ///< .concat() on bytes (type type)
|
||||
StringConcat, ///< .concat() on string (type type)
|
||||
ObjectCreation, ///< array creation using new
|
||||
Assert, ///< assert()
|
||||
Require, ///< require()
|
||||
|
@ -1101,6 +1101,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
ArrayUtils(m_context).popStorageArrayElement(*arrayType);
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::StringConcat:
|
||||
case FunctionType::Kind::BytesConcat:
|
||||
{
|
||||
_functionCall.expression().accept(*this);
|
||||
@ -1121,8 +1122,16 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
else
|
||||
{
|
||||
solAssert(!dynamic_cast<RationalNumberType const*>(argument->annotation().type), "");
|
||||
solAssert(argument->annotation().type->isImplicitlyConvertibleTo(*TypeProvider::bytesMemory()), "");
|
||||
targetTypes.emplace_back(TypeProvider::bytesMemory());
|
||||
if (function.kind() == FunctionType::Kind::StringConcat)
|
||||
{
|
||||
solAssert(argument->annotation().type->isImplicitlyConvertibleTo(*TypeProvider::stringMemory()), "");
|
||||
targetTypes.emplace_back(TypeProvider::stringMemory());
|
||||
}
|
||||
else if (function.kind() == FunctionType::Kind::BytesConcat)
|
||||
{
|
||||
solAssert(argument->annotation().type->isImplicitlyConvertibleTo(*TypeProvider::bytesMemory()), "");
|
||||
targetTypes.emplace_back(TypeProvider::bytesMemory());
|
||||
}
|
||||
}
|
||||
}
|
||||
utils().fetchFreeMemoryPointer();
|
||||
|
@ -2475,18 +2475,26 @@ string YulUtilFunctions::copyArrayFromStorageToMemoryFunction(ArrayType const& _
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::bytesConcatFunction(vector<Type const*> const& _argumentTypes)
|
||||
string YulUtilFunctions::bytesOrStringConcatFunction(
|
||||
vector<Type const*> const& _argumentTypes,
|
||||
FunctionType::Kind _functionTypeKind
|
||||
)
|
||||
{
|
||||
string functionName = "bytes_concat";
|
||||
solAssert(_functionTypeKind == FunctionType::Kind::BytesConcat || _functionTypeKind == FunctionType::Kind::StringConcat);
|
||||
std::string functionName = (_functionTypeKind == FunctionType::Kind::StringConcat) ? "string_concat" : "bytes_concat";
|
||||
size_t totalParams = 0;
|
||||
vector<Type const*> targetTypes;
|
||||
|
||||
for (Type const* argumentType: _argumentTypes)
|
||||
{
|
||||
solAssert(
|
||||
argumentType->isImplicitlyConvertibleTo(*TypeProvider::bytesMemory()) ||
|
||||
argumentType->isImplicitlyConvertibleTo(*TypeProvider::fixedBytes(32)),
|
||||
""
|
||||
);
|
||||
if (_functionTypeKind == FunctionType::Kind::StringConcat)
|
||||
solAssert(argumentType->isImplicitlyConvertibleTo(*TypeProvider::stringMemory()));
|
||||
else if (_functionTypeKind == FunctionType::Kind::BytesConcat)
|
||||
solAssert(
|
||||
argumentType->isImplicitlyConvertibleTo(*TypeProvider::bytesMemory()) ||
|
||||
argumentType->isImplicitlyConvertibleTo(*TypeProvider::fixedBytes(32))
|
||||
);
|
||||
|
||||
if (argumentType->category() == Type::Category::FixedBytes)
|
||||
targetTypes.emplace_back(argumentType);
|
||||
else if (
|
||||
@ -2496,15 +2504,16 @@ string YulUtilFunctions::bytesConcatFunction(vector<Type const*> const& _argumen
|
||||
targetTypes.emplace_back(TypeProvider::fixedBytes(static_cast<unsigned>(literalType->value().size())));
|
||||
else
|
||||
{
|
||||
solAssert(!dynamic_cast<RationalNumberType const*>(argumentType), "");
|
||||
solAssert(argumentType->isImplicitlyConvertibleTo(*TypeProvider::bytesMemory()), "");
|
||||
targetTypes.emplace_back(TypeProvider::bytesMemory());
|
||||
solAssert(!dynamic_cast<RationalNumberType const*>(argumentType));
|
||||
targetTypes.emplace_back(
|
||||
_functionTypeKind == FunctionType::Kind::StringConcat ?
|
||||
TypeProvider::stringMemory() :
|
||||
TypeProvider::bytesMemory()
|
||||
);
|
||||
}
|
||||
|
||||
totalParams += argumentType->sizeOnStack();
|
||||
functionName += "_" + argumentType->identifier();
|
||||
}
|
||||
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(<parameters>) -> outPtr {
|
||||
|
@ -312,9 +312,13 @@ public:
|
||||
/// of the storage array into it.
|
||||
std::string copyArrayFromStorageToMemoryFunction(ArrayType const& _from, ArrayType const& _to);
|
||||
|
||||
/// @returns the name of a function that does concatenation of variadic number of bytes
|
||||
/// or fixed bytes
|
||||
std::string bytesConcatFunction(std::vector<Type const*> const& _argumentTypes);
|
||||
/// @returns the name of a function that does concatenation of variadic number of
|
||||
/// bytes if @a functionTypeKind is FunctionType::Kind::BytesConcat,
|
||||
/// or of strings, if @a functionTypeKind is FunctionType::Kind::StringConcat.
|
||||
std::string bytesOrStringConcatFunction(
|
||||
std::vector<Type const*> const& _argumentTypes,
|
||||
FunctionType::Kind _functionTypeKind
|
||||
);
|
||||
|
||||
/// @returns the name of a function that performs index access for mappings.
|
||||
/// @param _mappingType the type of the mapping
|
||||
|
@ -1389,6 +1389,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::StringConcat:
|
||||
case FunctionType::Kind::BytesConcat:
|
||||
{
|
||||
TypePointers argumentTypes;
|
||||
@ -1399,11 +1400,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
argumentVars += IRVariable(*argument).stackSlots();
|
||||
}
|
||||
define(IRVariable(_functionCall)) <<
|
||||
m_utils.bytesConcatFunction(argumentTypes) <<
|
||||
m_utils.bytesOrStringConcatFunction(argumentTypes, functionType->kind()) <<
|
||||
"(" <<
|
||||
joinHumanReadable(argumentVars) <<
|
||||
")\n";
|
||||
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::MetaType:
|
||||
|
@ -0,0 +1,14 @@
|
||||
contract C {
|
||||
function f(string memory a, string memory b) public returns (string memory) {
|
||||
return string.concat(a, b);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(string,string): 0x40, 0x80, 32, "abcdabcdabcdabcdabcdabcdabcdabcd", 5, "bcdef" -> 0x20, 0x25, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
||||
// f(string,string): 0x40, 0xa0, 64, "abcdabcdabcdabcdabcdabcdabcdabcd", "abcdabcdabcdabcdabcdabcdabcdabcd", 5, "bcdef" -> 0x20, 0x45, 0x6162636461626364616263646162636461626364616263646162636461626364, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
||||
// f(string,string): 0x40, 0x80, 3, "abc", 3, "def" -> 0x20, 6, "abcdef"
|
||||
// f(string,string): 0x40, 0xa0, 34, "abcdabcdabcdabcdabcdabcdabcdabcd", "ab", 30, "cdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x40, 0x6162636461626364616263646162636461626364616263646162636461626364, 0x6162636461626364616263646162636461626364616263646162636461626364
|
||||
// f(string,string): 0x40, 0xa0, 34, "abcdabcdabcdabcdabcdabcdabcdabcd", "ab", 34, "cdabcdabcdabcdabcdabcdabcdabcdab", "cd" -> 0x20, 0x44, 0x6162636461626364616263646162636461626364616263646162636461626364, 0x6162636461626364616263646162636461626364616263646162636461626364, 44048183293808120317390542201052832727062033572611867748297851798484192067584
|
||||
// f(string,string): 0x40, 0x80, 3, "abc", 30, "dabcdabcdabcdabcdabcdabcdabcda" -> 0x20, 0x21, 0x6162636461626364616263646162636461626364616263646162636461626364, 43874346312576839672212443538448152585028080127215369968075725190498334277632
|
@ -0,0 +1,37 @@
|
||||
contract C{
|
||||
string s = "bcdef";
|
||||
|
||||
function f(string memory a) public returns (string memory) {
|
||||
return string.concat(a, "bcdef");
|
||||
}
|
||||
function g(string calldata a) public returns (string memory) {
|
||||
return string.concat(a, "abcdefghabcdefghabcdefghabcdefghab");
|
||||
}
|
||||
function h(string calldata a) public returns (string memory) {
|
||||
return string.concat(a, s);
|
||||
}
|
||||
function j(string calldata a) public returns (string memory) {
|
||||
string storage ref = s;
|
||||
return string.concat(a, ref, s);
|
||||
}
|
||||
function k(string calldata a, bytes memory b) public returns (string memory) {
|
||||
return string.concat(a, string(b));
|
||||
}
|
||||
function slice(string calldata a) public returns (string memory) {
|
||||
require(bytes(a).length > 2, "");
|
||||
return string.concat(a[:2], a[2:]);
|
||||
}
|
||||
function strParam(bytes calldata a) public returns (string memory) {
|
||||
return string.concat(string(a), "bcdef");
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(string): 0x20, 32, "abcdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x25, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
||||
// g(string): 0x20, 32, "abcdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x42, 0x6162636461626364616263646162636461626364616263646162636461626364, 0x6162636465666768616263646566676861626364656667686162636465666768, 44047497324925121336511606693520958599579173549109180625971642598225011015680
|
||||
// h(string): 0x20, 32, "abcdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x25, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
||||
// j(string): 0x20, 32, "abcdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x2a, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928944786876717917111204727192787026596791669343131645116682757734400
|
||||
// k(string,bytes): 0x40, 0x80, 32, "abcdabcdabcdabcdabcdabcdabcdabcd", 5, "bcdef" -> 0x20, 0x25, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
||||
// slice(string): 0x20, 4, "abcd" -> 0x20, 4, "abcd"
|
||||
// strParam(bytes): 0x20, 32, "abcdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x25, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
@ -0,0 +1,10 @@
|
||||
contract C {
|
||||
function f() public returns (string memory) {
|
||||
return string.concat();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileToEwasm: also
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0x20, 0
|
@ -0,0 +1,27 @@
|
||||
contract C {
|
||||
function f() public returns (string memory) {
|
||||
string memory b = "";
|
||||
return string.concat(
|
||||
string.concat(b),
|
||||
string.concat(b, b),
|
||||
string.concat("", b),
|
||||
string.concat(b, "")
|
||||
);
|
||||
}
|
||||
|
||||
function g() public returns (string memory) {
|
||||
return string.concat("", "abc", hex"", "abc", unicode"");
|
||||
}
|
||||
|
||||
function h() public returns (string memory) {
|
||||
string memory b = "";
|
||||
return string.concat(b, "abc", b, "abc", b);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileToEwasm: also
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0x20, 0
|
||||
// g() -> 0x20, 6, "abcabc"
|
||||
// h() -> 0x20, 6, "abcabc"
|
@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
function f(string memory a, string memory b, string memory c) public returns (string memory) {
|
||||
return string.concat(string.concat(a, b), c);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(string,string,string): 0x60, 0x60, 0x60, 2, "ab" -> 0x20, 6, "ababab"
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
function g() public pure returns (string memory) {
|
||||
return string.concat;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 6359: (83-96): Return argument type function () pure returns (string memory) is not implicitly convertible to expected type (type of first return variable) string memory.
|
@ -0,0 +1,13 @@
|
||||
contract C {
|
||||
function j() external {
|
||||
string memory a = "hello";
|
||||
string memory b = " world";
|
||||
|
||||
string memory d = string.concat(bytes(a), bytes(b));
|
||||
string memory e = string.concat(a, 0);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9977: (153-161): Invalid type for argument in the string.concat function call. string type is required, but t_bytes_memory_ptr provided.
|
||||
// TypeError 9977: (163-171): Invalid type for argument in the string.concat function call. string type is required, but t_bytes_memory_ptr provided.
|
||||
// TypeError 9977: (217-218): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
@ -0,0 +1,15 @@
|
||||
contract C {
|
||||
string s;
|
||||
function f(string calldata c, string calldata c1) public {
|
||||
string memory a;
|
||||
bytes16 b;
|
||||
uint8[] memory num;
|
||||
bytes1[] memory m;
|
||||
string memory d = string.concat(a, b, c, num, s, "abc", m, c1, bytes(c1));
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9977: (232-233): Invalid type for argument in the string.concat function call. string type is required, but t_bytes16 provided.
|
||||
// TypeError 9977: (238-241): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_uint8_$dyn_memory_ptr provided.
|
||||
// TypeError 9977: (253-254): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_bytes1_$dyn_memory_ptr provided.
|
||||
// TypeError 9977: (260-269): Invalid type for argument in the string.concat function call. string type is required, but t_bytes_calldata_ptr provided.
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
function f() public {
|
||||
string.concat([], [], []);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 6378: (61-63): Unable to deduce common type for array elements.
|
@ -0,0 +1,40 @@
|
||||
contract C {
|
||||
struct S {
|
||||
uint x;
|
||||
}
|
||||
|
||||
enum E {A, B, C}
|
||||
|
||||
mapping(uint => E) m;
|
||||
|
||||
function f() public {
|
||||
bool b;
|
||||
uint u;
|
||||
uint8 u8;
|
||||
address a;
|
||||
address payable ap;
|
||||
function () external fext;
|
||||
function () internal fint;
|
||||
uint[] memory uDynamic;
|
||||
uint[2] memory uStatic;
|
||||
C c;
|
||||
S memory s;
|
||||
E e;
|
||||
|
||||
string.concat(b, u, u8, a, ap, fext, fint, uDynamic, uStatic, c, s, e, m);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9977: (426-427): Invalid type for argument in the string.concat function call. string type is required, but t_bool provided.
|
||||
// TypeError 9977: (429-430): Invalid type for argument in the string.concat function call. string type is required, but t_uint256 provided.
|
||||
// TypeError 9977: (432-434): Invalid type for argument in the string.concat function call. string type is required, but t_uint8 provided.
|
||||
// TypeError 9977: (436-437): Invalid type for argument in the string.concat function call. string type is required, but t_address provided.
|
||||
// TypeError 9977: (439-441): Invalid type for argument in the string.concat function call. string type is required, but t_address_payable provided.
|
||||
// TypeError 9977: (443-447): Invalid type for argument in the string.concat function call. string type is required, but t_function_external_nonpayable$__$returns$__$ provided.
|
||||
// TypeError 9977: (449-453): Invalid type for argument in the string.concat function call. string type is required, but t_function_internal_nonpayable$__$returns$__$ provided.
|
||||
// TypeError 9977: (455-463): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_uint256_$dyn_memory_ptr provided.
|
||||
// TypeError 9977: (465-472): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_uint256_$2_memory_ptr provided.
|
||||
// TypeError 9977: (474-475): Invalid type for argument in the string.concat function call. string type is required, but t_contract$_C_$86 provided.
|
||||
// TypeError 9977: (477-478): Invalid type for argument in the string.concat function call. string type is required, but t_struct$_S_$4_memory_ptr provided.
|
||||
// TypeError 9977: (480-481): Invalid type for argument in the string.concat function call. string type is required, but t_enum$_E_$8 provided.
|
||||
// TypeError 9977: (483-484): Invalid type for argument in the string.concat function call. string type is required, but t_mapping$_t_uint256_$_t_enum$_E_$8_$ provided.
|
@ -0,0 +1,58 @@
|
||||
contract C {
|
||||
struct S {
|
||||
uint x;
|
||||
}
|
||||
|
||||
enum E {A, B, C}
|
||||
|
||||
function f() public {
|
||||
string.concat(
|
||||
false,
|
||||
1,
|
||||
1e10,
|
||||
1e-10,
|
||||
0.1,
|
||||
0x1234567,
|
||||
0x11112222333344445555666677778888999900, // One byte less than an address
|
||||
0x1111222233334444555566667777888899990000, // Address
|
||||
0x111122223333444455556666777788889999000011, // One byte more than an address
|
||||
0x00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff, // exactly 32 bytes
|
||||
-0x0000000000000000000000000000000000000000000000000000000000000001, // exactly 32 bytes
|
||||
bytes(bytes32(0x00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff))[:],
|
||||
f,
|
||||
(),
|
||||
(0, 0),
|
||||
[0],
|
||||
[0][:],
|
||||
[0][0],
|
||||
new C(),
|
||||
S(0),
|
||||
E.A
|
||||
);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9640: (698-780): Explicit type conversion not allowed from "bytes32" to "bytes memory".
|
||||
// TypeError 1227: (698-783): Index range access is only supported for dynamic calldata arrays.
|
||||
// TypeError 1227: (865-871): Index range access is only supported for dynamic calldata arrays.
|
||||
// TypeError 9977: (134-139): Invalid type for argument in the string.concat function call. string type is required, but t_bool provided.
|
||||
// TypeError 9977: (153-154): Invalid type for argument in the string.concat function call. string type is required, but t_rational_1_by_1 provided.
|
||||
// TypeError 9977: (168-172): Invalid type for argument in the string.concat function call. string type is required, but t_rational_10000000000_by_1 provided.
|
||||
// TypeError 9977: (186-191): Invalid type for argument in the string.concat function call. string type is required, but t_rational_1_by_10000000000 provided.
|
||||
// TypeError 9977: (205-208): Invalid type for argument in the string.concat function call. string type is required, but t_rational_1_by_10 provided.
|
||||
// TypeError 9977: (222-231): Invalid type for argument in the string.concat function call. string type is required, but t_rational_19088743_by_1 provided.
|
||||
// TypeError 9977: (245-285): Invalid type for argument in the string.concat function call. string type is required, but t_rational_380605192295934637532253317235440047844071680_by_1 provided.
|
||||
// TypeError 9977: (336-378): Invalid type for argument in the string.concat function call. string type is required, but t_address provided.
|
||||
// TypeError 9977: (405-449): Invalid type for argument in the string.concat function call. string type is required, but t_rational_24943341882306372405313753398341798975509081620497_by_1 provided.
|
||||
// TypeError 9977: (496-562): Invalid type for argument in the string.concat function call. string type is required, but t_rational_30272441630670900764332283662402067049651745785153368133042924362431065855_by_1 provided.
|
||||
// TypeError 9977: (597-664): Invalid type for argument in the string.concat function call. string type is required, but t_rational_minus_1_by_1 provided.
|
||||
// TypeError 9977: (698-783): Invalid type for argument in the string.concat function call. string type is required, but t_bytes_memory_ptr_slice provided.
|
||||
// TypeError 9977: (797-798): Invalid type for argument in the string.concat function call. string type is required, but t_function_internal_nonpayable$__$returns$__$ provided.
|
||||
// TypeError 9977: (812-814): Invalid type for argument in the string.concat function call. string type is required, but t_tuple$__$ provided.
|
||||
// TypeError 9977: (828-834): Invalid type for argument in the string.concat function call. string type is required, but t_tuple$_t_rational_0_by_1_$_t_rational_0_by_1_$ provided.
|
||||
// TypeError 9977: (848-851): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_uint8_$1_memory_ptr provided.
|
||||
// TypeError 9977: (865-871): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_uint8_$1_memory_ptr_slice provided.
|
||||
// TypeError 9977: (885-891): Invalid type for argument in the string.concat function call. string type is required, but t_uint8 provided.
|
||||
// TypeError 9977: (905-912): Invalid type for argument in the string.concat function call. string type is required, but t_contract$_C_$61 provided.
|
||||
// TypeError 9977: (926-930): Invalid type for argument in the string.concat function call. string type is required, but t_struct$_S_$4_memory_ptr provided.
|
||||
// TypeError 9977: (944-947): Invalid type for argument in the string.concat function call. string type is required, but t_enum$_E_$8 provided.
|
@ -0,0 +1,33 @@
|
||||
contract C {
|
||||
function f() public pure {
|
||||
string.concat(
|
||||
0,
|
||||
-0,
|
||||
0.0,
|
||||
-0.0,
|
||||
0e10,
|
||||
-0e10,
|
||||
0e-10,
|
||||
-0e-10,
|
||||
(0),
|
||||
0x00,
|
||||
-0x00,
|
||||
0x0000000000000000000000000000000000000000000000000000000000000000, // exactly 32 bytes
|
||||
-0x0000000000000000000000000000000000000000000000000000000000000000 // exactly 32 bytes
|
||||
);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9977: (79-80): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (94-96): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (110-113): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (127-131): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (145-149): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (163-168): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (182-187): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (201-207): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (221-224): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (238-242): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (256-261): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (275-341): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (375-442): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
Loading…
Reference in New Issue
Block a user