[Sol2Yul] Adding support for constructors with parameters in case of inheritance

This commit is contained in:
Djordje Mijovic 2020-04-06 17:26:59 +02:00
parent d0fcd468f6
commit 5329da93fb
22 changed files with 476 additions and 82 deletions

View File

@ -2334,3 +2334,39 @@ string YulUtilFunctions::extractReturndataFunction()
});
}
string YulUtilFunctions::copyConstructorArgumentsToMemoryFunction(
ContractDefinition const& _contract,
string const& _creationObjectName
)
{
string functionName = "copy_arguments_for_constructor_" +
toString(_contract.constructor()->id()) +
"_object_" +
_contract.name() +
"_" +
toString(_contract.id());
return m_functionCollector.createFunction(functionName, [&]() {
string returnParams = suffixedVariableNameList("ret_param_",0, _contract.constructor()->parameters().size());
ABIFunctions abiFunctions(m_evmVersion, m_revertStrings, m_functionCollector);
return util::Whiskers(R"(
function <functionName>() -> <retParams> {
let programSize := datasize("<object>")
let argSize := sub(codesize(), programSize)
let memoryDataOffset := <allocate>(argSize)
codecopy(memoryDataOffset, programSize, argSize)
<retParams> := <abiDecode>(memoryDataOffset, add(memoryDataOffset, argSize))
}
)")
("functionName", functionName)
("retParams", returnParams)
("object", _creationObjectName)
("allocate", allocationFunction())
("abiDecode", abiFunctions.tupleDecoder(FunctionType(*_contract.constructor()).parameterTypes(), true))
.render();
});
}

View File

@ -337,6 +337,13 @@ public:
/// If returndatacopy() is not supported by the underlying target, a empty array will be returned instead.
std::string extractReturndataFunction();
/// @returns function name that returns constructor arguments copied to memory
/// signature: () -> arguments
std::string copyConstructorArgumentsToMemoryFunction(
ContractDefinition const& _contract,
std::string const& _creationObjectName
);
private:
/// Special case of conversionFunction - handles everything that does not
/// use exactly one variable to hold the value.

View File

