mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Bound functions.
This commit is contained in:
parent
b62de4f16d
commit
f87edb6efc
@ -3017,6 +3017,11 @@ TypePointers FunctionType::parameterTypes() const
|
|||||||
return TypePointers(m_parameterTypes.cbegin() + 1, m_parameterTypes.cend());
|
return TypePointers(m_parameterTypes.cbegin() + 1, m_parameterTypes.cend());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypePointers const& FunctionType::parameterTypesIncludingSelf() const
|
||||||
|
{
|
||||||
|
return m_parameterTypes;
|
||||||
|
}
|
||||||
|
|
||||||
string FunctionType::richIdentifier() const
|
string FunctionType::richIdentifier() const
|
||||||
{
|
{
|
||||||
string id = "t_function_";
|
string id = "t_function_";
|
||||||
@ -3267,8 +3272,7 @@ vector<tuple<string, TypePointer>> FunctionType::makeStackItems() const
|
|||||||
if (m_saltSet)
|
if (m_saltSet)
|
||||||
slots.emplace_back("salt", TypeProvider::fixedBytes(32));
|
slots.emplace_back("salt", TypeProvider::fixedBytes(32));
|
||||||
if (bound())
|
if (bound())
|
||||||
for (auto const& [boundName, boundType]: m_parameterTypes.front()->stackItems())
|
slots.emplace_back("self", m_parameterTypes.front());
|
||||||
slots.emplace_back("self_" + boundName, boundType);
|
|
||||||
return slots;
|
return slots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1244,6 +1244,7 @@ public:
|
|||||||
static FunctionTypePointer newExpressionType(ContractDefinition const& _contract);
|
static FunctionTypePointer newExpressionType(ContractDefinition const& _contract);
|
||||||
|
|
||||||
TypePointers parameterTypes() const;
|
TypePointers parameterTypes() const;
|
||||||
|
TypePointers const& parameterTypesIncludingSelf() const;
|
||||||
std::vector<std::string> parameterNames() const;
|
std::vector<std::string> parameterNames() const;
|
||||||
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
|
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
|
||||||
/// @returns the list of return parameter types. All dynamically-sized types (this excludes
|
/// @returns the list of return parameter types. All dynamically-sized types (this excludes
|
||||||
|
@ -42,6 +42,7 @@ string ABIFunctions::tupleEncoder(
|
|||||||
bool _reversed
|
bool _reversed
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
solAssert(_givenTypes.size() == _targetTypes.size(), "");
|
||||||
EncodingOptions options;
|
EncodingOptions options;
|
||||||
options.encodeAsLibraryTypes = _encodeAsLibraryTypes;
|
options.encodeAsLibraryTypes = _encodeAsLibraryTypes;
|
||||||
options.encodeFunctionFromStack = true;
|
options.encodeFunctionFromStack = true;
|
||||||
|
@ -28,7 +28,7 @@ using namespace solidity::frontend;
|
|||||||
YulArity YulArity::fromType(FunctionType const& _functionType)
|
YulArity YulArity::fromType(FunctionType const& _functionType)
|
||||||
{
|
{
|
||||||
return YulArity{
|
return YulArity{
|
||||||
TupleType(_functionType.parameterTypes()).sizeOnStack(),
|
TupleType(_functionType.parameterTypesIncludingSelf()).sizeOnStack(),
|
||||||
TupleType(_functionType.returnParameterTypes()).sizeOnStack()
|
TupleType(_functionType.returnParameterTypes()).sizeOnStack()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -811,7 +811,6 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
|||||||
if (
|
if (
|
||||||
functionType &&
|
functionType &&
|
||||||
functionType->kind() == FunctionType::Kind::Internal &&
|
functionType->kind() == FunctionType::Kind::Internal &&
|
||||||
!functionType->bound() &&
|
|
||||||
IRHelpers::referencedFunctionDeclaration(_functionCall.expression())
|
IRHelpers::referencedFunctionDeclaration(_functionCall.expression())
|
||||||
)
|
)
|
||||||
m_context.internalFunctionCalledDirectly(_functionCall.expression());
|
m_context.internalFunctionCalledDirectly(_functionCall.expression());
|
||||||
@ -888,8 +887,6 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
solAssert(functionType->kind() == FunctionType::Kind::Internal || functionType->kind() == FunctionType::Kind::DelegateCall, "");
|
solAssert(functionType->kind() == FunctionType::Kind::Internal || functionType->kind() == FunctionType::Kind::DelegateCall, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
solAssert(!functionType->bound(), "");
|
|
||||||
|
|
||||||
switch (functionType->kind())
|
switch (functionType->kind())
|
||||||
{
|
{
|
||||||
@ -924,19 +921,17 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
}
|
}
|
||||||
|
|
||||||
solAssert(functionDef && functionDef->isImplemented(), "");
|
solAssert(functionDef && functionDef->isImplemented(), "");
|
||||||
|
solAssert(
|
||||||
|
functionDef->parameters().size() == arguments.size() + (functionType->bound() ? 1 : 0),
|
||||||
|
""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
solAssert(!functionType->takesArbitraryParameters(), "");
|
solAssert(!functionType->takesArbitraryParameters(), "");
|
||||||
|
|
||||||
vector<string> args;
|
vector<string> args;
|
||||||
if (functionType->bound())
|
if (functionType->bound())
|
||||||
{
|
args += IRVariable(_functionCall.expression()).part("self").stackSlots();
|
||||||
solAssert(memberAccess && functionDef, "");
|
|
||||||
solAssert(functionDef->parameters().size() == arguments.size() + 1, "");
|
|
||||||
args += convert(memberAccess->expression(), *functionDef->parameters()[0]->type()).stackSlots();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
solAssert(!functionDef || functionDef->parameters().size() == arguments.size(), "");
|
|
||||||
|
|
||||||
for (size_t i = 0; i < arguments.size(); ++i)
|
for (size_t i = 0; i < arguments.size(); ++i)
|
||||||
args += convert(*arguments[i], *parameterTypes[i]).stackSlots();
|
args += convert(*arguments[i], *parameterTypes[i]).stackSlots();
|
||||||
@ -1580,6 +1575,23 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
Type::Category::Array,
|
Type::Category::Array,
|
||||||
Type::Category::FixedBytes,
|
Type::Category::FixedBytes,
|
||||||
}).count(objectCategory) > 0, "");
|
}).count(objectCategory) > 0, "");
|
||||||
|
|
||||||
|
define(IRVariable(_memberAccess).part("self"), _memberAccess.expression());
|
||||||
|
auto const& functionDefinition = dynamic_cast<FunctionDefinition const&>(memberFunctionType->declaration());
|
||||||
|
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
|
||||||
|
if (memberFunctionType->kind() == FunctionType::Kind::Internal)
|
||||||
|
{
|
||||||
|
define(IRVariable(_memberAccess).part("functionIdentifier")) << to_string(functionDefinition.id()) << "\n";
|
||||||
|
m_context.internalFunctionAccessed(_memberAccess, functionDefinition);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(memberFunctionType->kind() == FunctionType::Kind::DelegateCall, "");
|
||||||
|
auto contract = dynamic_cast<ContractDefinition const*>(functionDefinition.scope());
|
||||||
|
solAssert(contract && contract->isLibrary(), "");
|
||||||
|
define(IRVariable(_memberAccess).part("address")) << linkerSymbol(*contract) << "\n";
|
||||||
|
define(IRVariable(_memberAccess).part("functionSelector")) << memberFunctionType->externalIdentifier();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2283,15 +2295,21 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
|||||||
"Can only be used for regular external calls."
|
"Can only be used for regular external calls."
|
||||||
);
|
);
|
||||||
|
|
||||||
solUnimplementedAssert(!funType.bound(), "");
|
|
||||||
|
|
||||||
bool const isDelegateCall = funKind == FunctionType::Kind::DelegateCall;
|
bool const isDelegateCall = funKind == FunctionType::Kind::DelegateCall;
|
||||||
bool const useStaticCall = funType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall();
|
bool const useStaticCall = funType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall();
|
||||||
|
|
||||||
ReturnInfo const returnInfo{m_context.evmVersion(), funType};
|
ReturnInfo const returnInfo{m_context.evmVersion(), funType};
|
||||||
|
|
||||||
|
TypePointers parameterTypes = funType.parameterTypes();
|
||||||
TypePointers argumentTypes;
|
TypePointers argumentTypes;
|
||||||
vector<string> argumentStrings;
|
vector<string> argumentStrings;
|
||||||
|
if (funType.bound())
|
||||||
|
{
|
||||||
|
parameterTypes.insert(parameterTypes.begin(), funType.selfType());
|
||||||
|
argumentTypes.emplace_back(funType.selfType());
|
||||||
|
argumentStrings += IRVariable(_functionCall.expression()).part("self").stackSlots();
|
||||||
|
}
|
||||||
|
|
||||||
for (auto const& arg: _arguments)
|
for (auto const& arg: _arguments)
|
||||||
{
|
{
|
||||||
argumentTypes.emplace_back(&type(*arg));
|
argumentTypes.emplace_back(&type(*arg));
|
||||||
@ -2370,7 +2388,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
|||||||
bool encodeForLibraryCall = funKind == FunctionType::Kind::DelegateCall;
|
bool encodeForLibraryCall = funKind == FunctionType::Kind::DelegateCall;
|
||||||
|
|
||||||
solAssert(funType.padArguments(), "");
|
solAssert(funType.padArguments(), "");
|
||||||
templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, funType.parameterTypes(), encodeForLibraryCall));
|
templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, parameterTypes, encodeForLibraryCall));
|
||||||
templ("argumentString", joinHumanReadablePrefixed(argumentStrings));
|
templ("argumentString", joinHumanReadablePrefixed(argumentStrings));
|
||||||
|
|
||||||
solAssert(!isDelegateCall || !funType.valueSet(), "Value set for delegatecall");
|
solAssert(!isDelegateCall || !funType.valueSet(), "Value set for delegatecall");
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Error (1834): Unimplemented feature error in <FILENAME REMOVED>
|
Error (1834): Unimplemented feature error in <FILENAME REMOVED>
|
||||||
--> yul_unimplemented/input.sol:8:9:
|
--> yul_unimplemented/input.sol:5:16:
|
||||||
|
|
|
|
||||||
8 | x.f();
|
5 | return type(test).name;
|
||||||
| ^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
pragma solidity >=0.0;
|
pragma solidity >=0.0;
|
||||||
library L { function f(uint) public {} }
|
|
||||||
contract test {
|
contract test {
|
||||||
using L for uint;
|
function f() public pure returns (string memory) {
|
||||||
function f() public {
|
return type(test).name;
|
||||||
uint x;
|
|
||||||
x.f();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,6 +14,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// library: D
|
// library: D
|
||||||
|
@ -14,6 +14,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// library: D
|
// library: D
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
library L {
|
||||||
|
struct S {
|
||||||
|
uint256[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f(S memory _s) internal {
|
||||||
|
_s.data[3] += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for L.S;
|
||||||
|
|
||||||
|
function f() public returns (uint256) {
|
||||||
|
L.S memory x;
|
||||||
|
x.data = new uint256[](7);
|
||||||
|
x.data[3] = 8;
|
||||||
|
(x.f)();
|
||||||
|
return x.data[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f() -> 0x0a
|
@ -0,0 +1,22 @@
|
|||||||
|
library L {
|
||||||
|
function f(string memory a) internal pure returns (string memory) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function g(string storage a) internal pure returns (string memory) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for string;
|
||||||
|
string s;
|
||||||
|
|
||||||
|
function test(string calldata x) public returns (string memory, string memory) {
|
||||||
|
s = x;
|
||||||
|
return (s.f(), s.g());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// test(string): 0x20, 3, "def" -> 0x40, 0x80, 3, "def", 3, "def"
|
Loading…
Reference in New Issue
Block a user