diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index bcb309c99..38ed88f4c 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1333,6 +1333,35 @@ string YulUtilFunctions::allocateMemoryArrayFunction(ArrayType const& _type) string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) { + if (_from.category() == Type::Category::Function) + { + solAssert(_to.category() == Type::Category::Function, ""); + FunctionType const& fromType = dynamic_cast(_from); + FunctionType const& targetType = dynamic_cast(_to); + solAssert( + fromType.isImplicitlyConvertibleTo(targetType) && + fromType.sizeOnStack() == targetType.sizeOnStack() && + (fromType.kind() == FunctionType::Kind::Internal || fromType.kind() == FunctionType::Kind::External) && + fromType.kind() == targetType.kind(), + "Invalid function type conversion requested." + ); + string const functionName = + "convert_" + + _from.identifier() + + "_to_" + + _to.identifier(); + return m_functionCollector->createFunction(functionName, [&]() { + return Whiskers(R"( + function (addr, functionId) -> outAddr, outFunctionId { + outAddr := addr + outFunctionId := functionId + } + )") + ("functionName", functionName) + .render(); + }); + } + if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1) return conversionFunctionSpecial(_from, _to); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index b40768be2..7ce1785b6 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -47,6 +47,7 @@ using namespace std; using namespace solidity; using namespace solidity::util; using namespace solidity::frontend; +using namespace std::string_literals; namespace { @@ -1212,7 +1213,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall( argumentTypes.emplace_back(&type(*arg)); argumentStrings.emplace_back(IRVariable(*arg).commaSeparatedList()); } - string argumentString = ", " + joinHumanReadable(argumentStrings); + string argumentString = argumentStrings.empty() ? ""s : (", " + joinHumanReadable(argumentStrings)); solUnimplementedAssert(funKind != FunctionType::Kind::ECRecover, ""); diff --git a/test/libsolidity/semanticTests/viaYul/conversion/function_cast.sol b/test/libsolidity/semanticTests/viaYul/conversion/function_cast.sol new file mode 100644 index 000000000..08462c5f8 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/conversion/function_cast.sol @@ -0,0 +1,23 @@ +contract C { + function f(uint x) public pure returns (uint) { + return 2 * x; + } + function g() public view returns (function (uint) external returns (uint)) { + return this.f; + } + function h(uint x) public returns (uint) { + return this.g()(x) + 1; + } + function t() external view returns ( + function(uint) external returns (uint) a, + function(uint) external view returns (uint) b) { + a = this.f; + b = this.f; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 2 -> 4 +// h(uint256): 2 -> 5 +// t() -> 0xFDD67305928FCAC8D213D1E47BFA6165CD0B87BB3DE648B0000000000000000, 0xFDD67305928FCAC8D213D1E47BFA6165CD0B87BB3DE648B0000000000000000