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("assignment_op", _out > 0 ? ":=" : "");
|
||||
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;
|
||||
for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts)
|
||||
for (FunctionDefinition const* function: contract->definedFunctions())
|
||||
|
@ -75,15 +75,15 @@ pair<string, string> IRGenerator::run(ContractDefinition const& _contract)
|
||||
|
||||
string IRGenerator::generate(ContractDefinition const& _contract)
|
||||
{
|
||||
solUnimplementedAssert(!_contract.isLibrary(), "Libraries not yet implemented.");
|
||||
|
||||
Whiskers t(R"(
|
||||
object "<CreationObject>" {
|
||||
code {
|
||||
<memoryInit>
|
||||
<callValueCheck>
|
||||
<?notLibrary>
|
||||
<?constructorHasParams> let <constructorParams> := <copyConstructorArguments>() </constructorHasParams>
|
||||
<implicitConstructor>(<constructorParams>)
|
||||
</notLibrary>
|
||||
<deploy>
|
||||
<functions>
|
||||
}
|
||||
@ -101,6 +101,7 @@ string IRGenerator::generate(ContractDefinition const& _contract)
|
||||
|
||||
t("CreationObject", creationObjectName(_contract));
|
||||
t("memoryInit", memoryInit());
|
||||
t("notLibrary", !_contract.isLibrary());
|
||||
|
||||
FunctionDefinition const* constructor = _contract.constructor();
|
||||
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)]);
|
||||
}
|
||||
|
||||
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(), "");
|
||||
switch (functionType->kind())
|
||||
{
|
||||
@ -579,32 +587,60 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
else
|
||||
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(), "");
|
||||
if (auto functionDef = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration))
|
||||
solUnimplementedAssert(!functionType->bound(), "Internal calls to bound functions are not yet implemented for libraries and not allowed for contracts");
|
||||
|
||||
functionDef = dynamic_cast<FunctionDefinition const*>(memberAccess->annotation().referencedDeclaration);
|
||||
if (functionDef.value() != nullptr)
|
||||
solAssert(functionType->declaration() == *memberAccess->annotation().referencedDeclaration, "");
|
||||
else
|
||||
{
|
||||
define(_functionCall) <<
|
||||
m_context.enqueueFunctionForCodeGeneration(
|
||||
functionDef->resolveVirtual(m_context.mostDerivedContract())
|
||||
) <<
|
||||
"(" <<
|
||||
joinHumanReadable(args) <<
|
||||
")\n";
|
||||
return;
|
||||
solAssert(dynamic_cast<VariableDeclaration const*>(memberAccess->annotation().referencedDeclaration), "");
|
||||
solAssert(!functionType->hasDeclaration(), "");
|
||||
}
|
||||
}
|
||||
else if (auto identifier = dynamic_cast<Identifier const*>(&_functionCall.expression()))
|
||||
{
|
||||
solAssert(!functionType->bound(), "");
|
||||
|
||||
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";
|
||||
if (auto unresolvedFunctionDef = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration))
|
||||
{
|
||||
functionDef = &unresolvedFunctionDef->resolveVirtual(m_context.mostDerivedContract());
|
||||
solAssert(functionType->declaration() == *identifier->annotation().referencedDeclaration, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
functionDef = nullptr;
|
||||
solAssert(dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration), "");
|
||||
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;
|
||||
}
|
||||
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";
|
||||
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||
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))
|
||||
{
|
||||
|
@ -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
|
||||
* of a specific S
|
||||
* olidity type. If the Solidity type occupies a single stack slot, the IRVariable refers to a single yul variable.
|
||||
* of a specific Solidity 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()``.
|
||||
* 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
|
||||
|
@ -34,6 +34,8 @@ contract Child is Base {
|
||||
BaseBase.init(c, d);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// x() -> 0
|
||||
// y() -> 0
|
||||
|
@ -18,6 +18,8 @@ contract Child is Base {
|
||||
Base.init(c, d);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// x() -> 0
|
||||
// y() -> 0
|
||||
|
@ -15,5 +15,7 @@ contract B {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 1
|
||||
|
@ -17,5 +17,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 2
|
||||
|
@ -22,5 +22,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 2
|
||||
|
@ -6,6 +6,8 @@ contract C {
|
||||
return L.f(v);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g(uint256): 1 -> 1
|
||||
// g(uint256): 2 -> 4
|
||||
|
Loading…
Reference in New Issue
Block a user