mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8721 from ethereum/sol-yul-internal-library-calls
[Sol->Yul] Calls to internal library functions
This commit is contained in:
commit
a85736d874
@ -135,6 +135,11 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
|
|||||||
templ("arrow", _out > 0 ? "->" : "");
|
templ("arrow", _out > 0 ? "->" : "");
|
||||||
templ("assignment_op", _out > 0 ? ":=" : "");
|
templ("assignment_op", _out > 0 ? ":=" : "");
|
||||||
templ("out", suffixedVariableNameList("out_", 0, _out));
|
templ("out", suffixedVariableNameList("out_", 0, _out));
|
||||||
|
|
||||||
|
// UNIMPLEMENTED: Internal library calls via pointers are not implemented yet.
|
||||||
|
// We're not generating code for internal library functions here even though it's possible
|
||||||
|
// to call them via pointers. Right now such calls end up triggering the `default` case in
|
||||||
|
// the switch above.
|
||||||
vector<map<string, string>> functions;
|
vector<map<string, string>> functions;
|
||||||
for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts)
|
for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts)
|
||||||
for (FunctionDefinition const* function: contract->definedFunctions())
|
for (FunctionDefinition const* function: contract->definedFunctions())
|
||||||
|
@ -75,15 +75,15 @@ pair<string, string> IRGenerator::run(ContractDefinition const& _contract)
|
|||||||
|
|
||||||
string IRGenerator::generate(ContractDefinition const& _contract)
|
string IRGenerator::generate(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(!_contract.isLibrary(), "Libraries not yet implemented.");
|
|
||||||
|
|
||||||
Whiskers t(R"(
|
Whiskers t(R"(
|
||||||
object "<CreationObject>" {
|
object "<CreationObject>" {
|
||||||
code {
|
code {
|
||||||
<memoryInit>
|
<memoryInit>
|
||||||
<callValueCheck>
|
<callValueCheck>
|
||||||
|
<?notLibrary>
|
||||||
<?constructorHasParams> let <constructorParams> := <copyConstructorArguments>() </constructorHasParams>
|
<?constructorHasParams> let <constructorParams> := <copyConstructorArguments>() </constructorHasParams>
|
||||||
<implicitConstructor>(<constructorParams>)
|
<implicitConstructor>(<constructorParams>)
|
||||||
|
</notLibrary>
|
||||||
<deploy>
|
<deploy>
|
||||||
<functions>
|
<functions>
|
||||||
}
|
}
|
||||||
@ -101,6 +101,7 @@ string IRGenerator::generate(ContractDefinition const& _contract)
|
|||||||
|
|
||||||
t("CreationObject", creationObjectName(_contract));
|
t("CreationObject", creationObjectName(_contract));
|
||||||
t("memoryInit", memoryInit());
|
t("memoryInit", memoryInit());
|
||||||
|
t("notLibrary", !_contract.isLibrary());
|
||||||
|
|
||||||
FunctionDefinition const* constructor = _contract.constructor();
|
FunctionDefinition const* constructor = _contract.constructor();
|
||||||
t("callValueCheck", !constructor || !constructor->isPayable() ? callValueCheck() : "");
|
t("callValueCheck", !constructor || !constructor->isPayable() ? callValueCheck() : "");
|
||||||
|
@ -567,6 +567,14 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
arguments.push_back(callArguments[std::distance(callArgumentNames.begin(), it)]);
|
arguments.push_back(callArguments[std::distance(callArgumentNames.begin(), it)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression()))
|
||||||
|
if (auto expressionType = dynamic_cast<TypeType const*>(memberAccess->expression().annotation().type))
|
||||||
|
if (auto contractType = dynamic_cast<ContractType const*>(expressionType->actualType()))
|
||||||
|
solUnimplementedAssert(
|
||||||
|
!contractType->contractDefinition().isLibrary() || functionType->kind() == FunctionType::Kind::Internal,
|
||||||
|
"Only internal function calls implemented for libraries"
|
||||||
|
);
|
||||||
|
|
||||||
solUnimplementedAssert(!functionType->bound(), "");
|
solUnimplementedAssert(!functionType->bound(), "");
|
||||||
switch (functionType->kind())
|
switch (functionType->kind())
|
||||||
{
|
{
|
||||||
@ -579,32 +587,60 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
else
|
else
|
||||||
args.emplace_back(convert(*arguments[i], *parameterTypes[i]).commaSeparatedList());
|
args.emplace_back(convert(*arguments[i], *parameterTypes[i]).commaSeparatedList());
|
||||||
|
|
||||||
if (auto identifier = dynamic_cast<Identifier const*>(&_functionCall.expression()))
|
optional<FunctionDefinition const*> functionDef;
|
||||||
|
if (auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression()))
|
||||||
{
|
{
|
||||||
solAssert(!functionType->bound(), "");
|
solUnimplementedAssert(!functionType->bound(), "Internal calls to bound functions are not yet implemented for libraries and not allowed for contracts");
|
||||||
if (auto functionDef = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration))
|
|
||||||
|
functionDef = dynamic_cast<FunctionDefinition const*>(memberAccess->annotation().referencedDeclaration);
|
||||||
|
if (functionDef.value() != nullptr)
|
||||||
|
solAssert(functionType->declaration() == *memberAccess->annotation().referencedDeclaration, "");
|
||||||
|
else
|
||||||
{
|
{
|
||||||
define(_functionCall) <<
|
solAssert(dynamic_cast<VariableDeclaration const*>(memberAccess->annotation().referencedDeclaration), "");
|
||||||
m_context.enqueueFunctionForCodeGeneration(
|
solAssert(!functionType->hasDeclaration(), "");
|
||||||
functionDef->resolveVirtual(m_context.mostDerivedContract())
|
|
||||||
) <<
|
|
||||||
"(" <<
|
|
||||||
joinHumanReadable(args) <<
|
|
||||||
")\n";
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (auto identifier = dynamic_cast<Identifier const*>(&_functionCall.expression()))
|
||||||
|
{
|
||||||
|
solAssert(!functionType->bound(), "");
|
||||||
|
|
||||||
define(_functionCall) <<
|
if (auto unresolvedFunctionDef = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration))
|
||||||
// NOTE: internalDispatch() takes care of adding the function to function generation queue
|
{
|
||||||
m_context.internalDispatch(
|
functionDef = &unresolvedFunctionDef->resolveVirtual(m_context.mostDerivedContract());
|
||||||
TupleType(functionType->parameterTypes()).sizeOnStack(),
|
solAssert(functionType->declaration() == *identifier->annotation().referencedDeclaration, "");
|
||||||
TupleType(functionType->returnParameterTypes()).sizeOnStack()
|
}
|
||||||
) <<
|
else
|
||||||
"(" <<
|
{
|
||||||
IRVariable(_functionCall.expression()).part("functionIdentifier").name() <<
|
functionDef = nullptr;
|
||||||
joinHumanReadablePrefixed(args) <<
|
solAssert(dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration), "");
|
||||||
")\n";
|
solAssert(!functionType->hasDeclaration(), "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// Not a simple expression like x or A.x
|
||||||
|
functionDef = nullptr;
|
||||||
|
|
||||||
|
solAssert(functionDef.has_value(), "");
|
||||||
|
solAssert(functionDef.value() == nullptr || functionDef.value()->isImplemented(), "");
|
||||||
|
|
||||||
|
if (functionDef.value() != nullptr)
|
||||||
|
define(_functionCall) <<
|
||||||
|
m_context.enqueueFunctionForCodeGeneration(*functionDef.value()) <<
|
||||||
|
"(" <<
|
||||||
|
joinHumanReadable(args) <<
|
||||||
|
")\n";
|
||||||
|
else
|
||||||
|
define(_functionCall) <<
|
||||||
|
// NOTE: internalDispatch() takes care of adding the function to function generation queue
|
||||||
|
m_context.internalDispatch(
|
||||||
|
TupleType(functionType->parameterTypes()).sizeOnStack(),
|
||||||
|
TupleType(functionType->returnParameterTypes()).sizeOnStack()
|
||||||
|
) <<
|
||||||
|
"(" <<
|
||||||
|
IRVariable(_functionCall.expression()).part("functionIdentifier").name() <<
|
||||||
|
joinHumanReadablePrefixed(args) <<
|
||||||
|
")\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FunctionType::Kind::External:
|
case FunctionType::Kind::External:
|
||||||
@ -1297,9 +1333,9 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
|
|||||||
define(_identifier) << to_string(functionDef->resolveVirtual(m_context.mostDerivedContract()).id()) << "\n";
|
define(_identifier) << to_string(functionDef->resolveVirtual(m_context.mostDerivedContract()).id()) << "\n";
|
||||||
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
handleVariableReference(*varDecl, _identifier);
|
handleVariableReference(*varDecl, _identifier);
|
||||||
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
|
else if (dynamic_cast<ContractDefinition const*>(declaration))
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(!contract->isLibrary(), "Libraries not yet supported.");
|
// no-op
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<EventDefinition const*>(declaration))
|
else if (dynamic_cast<EventDefinition const*>(declaration))
|
||||||
{
|
{
|
||||||
|
@ -29,8 +29,7 @@ class Expression;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An IRVariable refers to a set of yul variables that correspond to the stack layout of a Solidity variable or expression
|
* An IRVariable refers to a set of yul variables that correspond to the stack layout of a Solidity variable or expression
|
||||||
* of a specific S
|
* of a specific Solidity type. If the Solidity type occupies a single stack slot, the IRVariable refers to a single yul variable.
|
||||||
* olidity type. If the Solidity type occupies a single stack slot, the IRVariable refers to a single yul variable.
|
|
||||||
* Otherwise the set of yul variables it refers to is (recursively) determined by @see ``Type::stackItems()``.
|
* Otherwise the set of yul variables it refers to is (recursively) determined by @see ``Type::stackItems()``.
|
||||||
* For example, an IRVariable referring to a dynamically sized calldata array will consist of two parts named
|
* For example, an IRVariable referring to a dynamically sized calldata array will consist of two parts named
|
||||||
* ``offset`` and ``length``, whereas an IRVariable referring to a statically sized calldata type, a storage reference
|
* ``offset`` and ``length``, whereas an IRVariable referring to a statically sized calldata type, a storage reference
|
||||||
|
@ -34,6 +34,8 @@ contract Child is Base {
|
|||||||
BaseBase.init(c, d);
|
BaseBase.init(c, d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// x() -> 0
|
// x() -> 0
|
||||||
// y() -> 0
|
// y() -> 0
|
||||||
|
@ -18,6 +18,8 @@ contract Child is Base {
|
|||||||
Base.init(c, d);
|
Base.init(c, d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// x() -> 0
|
// x() -> 0
|
||||||
// y() -> 0
|
// y() -> 0
|
||||||
|
@ -15,5 +15,7 @@ contract B {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// g() -> 1
|
// g() -> 1
|
||||||
|
@ -17,5 +17,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f() -> 2
|
// f() -> 2
|
||||||
|
@ -22,5 +22,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f() -> 2
|
// f() -> 2
|
||||||
|
@ -6,6 +6,8 @@ contract C {
|
|||||||
return L.f(v);
|
return L.f(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// g(uint256): 1 -> 1
|
// g(uint256): 1 -> 1
|
||||||
// g(uint256): 2 -> 4
|
// g(uint256): 2 -> 4
|
||||||
|
Loading…
Reference in New Issue
Block a user