Added support for FunctionType::Kind::StringConcat and functions string.concat

This commit is contained in:
nishant-sachdeva
2022-02-10 22:08:47 +05:30
parent f1be7e1e23
commit 276851ff91
24 changed files with 391 additions and 38 deletions
+37 -3
View File
@@ -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:
{
+6
View File
@@ -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,
+4 -4
View File
@@ -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;
}
+1
View File
@@ -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()
+11 -2
View File
@@ -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();
+21 -12
View File
@@ -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 {
+7 -3
View File
@@ -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: