Merge pull request #6787 from ethereum/sol2yul-ctor-code

Improve constructor-code codegen (wrt. state variable initialization)
This commit is contained in:
chriseth 2019-08-05 11:50:34 +02:00 committed by GitHub
commit 9b375edfe3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 78 additions and 12 deletions

View File

@ -39,6 +39,9 @@
#include <liblangutil/SourceReferenceFormatter.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <sstream>
using namespace std;
using namespace dev;
@ -177,19 +180,45 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
string IRGenerator::constructorCode(ContractDefinition const& _contract)
{
// TODO initialize state variables in base to derived order.
// TODO base constructors
// TODO callValueCheck if there is no constructor.
if (FunctionDefinition const* constructor = _contract.constructor())
// Initialization of state variables in base-to-derived order.
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
using boost::adaptors::reverse;
ostringstream out;
FunctionDefinition const* constructor = _contract.constructor();
if (constructor && !constructor->isPayable())
out << callValueCheck();
for (ContractDefinition const* contract: reverse(_contract.annotation().linearizedBaseContracts))
{
string out;
if (!constructor->isPayable())
out = callValueCheck();
solUnimplementedAssert(constructor->parameters().empty(), "");
return move(out) + m_context.functionName(*constructor) + "()\n";
out <<
"\n// Begin state variable initialization for contract \"" <<
contract->name() <<
"\" (" <<
contract->stateVariables().size() <<
" variables)\n";
IRGeneratorForStatements generator{m_context, m_utils};
for (VariableDeclaration const* variable: contract->stateVariables())
if (!variable->isConstant())
generator.initializeStateVar(*variable);
out << generator.code();
out << "// End state variable initialization for contract \"" << contract->name() << "\".\n";
}
return {};
if (constructor)
{
solUnimplementedAssert(constructor->parameters().empty(), "");
// TODO base constructors
out << m_context.functionName(*constructor) + "()\n";
}
return out.str();
}
string IRGenerator::deployCode(ContractDefinition const& _contract)

View File

@ -133,6 +133,21 @@ string IRGeneratorForStatements::code() const
return m_code.str();
}
void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _varDecl)
{
solAssert(m_context.isStateVariable(_varDecl), "Must be a state variable.");
solAssert(!_varDecl.isConstant(), "");
if (_varDecl.value())
{
_varDecl.value()->accept(*this);
string value = m_context.newYulVariable();
Type const& varType = *_varDecl.type();
m_code << "let " << value << " := " << expressionAsType(*_varDecl.value(), varType) << "\n";
m_code << IRStorageItem{m_context, _varDecl}.storeValue(value, varType);
}
}
void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement)
{
for (auto const& decl: _varDeclStatement.declarations())

View File

@ -45,6 +45,9 @@ public:
std::string code() const;
/// Generates code to initialize the given state variable.
void initializeStateVar(VariableDeclaration const& _varDecl);
void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
bool visit(Assignment const& _assignment) override;
bool visit(TupleExpression const& _tuple) override;

View File

@ -10,6 +10,9 @@ object \"C_6\" {
code {
mstore(64, 128)
// Begin state variable initialization for contract \"C\" (0 variables)
// End state variable initialization for contract \"C\".
codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))
return(0, datasize(\"C_6_deployed\"))

View File

@ -7921,8 +7921,10 @@ BOOST_AUTO_TEST_CASE(accessor_for_state_variable)
}
)";
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("ticketPrice()"), encodeArgs(u256(500)));
ALSO_VIA_YUL(
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("ticketPrice()"), encodeArgs(u256(500)));
);
}
BOOST_AUTO_TEST_CASE(accessor_for_const_state_variable)

View File

@ -0,0 +1,14 @@
contract C {
uint public i = 1;
uint public k = 2;
constructor() public {
i = i + i;
k = k - i;
}
}
// ====
// compileViaYul: also
// ----
// i() -> 2
// k() -> 0