mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Abstract contract and inheritance
- Checking the linearized base contracts for abstract functions and handle their existence appropriately - If a contract is abstract it can't be created with new - An abstract contract is not compiled (no backend code is generated) - Of course tests
This commit is contained in:
parent
a7e78fadf5
commit
85bb056993
40
AST.cpp
40
AST.cpp
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
#include <libsolidity/Utils.h>
|
||||
#include <libsolidity/AST.h>
|
||||
#include <libsolidity/ASTVisitor.h>
|
||||
@ -52,6 +53,7 @@ void ContractDefinition::checkTypeRequirements()
|
||||
baseSpecifier->checkTypeRequirements();
|
||||
|
||||
checkIllegalOverrides();
|
||||
checkAbstractFunctions();
|
||||
|
||||
FunctionDefinition const* constructor = getConstructor();
|
||||
if (constructor && !constructor->getReturnParameters().empty())
|
||||
@ -128,6 +130,42 @@ FunctionDefinition const* ContractDefinition::getFallbackFunction() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ContractDefinition::checkAbstractFunctions()
|
||||
{
|
||||
map<string, bool> functions;
|
||||
|
||||
// Search from base to derived
|
||||
for (ContractDefinition const* contract: boost::adaptors::reverse(getLinearizedBaseContracts()))
|
||||
{
|
||||
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
|
||||
{
|
||||
string const& name = function->getName();
|
||||
if (!function->isFullyImplemented() && functions.count(name) && functions[name])
|
||||
BOOST_THROW_EXCEPTION(function->createTypeError("Redeclaring an already implemented function as abstract"));
|
||||
// if (functions.count(name) && !functions[name] && function->isFullyImplemented())
|
||||
// functions.insert(make_pair(name, true);
|
||||
|
||||
// if (functions.count(name) && !functions[name] && function->isFullyImplemented)
|
||||
// functions.insert(make_pair(name, true));
|
||||
|
||||
// functions.insert(make_pair(name, function->isFullyImplemented()));
|
||||
functions[name] = function->isFullyImplemented();
|
||||
|
||||
// if (function->isFullyImplemented())
|
||||
// full_functions.insert(make_pair(name, function.get()));
|
||||
// else
|
||||
// abs_functions.insert(make_pair(name, function.get()));
|
||||
}
|
||||
}
|
||||
for (auto const& it: functions)
|
||||
if (!it.second)
|
||||
{
|
||||
setFullyImplemented(false);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ContractDefinition::checkIllegalOverrides() const
|
||||
{
|
||||
// TODO unify this at a later point. for this we need to put the constness and the access specifier
|
||||
@ -643,6 +681,8 @@ void NewExpression::checkTypeRequirements()
|
||||
m_contract = dynamic_cast<ContractDefinition const*>(m_contractName->getReferencedDeclaration());
|
||||
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 object 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},
|
||||
|
1
AST.h
1
AST.h
@ -283,6 +283,7 @@ public:
|
||||
|
||||
private:
|
||||
void checkIllegalOverrides() const;
|
||||
void checkAbstractFunctions();
|
||||
|
||||
std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& getInterfaceFunctionList() const;
|
||||
|
||||
|
@ -138,6 +138,8 @@ void CompilerStack::compile(bool _optimize)
|
||||
for (ASTPointer<ASTNode> const& node: source->ast->getNodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
if (!contract->isFullyImplemented())
|
||||
continue;
|
||||
shared_ptr<Compiler> compiler = make_shared<Compiler>(_optimize);
|
||||
compiler->compileContract(*contract, contractBytecode);
|
||||
Contract& compiledContract = m_contracts[contract->getName()];
|
||||
|
@ -141,10 +141,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||
if (currentToken == Token::RBrace)
|
||||
break;
|
||||
else if (currentToken == Token::Function)
|
||||
{
|
||||
ASTPointer<FunctionDefinition> func = parseFunctionDefinition(name.get());
|
||||
functions.push_back(func);
|
||||
}
|
||||
functions.push_back(parseFunctionDefinition(name.get()));
|
||||
else if (currentToken == Token::Struct)
|
||||
structs.push_back(parseStructDefinition());
|
||||
else if (currentToken == Token::Enum)
|
||||
|
Loading…
Reference in New Issue
Block a user