aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-04-17 23:31:47 +0800
committerchriseth <c@ethdev.com>2015-04-17 23:31:47 +0800
commitc9812f7269704fcfa708d9b352b8344a5754a223 (patch)
treeacae6a747018dcab896c7129d4467ad43c067232
parent5622364a98102574f04019e2f1041d54d2d04984 (diff)
parentc558aa06567f4e6e28b8f15c3dee73867fde447b (diff)
downloaddexon-solidity-c9812f7269704fcfa708d9b352b8344a5754a223.tar
dexon-solidity-c9812f7269704fcfa708d9b352b8344a5754a223.tar.gz
dexon-solidity-c9812f7269704fcfa708d9b352b8344a5754a223.tar.bz2
dexon-solidity-c9812f7269704fcfa708d9b352b8344a5754a223.tar.lz
dexon-solidity-c9812f7269704fcfa708d9b352b8344a5754a223.tar.xz
dexon-solidity-c9812f7269704fcfa708d9b352b8344a5754a223.tar.zst
dexon-solidity-c9812f7269704fcfa708d9b352b8344a5754a223.zip
Merge pull request #1501 from LefterisJP/abstract_contract_contructors
Abstract contract contructors
-rw-r--r--AST.cpp56
-rw-r--r--AST.h5
-rw-r--r--Compiler.cpp1
-rw-r--r--CompilerStack.cpp16
-rw-r--r--CompilerStack.h4
5 files changed, 65 insertions, 17 deletions
diff --git a/AST.cpp b/AST.cpp
index 0abdf781..5f681205 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -54,6 +54,7 @@ void ContractDefinition::checkTypeRequirements()
checkIllegalOverrides();
checkAbstractFunctions();
+ checkAbstractConstructors();
FunctionDefinition const* constructor = getConstructor();
if (constructor && !constructor->getReturnParameters().empty())
@@ -152,6 +153,45 @@ void ContractDefinition::checkAbstractFunctions()
}
}
+void ContractDefinition::checkAbstractConstructors()
+{
+ set<ContractDefinition const*> argumentsNeeded;
+ // check that we get arguments for all base constructors that need it.
+ // If not mark the contract as abstract (not fully implemented)
+
+ vector<ContractDefinition const*> const& bases = getLinearizedBaseContracts();
+ for (ContractDefinition const* contract: bases)
+ if (FunctionDefinition const* constructor = contract->getConstructor())
+ if (contract != this && !constructor->getParameters().empty())
+ argumentsNeeded.insert(contract);
+
+ for (ContractDefinition const* contract: bases)
+ {
+ if (FunctionDefinition const* constructor = contract->getConstructor())
+ for (auto const& modifier: constructor->getModifiers())
+ {
+ auto baseContract = dynamic_cast<ContractDefinition const*>(
+ modifier->getName()->getReferencedDeclaration()
+ );
+ if (baseContract)
+ argumentsNeeded.erase(baseContract);
+ }
+
+
+ for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts())
+ {
+ auto baseContract = dynamic_cast<ContractDefinition const*>(
+ base->getName()->getReferencedDeclaration()
+ );
+ solAssert(baseContract, "");
+ if (!base->getArguments().empty())
+ argumentsNeeded.erase(baseContract);
+ }
+ }
+ if (!argumentsNeeded.empty())
+ setFullyImplemented(false);
+}
+
void ContractDefinition::checkIllegalOverrides() const
{
// TODO unify this at a later point. for this we need to put the constness and the access specifier
@@ -281,7 +321,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.empty() && 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 +388,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 +466,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 +479,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;
@@ -686,7 +726,7 @@ void NewExpression::checkTypeRequirements()
if (!m_contract)
BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract."));
if (!m_contract->isFullyImplemented())
- BOOST_THROW_EXCEPTION(m_contract->createTypeError("Trying to create an instance of an abstract contract."));
+ BOOST_THROW_EXCEPTION(createTypeError("Trying to create an instance of an abstract contract."));
shared_ptr<ContractType const> contractType = make_shared<ContractType>(*m_contract);
TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes();
m_type = make_shared<FunctionType>(parameterTypes, TypePointers{contractType},
diff --git a/AST.h b/AST.h
index 9f5f9fcb..0c133ff1 100644
--- a/AST.h
+++ b/AST.h
@@ -284,6 +284,7 @@ public:
private:
void checkIllegalOverrides() const;
void checkAbstractFunctions();
+ void checkAbstractConstructors();
std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& getInterfaceFunctionList() const;
@@ -376,7 +377,7 @@ class EnumValue: public Declaration
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- TypePointer getType(ContractDefinition const* = nullptr) const;
+ virtual TypePointer getType(ContractDefinition const* = nullptr) const override;
};
/**
@@ -566,7 +567,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;
diff --git a/Compiler.cpp b/Compiler.cpp
index 886565cb..f0197e23 100644
--- a/Compiler.cpp
+++ b/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)
diff --git a/CompilerStack.cpp b/CompilerStack.cpp
index 1301bfa5..c35d9324 100644
--- a/CompilerStack.cpp
+++ b/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
diff --git a/CompilerStack.h b/CompilerStack.h
index 1cf576ab..19c1ba4e 100644
--- a/CompilerStack.h
+++ b/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;