diff options
author | Lefteris Karapetsas <lefteris@refu.co> | 2015-03-27 22:15:34 +0800 |
---|---|---|
committer | Lefteris Karapetsas <lefteris@refu.co> | 2015-03-27 22:15:34 +0800 |
commit | 85bb056993ccb111b7e32e28475b906f75b77aa6 (patch) | |
tree | e401f72dd8d2ee621b2908bc24f1428687e6c16e /AST.cpp | |
parent | a7e78fadf5d8fd4d1d4300a4d8064d9bf51af687 (diff) | |
download | dexon-solidity-85bb056993ccb111b7e32e28475b906f75b77aa6.tar.gz dexon-solidity-85bb056993ccb111b7e32e28475b906f75b77aa6.tar.zst dexon-solidity-85bb056993ccb111b7e32e28475b906f75b77aa6.zip |
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
Diffstat (limited to 'AST.cpp')
-rw-r--r-- | AST.cpp | 40 |
1 files changed, 40 insertions, 0 deletions
@@ -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}, |