Browse Source

Allowing abstract contracts constructor to have no args

- If a constructor is part of an abstract contract we can omit its
  arguments

- IF a contract is abstract make sure to not create and/or request
  Assembly code about it since it's not compiled
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
45117f53b0
  1. 14
      libsolidity/AST.cpp
  2. 2
      libsolidity/AST.h
  3. 1
      libsolidity/Compiler.cpp
  4. 16
      libsolidity/CompilerStack.cpp
  5. 4
      libsolidity/CompilerStack.h
  6. 2
      mix/CodeModel.cpp
  7. 18
      test/SolidityNameAndTypeResolution.cpp

14
libsolidity/AST.cpp

@ -281,7 +281,7 @@ void InheritanceSpecifier::checkTypeRequirements()
ContractDefinition const* base = dynamic_cast<ContractDefinition const*>(m_baseName->getReferencedDeclaration());
solAssert(base, "Base contract not available.");
TypePointers parameterTypes = ContractType(*base).getConstructorType()->getParameterTypes();
if (parameterTypes.size() != m_arguments.size())
if (m_arguments.size() != 0 && parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call."));
for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
@ -348,8 +348,8 @@ void FunctionDefinition::checkTypeRequirements()
}
for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers)
modifier->checkTypeRequirements(isConstructor() ?
dynamic_cast<ContractDefinition const&>(*getScope()).getBaseContracts() :
vector<ASTPointer<InheritanceSpecifier>>());
dynamic_cast<ContractDefinition const&>(*getScope()).getLinearizedBaseContracts() :
vector<ContractDefinition const*>());
if (m_body)
m_body->checkTypeRequirements();
}
@ -426,7 +426,7 @@ void ModifierDefinition::checkTypeRequirements()
m_body->checkTypeRequirements();
}
void ModifierInvocation::checkTypeRequirements(vector<ASTPointer<InheritanceSpecifier>> const& _bases)
void ModifierInvocation::checkTypeRequirements(vector<ContractDefinition const*> const& _bases)
{
m_modifierName->checkTypeRequirements();
for (ASTPointer<Expression> const& argument: m_arguments)
@ -439,10 +439,10 @@ void ModifierInvocation::checkTypeRequirements(vector<ASTPointer<InheritanceSpec
parameters = &modifier->getParameters();
else
// check parameters for Base constructors
for (auto const& base: _bases)
if (declaration == base->getName()->getReferencedDeclaration())
for (auto const* base: _bases)
if (declaration == base)
{
if (auto referencedConstructor = dynamic_cast<ContractDefinition const&>(*declaration).getConstructor())
if (auto referencedConstructor = base->getConstructor())
parameters = &referencedConstructor->getParameters();
else
parameters = &emptyParameterList;

2
libsolidity/AST.h

@ -566,7 +566,7 @@ public:
std::vector<ASTPointer<Expression>> const& getArguments() const { return m_arguments; }
/// @param _bases is the list of base contracts for base constructor calls. For modifiers an empty vector should be passed.
void checkTypeRequirements(std::vector<ASTPointer<InheritanceSpecifier>> const& _bases);
void checkTypeRequirements(std::vector<ContractDefinition const*> const& _bases);
private:
ASTPointer<Identifier> m_modifierName;

1
libsolidity/Compiler.cpp

@ -136,6 +136,7 @@ void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor)
FunctionType constructorType(_constructor);
if (!constructorType.getParameterTypes().empty())
{
solAssert(m_baseArguments.count(&_constructor), "");
std::vector<ASTPointer<Expression>> const* arguments = m_baseArguments[&_constructor];
solAssert(arguments, "");
for (unsigned i = 0; i < arguments->size(); ++i)

16
libsolidity/CompilerStack.cpp

@ -157,14 +157,16 @@ bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
return getBytecode();
}
eth::AssemblyItems const& CompilerStack::getAssemblyItems(string const& _contractName) const
eth::AssemblyItems const* CompilerStack::getAssemblyItems(string const& _contractName) const
{
return getContract(_contractName).compiler->getAssemblyItems();
Contract const& contract = getContract(_contractName);
return contract.compiler ? &getContract(_contractName).compiler->getAssemblyItems() : nullptr;
}
eth::AssemblyItems const& CompilerStack::getRuntimeAssemblyItems(string const& _contractName) const
eth::AssemblyItems const* CompilerStack::getRuntimeAssemblyItems(string const& _contractName) const
{
return getContract(_contractName).compiler->getRuntimeAssemblyItems();
Contract const& contract = getContract(_contractName);
return contract.compiler ? &getContract(_contractName).compiler->getRuntimeAssemblyItems() : nullptr;
}
bytes const& CompilerStack::getBytecode(string const& _contractName) const
@ -184,7 +186,11 @@ dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const
void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes) const
{
getContract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes);
Contract const& contract = getContract(_contractName);
if (contract.compiler)
getContract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes);
else
_outStream << "Contract not fully implemented" << endl;
}
string const& CompilerStack::getInterface(string const& _contractName) const

4
libsolidity/CompilerStack.h

@ -94,9 +94,9 @@ public:
/// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor.
bytes const& getRuntimeBytecode(std::string const& _contractName = "") const;
/// @returns normal contract assembly items
eth::AssemblyItems const& getAssemblyItems(std::string const& _contractName = "") const;
eth::AssemblyItems const* getAssemblyItems(std::string const& _contractName = "") const;
/// @returns runtime contract assembly items
eth::AssemblyItems const& getRuntimeAssemblyItems(std::string const& _contractName = "") const;
eth::AssemblyItems const* getRuntimeAssemblyItems(std::string const& _contractName = "") const;
/// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor.
dev::h256 getContractCodeHash(std::string const& _contractName = "") const;

2
mix/CodeModel.cpp

@ -135,7 +135,7 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler
CollectDeclarationsVisitor visitor(&m_functions, &m_locals);
m_storage = collectStorage(contractDefinition);
contractDefinition.accept(visitor);
m_assemblyItems = _compiler.getRuntimeAssemblyItems(name);
m_assemblyItems = *_compiler.getRuntimeAssemblyItems(name);
m_constructorAssemblyItems = _compiler.getAssemblyItems(name);
}

18
test/SolidityNameAndTypeResolution.cpp

@ -407,6 +407,20 @@ BOOST_AUTO_TEST_CASE(create_abstract_contract)
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_optional)
{
ASTPointer<SourceUnit> sourceUnit;
char const* text = R"(
contract BaseBase { function BaseBase(uint j); }
contract base is BaseBase { function foo(); }
contract derived is base {
function derived(uint i) BaseBase(i){}
function foo() {}
}
)";
ETH_TEST_REQUIRE_NO_THROW(parseTextAndResolveNames(text), "Parsing and name resolving failed");
}
BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract)
{
ASTPointer<SourceUnit> sourceUnit;
@ -665,7 +679,7 @@ BOOST_AUTO_TEST_CASE(missing_base_constructor_arguments)
contract A { function A(uint a) { } }
contract B is A { }
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(base_constructor_arguments_override)
@ -674,7 +688,7 @@ BOOST_AUTO_TEST_CASE(base_constructor_arguments_override)
contract A { function A(uint a) { } }
contract B is A { }
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion)

Loading…
Cancel
Save