From 235638b3fc2ae96c06057e8c4782d864292a3aee Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 20 May 2019 12:01:47 +0200 Subject: [PATCH] Implements constructor code for state variables. --- libsolidity/codegen/ir/IRGenerator.cpp | 49 +++++++++++++++---- .../codegen/ir/IRGeneratorForStatements.cpp | 15 ++++++ .../codegen/ir/IRGeneratorForStatements.h | 3 ++ .../standard_ir_requested/output.json | 3 ++ test/libsolidity/SolidityEndToEndTest.cpp | 6 ++- .../state_var_initialization.sol | 14 ++++++ 6 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 test/libsolidity/semanticTests/state_var_initialization.sol diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index e3b4d5401..9c7834ff7 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -39,6 +39,9 @@ #include #include +#include + +#include 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) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 094ac8ddd..6aadeb22b 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -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()) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index f8a0eadd0..d64ab9e0a 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -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; diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index dfe29f802..1b45e4586 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -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\")) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 66a9af271..0ea719f9a 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -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) diff --git a/test/libsolidity/semanticTests/state_var_initialization.sol b/test/libsolidity/semanticTests/state_var_initialization.sol new file mode 100644 index 000000000..ba97a9441 --- /dev/null +++ b/test/libsolidity/semanticTests/state_var_initialization.sol @@ -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