@ -81,7 +81,9 @@ string IRGenerator::generate(ContractDefinition const& _contract)
object "<CreationObject>" {
code {
<memoryInit>
<constructor>
<callValueCheck>
<?constructorHasParams> let <constructorParams> := <copyConstructorArguments>() </constructorHasParams>
<implicitConstructor>(<constructorParams>)
<deploy>
<functions>
}
@ -99,8 +101,25 @@ string IRGenerator::generate(ContractDefinition const& _contract)
t("CreationObject", creationObjectName(_contract));
t("memoryInit", memoryInit());
t("constructor", constructorCode(_contract));
FunctionDefinition const* constructor = _contract.constructor();
t("callValueCheck", !constructor || !constructor->isPayable() ? callValueCheck() : "");
vector<string> constructorParams;
if (constructor && !constructor->parameters().empty())
{
for (size_t i = 0; i < constructor->parameters().size(); ++i)
constructorParams.emplace_back(m_context.newYulVariable());
t(
"copyConstructorArguments",
m_utils.copyConstructorArgumentsToMemoryFunction(_contract, creationObjectName(_contract))
);
}
t("constructorParams", joinHumanReadable(constructorParams));
t("constructorHasParams", !constructorParams.empty());
t("implicitConstructor", implicitConstructorName(_contract));
t("deploy", deployCode(_contract));
generateImplicitConstructors(_contract);
generateQueuedFunctions();
t("functions", m_context.functionCollector().requestedFunctions());
@ -238,64 +257,115 @@ string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDec
return generator.code();
}
string IRGenerator::constructorCode(ContractDefinition const& _contract)
pair<string, map<ContractDefinition const*, string>> IRGenerator::evaluateConstructorArguments(
ContractDefinition const& _contract
)
{
// Initialization of state variables in base-to-derived order.
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
map<ContractDefinition const*, string> constructorParams;
vector<pair<ContractDefinition const*, std::vector<ASTPointer<Expression>>const *>> baseConstructorArguments;
using boost::adaptors::reverse;
for (ASTPointer<InheritanceSpecifier> const& base: _contract.baseContracts())
if (FunctionDefinition const* baseConstructor = dynamic_cast<ContractDefinition const*>(
base->name().annotation().referencedDeclaration
)->constructor(); baseConstructor && base->arguments())
baseConstructorArguments.emplace_back(
dynamic_cast<ContractDefinition const*>(baseConstructor->scope()),
base->arguments()
);
ostringstream out;
if (FunctionDefinition const* constructor = _contract.constructor())
for (auto const& modifier: constructor->modifiers())
if (FunctionDefinition const* baseConstructor = dynamic_cast<ContractDefinition const*>(
modifier->name()->annotation().referencedDeclaration
)->constructor(); baseConstructor && modifier->arguments())
baseConstructorArguments.emplace_back(
dynamic_cast<ContractDefinition const*>(baseConstructor->scope()),
modifier->arguments()
);
FunctionDefinition const* constructor = _contract.constructor();
if (constructor && !constructor->isPayable())
out << callValueCheck();
for (ContractDefinition const* contract: reverse(_contract.annotation().linearizedBaseContracts))
IRGeneratorForStatements generator{m_context, m_utils};
for (auto&& [baseContract, arguments]: baseConstructorArguments)
{
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() && !variable->immutable())
generator.initializeStateVar(*variable);
out << generator.code();
out << "// End state variable initialization for contract \"" << contract->name() << "\".\n";
solAssert(baseContract && arguments, "");
if (baseContract->constructor() && !arguments->empty())
{
vector<string> params;
for (size_t i = 0; i < arguments->size(); ++i)
params.emplace_back(generator.evaluateExpression(
*(arguments->at(i)),
*(baseContract->constructor()->parameters()[i]->type())
).commaSeparatedList());
constructorParams[baseContract] = joinHumanReadable(params);
}
}
if (constructor)
return {generator.code(), constructorParams};
}
string IRGenerator::initStateVariables(ContractDefinition const& _contract)
{
IRGeneratorForStatements generator{m_context, m_utils};
for (VariableDeclaration const* variable: _contract.stateVariables())
if (!variable->isConstant() && !variable->immutable())
generator.initializeStateVar(*variable);
return generator.code();
}
void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contract)
{
auto listAllParams = [&](
map<ContractDefinition const*, string> const& baseParams) -> string
{
ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector());
unsigned paramVars = make_shared<TupleType>(constructor->functionType(false)->parameterTypes())->sizeOnStack();
vector<string> params;
for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
if (baseParams.count(contract))
params.emplace_back(baseParams.at(contract));
return joinHumanReadable(params);
};
Whiskers t(R"X(
let programSize := datasize("<object>")
let argSize := sub(codesize(), programSize)
map<ContractDefinition const*, string> baseConstructorParams;
for (size_t i = 0; i < _contract.annotation().linearizedBaseContracts.size(); ++i)
{
ContractDefinition const* contract = _contract.annotation().linearizedBaseContracts[i];
baseConstructorParams.erase(contract);
let memoryDataOffset := <allocate>(argSize)
codecopy(memoryDataOffset, programSize, argSize)
m_context.functionCollector().createFunction(implicitConstructorName(*contract), [&]() {
Whiskers t(R"(
function <functionName>(<params><comma><baseParams>) {
<evalBaseArguments>
<?hasNextConstructor> <nextConstructor>(<nextParams>) </hasNextConstructor>
<initStateVariables>
<userDefinedConstructorBody>
}
)");
string params;
if (contract->constructor())
for (ASTPointer<VariableDeclaration> const& varDecl: contract->constructor()->parameters())
params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList();
t("params", params);
string baseParamsString = listAllParams(baseConstructorParams);
t("baseParams", baseParamsString);
t("comma", !params.empty() && !baseParamsString.empty() ? ", " : "");
t("functionName", implicitConstructorName(*contract));
pair<string, map<ContractDefinition const*, string>> evaluatedArgs = evaluateConstructorArguments(*contract);
baseConstructorParams.insert(evaluatedArgs.second.begin(), evaluatedArgs.second.end());
t("evalBaseArguments", evaluatedArgs.first);
if (i < _contract.annotation().linearizedBaseContracts.size() - 1)
{
t("hasNextConstructor", true);
ContractDefinition const* nextContract = _contract.annotation().linearizedBaseContracts[i + 1];
t("nextConstructor", implicitConstructorName(*nextContract));
t("nextParams", listAllParams(baseConstructorParams));
}
else
t("hasNextConstructor", false);
t("initStateVariables", initStateVariables(*contract));
t("userDefinedConstructorBody", contract->constructor() ? generate(contract->constructor()->body()) : "");
<assignToParams> <abiDecode>(memoryDataOffset, add(memoryDataOffset, argSize))
<constructorName>(<params>)
)X");
t("object", creationObjectName(_contract));
t("allocate", m_utils.allocationFunction());
t("assignToParams", paramVars == 0 ? "" : "let " + suffixedVariableNameList("param_", 0, paramVars) + " := ");
t("params", suffixedVariableNameList("param_", 0, paramVars));
t("abiDecode", abiFunctions.tupleDecoder(constructor->functionType(false)->parameterTypes(), true));
t("constructorName", m_context.enqueueFunctionForCodeGeneration(*constructor));
out << t.render();
return t.render();
});
}
return out.str();
}
string IRGenerator::deployCode(ContractDefinition const& _contract)
@ -323,6 +393,11 @@ string IRGenerator::runtimeObjectName(ContractDefinition const& _contract)
return _contract.name() + "_" + to_string(_contract.id()) + "_deployed";
}
string IRGenerator::implicitConstructorName(ContractDefinition const& _contract)
{
return "constructor_" + _contract.name() + "_" + to_string(_contract.id());
}
string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
{
Whiskers t(R"X(

View File

@ -67,12 +67,29 @@ private:
/// Generates code that assigns the initial value of the respective type.
std::string generateInitialAssignment(VariableDeclaration const& _varDecl);
std::string constructorCode(ContractDefinition const& _contract);
/// Generates implicit constructors for all contracts in the inheritance hierarchy of
/// @a _contract
/// If there are user defined constructors, their body will be included in implicit constructors body.
void generateImplicitConstructors(ContractDefinition const& _contract);
/// Evaluates constructor's arguments for all base contracts (listed in inheritance specifiers) of
/// @a _contract
/// @returns Pair of expressions needed to evaluate params and list of parameters in a map contract -> params
std::pair<std::string, std::map<ContractDefinition const*, std::string>> evaluateConstructorArguments(
ContractDefinition const& _contract
);
/// Initializes state variables of
/// @a _contract
/// @returns Source code to initialize state variables
std::string initStateVariables(ContractDefinition const& _contract);
std::string deployCode(ContractDefinition const& _contract);
std::string callValueCheck();
std::string creationObjectName(ContractDefinition const& _contract);
std::string runtimeObjectName(ContractDefinition const& _contract);
std::string implicitConstructorName(ContractDefinition const& _contract);
std::string dispatchRoutine(ContractDefinition const& _contract);

View File

@ -169,6 +169,14 @@ void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _va
assign(m_context.localVariable(_varDecl), zero);
}
IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expression, Type const& _targetType)
{
_expression.accept(*this);
IRVariable variable{m_context.newYulVariable(), _targetType};
define(variable, _expression);
return variable;
}
void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement)
{
if (Expression const* expression = _varDeclStatement.initialValue())

View File

@ -51,6 +51,9 @@ public:
/// Generates code to initialize the given local variable.
void initializeLocalVar(VariableDeclaration const& _varDecl);
/// Calculates expression's value and returns variable where it was stored
IRVariable evaluateExpression(Expression const& _expression, Type const& _to);
void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
bool visit(Conditional const& _conditional) override;
bool visit(Assignment const& _assignment) override;

View File

@ -1,6 +1,8 @@
{"contracts":{"A":{"C":{"ewasm":{"wast":"(module
;; sub-module \"C_2_deployed\" will be encoded as custom section in binary here, but is skipped in text mode.
(import \"ethereum\" \"codeCopy\" (func $eth.codeCopy (param i32 i32 i32)))
(import \"ethereum\" \"revert\" (func $eth.revert (param i32 i32)))
(import \"ethereum\" \"getCallValue\" (func $eth.getCallValue (param i32)))
(import \"ethereum\" \"finish\" (func $eth.finish (param i32 i32)))
(memory $memory (export \"memory\") 1)
(export \"main\" (func $main))
@ -9,27 +11,30 @@
(local $_1 i64)
(local $p i64)
(local $r i64)
(local $hi i64)
(local $hi_1 i64)
(local $y i64)
(local $hi_2 i64)
(local $_2 i64)
(local $z1 i64)
(local $z2 i64)
(local $z3 i64)
(local $_3 i64)
(local.set $_1 (i64.const 0))
(local.set $p (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 64)))
(local.set $r (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $p)) (i32.wrap_i64 (i64.const 64)))))
(if (i64.ne (i64.extend_i32_u (i32.lt_u (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (local.get $p)))) (i64.const 0)) (then
(unreachable)))
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $_1)) (i64.const 16)))
(local.set $hi_1 (i64.shl (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $_1) (i64.const 16)))) (i64.const 32)))
(local.set $y (i64.or (local.get $hi_1) (call $endian_swap_32 (i64.shr_u (local.get $_1) (i64.const 32)))))
(i64.store (i32.wrap_i64 (local.get $r)) (local.get $y))
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 8))))) (local.get $y))
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 16))))) (local.get $y))
(local.set $hi_2 (i64.shl (call $endian_swap_32 (i64.const 128)) (i64.const 32)))
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 24))))) (i64.or (local.get $hi_2) (call $endian_swap_32 (i64.shr_u (i64.const 128) (i64.const 32)))))
(local.set $_2 (datasize \"C_2_deployed\"))
(call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\"))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))))
(call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))))
(local.set $_2 (call $endian_swap (local.get $_1)))
(i64.store (i32.wrap_i64 (local.get $r)) (local.get $_2))
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 8))))) (local.get $_2))
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 16))))) (local.get $_2))
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (i64.const 128)))
(call $eth.getCallValue (i32.wrap_i64 (i64.const 0)))
(local.set $z1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.const 0)))))
(local.set $z2 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 8))))))))
(local.set $z3 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 16))))))))
(if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $z1) (local.get $z2)) (i64.or (local.get $z3) (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 24)))))))))))))) (i64.const 0)) (then
(call $revert (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))))
(local.set $_3 (datasize \"C_2_deployed\"))
(call $codecopy (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\") (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))
(call $return (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))
)
(func $u256_to_i32
@ -62,6 +67,22 @@
(local.get $r)
)
(func $codecopy
(param $x1 i64)
(param $x2 i64)
(param $x3 i64)
(param $x4 i64)
(param $y1 i64)
(param $y2 i64)
(param $y3 i64)
(param $y4 i64)
(param $z1 i64)
(param $z2 i64)
(param $z3 i64)
(param $z4 i64)
(call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $z1) (local.get $z2) (local.get $z3) (local.get $z4))))
)
(func $endian_swap_16
(param $x i64)
(result i64)
@ -80,5 +101,39 @@
(local.get $y)
)
(func $endian_swap
(param $x i64)
(result i64)
(local $y i64)
(local $hi i64)
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
(local.get $y)
)
(func $return
(param $x1 i64)
(param $x2 i64)
(param $x3 i64)
(param $x4 i64)
(param $y1 i64)
(param $y2 i64)
(param $y3 i64)
(param $y4 i64)
(call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))))
)
(func $revert
(param $x1 i64)
(param $x2 i64)
(param $x3 i64)
(param $x4 i64)
(param $y1 i64)
(param $y2 i64)
(param $y3 i64)
(param $y4 i64)
(call $eth.revert (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))))
)
)
"}}}},"sources":{"A":{"id":0}}}

