diff --git a/libsolidity/codegen/ir/IRGenerationContext.cpp b/libsolidity/codegen/ir/IRGenerationContext.cpp index 313aff40d..3fa403272 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.cpp +++ b/libsolidity/codegen/ir/IRGenerationContext.cpp @@ -144,29 +144,27 @@ string IRGenerationContext::generateInternalDispatchFunction(YulArity const& _ar templ("assignment_op", _arity.out > 0 ? ":=" : ""); templ("out", suffixedVariableNameList("out_", 0, _arity.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> functions; - for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts) - for (FunctionDefinition const* function: contract->definedFunctions()) - if ( - !function->isConstructor() && - YulArity::fromType(*TypeProvider::function(*function, FunctionType::Kind::Internal)) == _arity - ) - { - // 0 is reserved for uninitialized function pointers - solAssert(function->id() != 0, "Unexpected function ID: 0"); + vector> cases; + for (FunctionDefinition const* function: collectFunctionsOfArity(_arity)) + { + solAssert(function, ""); + solAssert( + YulArity::fromType(*TypeProvider::function(*function, FunctionType::Kind::Internal)) == _arity, + "A single dispatch function can only handle functions of one arity" + ); + solAssert(!function->isConstructor(), ""); + // 0 is reserved for uninitialized function pointers + solAssert(function->id() != 0, "Unexpected function ID: 0"); - functions.emplace_back(map { - { "funID", to_string(function->id()) }, - { "name", IRNames::function(*function)} - }); + cases.emplace_back(map{ + {"funID", to_string(function->id())}, + {"name", IRNames::function(*function)} + }); - enqueueFunctionForCodeGeneration(*function); - } - templ("cases", move(functions)); + enqueueFunctionForCodeGeneration(*function); + } + + templ("cases", move(cases)); return templ.render(); }); } @@ -186,3 +184,20 @@ std::string IRGenerationContext::revertReasonIfDebug(std::string const& _message return YulUtilFunctions::revertReasonIfDebug(m_revertStrings, _message); } +set IRGenerationContext::collectFunctionsOfArity(YulArity const& _arity) +{ + // UNIMPLEMENTED: Internal library calls via pointers are not implemented yet. + // We're not returning any internal library functions here even though it's possible + // to call them via pointers. Right now such calls end will up triggering the `default` case in + // the switch in the generated dispatch function. + set functions; + for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts) + for (FunctionDefinition const* function: contract->definedFunctions()) + if ( + !function->isConstructor() && + YulArity::fromType(*TypeProvider::function(*function, FunctionType::Kind::Internal)) == _arity + ) + functions.insert(function); + + return functions; +} diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 42cdddcb0..30aa5e220 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -120,6 +120,8 @@ public: std::set& subObjectsCreated() { return m_subObjects; } private: + std::set collectFunctionsOfArity(YulArity const& _arity); + langutil::EVMVersion m_evmVersion; RevertStrings m_revertStrings; OptimiserSettings m_optimiserSettings;