View File

@ -8,8 +8,12 @@
object \"C_6\" {
code {
mstore(64, 128)
if callvalue() { revert(0, 0) }
constructor_C_6()
codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))
return(0, datasize(\"C_6_deployed\"))
function constructor_C_6()
{ }
}
object \"C_6_deployed\" {
code {

View File

@ -9,15 +9,21 @@
object \"C_6\" {
code {
mstore(64, 128)
if callvalue() { revert(0, 0) }
// Begin state variable initialization for contract \"C\" (0 variables)
// End state variable initialization for contract \"C\".
constructor_C_6()
codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))
return(0, datasize(\"C_6_deployed\"))
function constructor_C_6() {
}
}
object \"C_6_deployed\" {
code {

View File

@ -9,15 +9,21 @@
object \"C_10\" {
code {
mstore(64, 128)
if callvalue() { revert(0, 0) }
// Begin state variable initialization for contract \"C\" (0 variables)
// End state variable initialization for contract \"C\".
constructor_C_10()
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
return(0, datasize(\"C_10_deployed\"))
function constructor_C_10() {
}
}
object \"C_10_deployed\" {
code {

View File

@ -9,15 +9,21 @@
object \"C_10\" {
code {
mstore(64, 128)
if callvalue() { revert(0, 0) }
// Begin state variable initialization for contract \"C\" (0 variables)
// End state variable initialization for contract \"C\".
constructor_C_10()
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
return(0, datasize(\"C_10_deployed\"))
function constructor_C_10() {
}
}
object \"C_10_deployed\" {
code {

View File

@ -9,15 +9,21 @@
object \"C_10\" {
code {
mstore(64, 128)
if callvalue() { revert(0, 0) }
// Begin state variable initialization for contract \"C\" (0 variables)
// End state variable initialization for contract \"C\".
constructor_C_10()
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
return(0, datasize(\"C_10_deployed\"))
function constructor_C_10() {
}
}
object \"C_10_deployed\" {
code {

View File

@ -9,15 +9,21 @@
object \"C_10\" {
code {
mstore(64, 128)
if callvalue() { revert(0, 0) }
// Begin state variable initialization for contract \"C\" (0 variables)
// End state variable initialization for contract \"C\".
constructor_C_10()
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
return(0, datasize(\"C_10_deployed\"))
function constructor_C_10() {
}
}
object \"C_10_deployed\" {
code {

View File

@ -9,15 +9,21 @@
object \"C_10\" {
code {
mstore(64, 128)
if callvalue() { revert(0, 0) }
// Begin state variable initialization for contract \"C\" (0 variables)
// End state variable initialization for contract \"C\".
constructor_C_10()
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
return(0, datasize(\"C_10_deployed\"))
function constructor_C_10() {
}
}
object \"C_10_deployed\" {
code {

View File

@ -0,0 +1,14 @@
contract A {
uint x = 42;
function f() public returns(uint256) {
return x;
}
}
contract B is A {
uint public y = f();
}
// ====
// compileViaYul: true
// ----
// constructor() ->
// y() -> 42

View File

@ -0,0 +1,17 @@
contract A {
uint x;
constructor() public {
x = 42;
}
function f() public returns(uint256) {
return x;
}
}
contract B is A {
uint public y = f();
}
// ====
// compileViaYul: true
// ----
// constructor() ->
// y() -> 42

View File

@ -0,0 +1,28 @@
contract A {
uint public i;
uint public k;
constructor(uint newI, uint newK) public {
i = newI;
k = newK;
}
}
abstract contract B is A {
uint public j;
constructor(uint newJ) public {
j = newJ;
}
}
contract C is A {
constructor(uint newI, uint newK) A(newI, newK) public {}
}
contract D is B, C {
constructor(uint newI, uint newK) B(newI) C(newI, newK + 1) public {}
}
// ====
// compileViaYul: also
// ----
// constructor(): 2, 0 ->
// i() -> 2
// j() -> 2
// k() -> 1

View File

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

View File

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

View File

@ -0,0 +1,14 @@
contract A {
uint public x = 0;
uint y = f();
function f() public returns (uint256) {
++x;
return 42;
}
}
contract B is A {
}
// ====
// compileViaYul: also
// ----
// x() -> 1

View File

@ -0,0 +1,18 @@
contract A {
uint public x = 0;
uint y = f();
function f() public returns (uint256) {
++x;
return 42;
}
}
contract B is A {
uint public z;
constructor() public {
z = x;
}
}
// ====
// compileViaYul: also
// ----
// z() -> 1

View File

@ -0,0 +1,29 @@
contract A {
uint public a = 42;
uint public b;
uint public c;
constructor(uint x) public {
b = a;
a = x;
}
function f(uint x) public returns (uint256) { c = x * 3; return 23; }
}
contract B is A {
uint public d = f(a);
uint public e = b;
uint public b_a;
uint public b_b;
uint public b_c;
constructor() public A(17) { b_a = a; b_b = b; b_c = c; }
}
// ====
// compileViaYul: true
// ----
// a() -> 17
// b() -> 42
// c() -> 51
// b_a() -> 17
// b_b() -> 42
// b_c() -> 51
// d() -> 23
// e() -> 42