mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #1414 from LefterisJP/sol_notImplementedFuncs
Interface contracts
This commit is contained in:
commit
eab085baf6
34
AST.cpp
34
AST.cpp
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
#include <libsolidity/Utils.h>
|
#include <libsolidity/Utils.h>
|
||||||
#include <libsolidity/AST.h>
|
#include <libsolidity/AST.h>
|
||||||
#include <libsolidity/ASTVisitor.h>
|
#include <libsolidity/ASTVisitor.h>
|
||||||
@ -52,6 +53,7 @@ void ContractDefinition::checkTypeRequirements()
|
|||||||
baseSpecifier->checkTypeRequirements();
|
baseSpecifier->checkTypeRequirements();
|
||||||
|
|
||||||
checkIllegalOverrides();
|
checkIllegalOverrides();
|
||||||
|
checkAbstractFunctions();
|
||||||
|
|
||||||
FunctionDefinition const* constructor = getConstructor();
|
FunctionDefinition const* constructor = getConstructor();
|
||||||
if (constructor && !constructor->getReturnParameters().empty())
|
if (constructor && !constructor->getReturnParameters().empty())
|
||||||
@ -60,6 +62,7 @@ void ContractDefinition::checkTypeRequirements()
|
|||||||
|
|
||||||
FunctionDefinition const* fallbackFunction = nullptr;
|
FunctionDefinition const* fallbackFunction = nullptr;
|
||||||
for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
|
for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
|
||||||
|
{
|
||||||
if (function->getName().empty())
|
if (function->getName().empty())
|
||||||
{
|
{
|
||||||
if (fallbackFunction)
|
if (fallbackFunction)
|
||||||
@ -71,6 +74,9 @@ void ContractDefinition::checkTypeRequirements()
|
|||||||
BOOST_THROW_EXCEPTION(fallbackFunction->getParameterList().createTypeError("Fallback function cannot take parameters."));
|
BOOST_THROW_EXCEPTION(fallbackFunction->getParameterList().createTypeError("Fallback function cannot take parameters."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!function->isFullyImplemented())
|
||||||
|
setFullyImplemented(false);
|
||||||
|
}
|
||||||
for (ASTPointer<ModifierDefinition> const& modifier: getFunctionModifiers())
|
for (ASTPointer<ModifierDefinition> const& modifier: getFunctionModifiers())
|
||||||
modifier->checkTypeRequirements();
|
modifier->checkTypeRequirements();
|
||||||
|
|
||||||
@ -124,6 +130,28 @@ FunctionDefinition const* ContractDefinition::getFallbackFunction() const
|
|||||||
return nullptr;
|
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"));
|
||||||
|
functions[name] = function->isFullyImplemented();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& it: functions)
|
||||||
|
if (!it.second)
|
||||||
|
{
|
||||||
|
setFullyImplemented(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ContractDefinition::checkIllegalOverrides() const
|
void ContractDefinition::checkIllegalOverrides() const
|
||||||
{
|
{
|
||||||
// TODO unify this at a later point. for this we need to put the constness and the access specifier
|
// TODO unify this at a later point. for this we need to put the constness and the access specifier
|
||||||
@ -316,8 +344,8 @@ void FunctionDefinition::checkTypeRequirements()
|
|||||||
modifier->checkTypeRequirements(isConstructor() ?
|
modifier->checkTypeRequirements(isConstructor() ?
|
||||||
dynamic_cast<ContractDefinition const&>(*getScope()).getBaseContracts() :
|
dynamic_cast<ContractDefinition const&>(*getScope()).getBaseContracts() :
|
||||||
vector<ASTPointer<InheritanceSpecifier>>());
|
vector<ASTPointer<InheritanceSpecifier>>());
|
||||||
|
if (m_body)
|
||||||
m_body->checkTypeRequirements();
|
m_body->checkTypeRequirements();
|
||||||
}
|
}
|
||||||
|
|
||||||
string FunctionDefinition::externalSignature() const
|
string FunctionDefinition::externalSignature() const
|
||||||
@ -649,6 +677,8 @@ void NewExpression::checkTypeRequirements()
|
|||||||
m_contract = dynamic_cast<ContractDefinition const*>(m_contractName->getReferencedDeclaration());
|
m_contract = dynamic_cast<ContractDefinition const*>(m_contractName->getReferencedDeclaration());
|
||||||
if (!m_contract)
|
if (!m_contract)
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a 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."));
|
||||||
shared_ptr<ContractType const> contractType = make_shared<ContractType>(*m_contract);
|
shared_ptr<ContractType const> contractType = make_shared<ContractType>(*m_contract);
|
||||||
TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes();
|
TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes();
|
||||||
m_type = make_shared<FunctionType>(parameterTypes, TypePointers{contractType},
|
m_type = make_shared<FunctionType>(parameterTypes, TypePointers{contractType},
|
||||||
|
82
AST.h
82
AST.h
@ -196,6 +196,22 @@ protected:
|
|||||||
ASTPointer<ASTString> m_documentation;
|
ASTPointer<ASTString> m_documentation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class that is added to AST nodes that can be marked as not being fully implemented
|
||||||
|
*/
|
||||||
|
class ImplementationOptional
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ImplementationOptional(bool _implemented): m_implemented(_implemented) {}
|
||||||
|
|
||||||
|
/// @return whether this node is fully implemented or not
|
||||||
|
bool isFullyImplemented() const { return m_implemented; }
|
||||||
|
void setFullyImplemented(bool _implemented) { m_implemented = _implemented; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_implemented;
|
||||||
|
};
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -203,20 +219,24 @@ protected:
|
|||||||
* document order. It first visits all struct declarations, then all variable declarations and
|
* document order. It first visits all struct declarations, then all variable declarations and
|
||||||
* finally all function declarations.
|
* finally all function declarations.
|
||||||
*/
|
*/
|
||||||
class ContractDefinition: public Declaration, public Documented
|
class ContractDefinition: public Declaration, public Documented, public ImplementationOptional
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ContractDefinition(SourceLocation const& _location,
|
ContractDefinition(
|
||||||
ASTPointer<ASTString> const& _name,
|
SourceLocation const& _location,
|
||||||
ASTPointer<ASTString> const& _documentation,
|
ASTPointer<ASTString> const& _name,
|
||||||
std::vector<ASTPointer<InheritanceSpecifier>> const& _baseContracts,
|
ASTPointer<ASTString> const& _documentation,
|
||||||
std::vector<ASTPointer<StructDefinition>> const& _definedStructs,
|
std::vector<ASTPointer<InheritanceSpecifier>> const& _baseContracts,
|
||||||
std::vector<ASTPointer<EnumDefinition>> const& _definedEnums,
|
std::vector<ASTPointer<StructDefinition>> const& _definedStructs,
|
||||||
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
|
std::vector<ASTPointer<EnumDefinition>> const& _definedEnums,
|
||||||
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions,
|
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
|
||||||
std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers,
|
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions,
|
||||||
std::vector<ASTPointer<EventDefinition>> const& _events):
|
std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers,
|
||||||
Declaration(_location, _name), Documented(_documentation),
|
std::vector<ASTPointer<EventDefinition>> const& _events
|
||||||
|
):
|
||||||
|
Declaration(_location, _name),
|
||||||
|
Documented(_documentation),
|
||||||
|
ImplementationOptional(true),
|
||||||
m_baseContracts(_baseContracts),
|
m_baseContracts(_baseContracts),
|
||||||
m_definedStructs(_definedStructs),
|
m_definedStructs(_definedStructs),
|
||||||
m_definedEnums(_definedEnums),
|
m_definedEnums(_definedEnums),
|
||||||
@ -263,6 +283,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void checkIllegalOverrides() const;
|
void checkIllegalOverrides() const;
|
||||||
|
void checkAbstractFunctions();
|
||||||
|
|
||||||
std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& getInterfaceFunctionList() const;
|
std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& getInterfaceFunctionList() const;
|
||||||
|
|
||||||
@ -378,24 +399,29 @@ private:
|
|||||||
std::vector<ASTPointer<VariableDeclaration>> m_parameters;
|
std::vector<ASTPointer<VariableDeclaration>> m_parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FunctionDefinition: public Declaration, public VariableScope, public Documented
|
class FunctionDefinition: public Declaration, public VariableScope, public Documented, public ImplementationOptional
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FunctionDefinition(SourceLocation const& _location, ASTPointer<ASTString> const& _name,
|
FunctionDefinition(
|
||||||
Declaration::Visibility _visibility, bool _isConstructor,
|
SourceLocation const& _location,
|
||||||
ASTPointer<ASTString> const& _documentation,
|
ASTPointer<ASTString> const& _name,
|
||||||
ASTPointer<ParameterList> const& _parameters,
|
Declaration::Visibility _visibility, bool _isConstructor,
|
||||||
bool _isDeclaredConst,
|
ASTPointer<ASTString> const& _documentation,
|
||||||
std::vector<ASTPointer<ModifierInvocation>> const& _modifiers,
|
ASTPointer<ParameterList> const& _parameters,
|
||||||
ASTPointer<ParameterList> const& _returnParameters,
|
bool _isDeclaredConst,
|
||||||
ASTPointer<Block> const& _body):
|
std::vector<ASTPointer<ModifierInvocation>> const& _modifiers,
|
||||||
Declaration(_location, _name, _visibility), Documented(_documentation),
|
ASTPointer<ParameterList> const& _returnParameters,
|
||||||
m_isConstructor(_isConstructor),
|
ASTPointer<Block> const& _body
|
||||||
m_parameters(_parameters),
|
):
|
||||||
m_isDeclaredConst(_isDeclaredConst),
|
Declaration(_location, _name, _visibility),
|
||||||
m_functionModifiers(_modifiers),
|
Documented(_documentation),
|
||||||
m_returnParameters(_returnParameters),
|
ImplementationOptional(_body != nullptr),
|
||||||
m_body(_body)
|
m_isConstructor(_isConstructor),
|
||||||
|
m_parameters(_parameters),
|
||||||
|
m_isDeclaredConst(_isDeclaredConst),
|
||||||
|
m_functionModifiers(_modifiers),
|
||||||
|
m_returnParameters(_returnParameters),
|
||||||
|
m_body(_body)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual void accept(ASTVisitor& _visitor) override;
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
|
@ -175,7 +175,8 @@ void FunctionDefinition::accept(ASTVisitor& _visitor)
|
|||||||
if (m_returnParameters)
|
if (m_returnParameters)
|
||||||
m_returnParameters->accept(_visitor);
|
m_returnParameters->accept(_visitor);
|
||||||
listAccept(m_functionModifiers, _visitor);
|
listAccept(m_functionModifiers, _visitor);
|
||||||
m_body->accept(_visitor);
|
if (m_body)
|
||||||
|
m_body->accept(_visitor);
|
||||||
}
|
}
|
||||||
_visitor.endVisit(*this);
|
_visitor.endVisit(*this);
|
||||||
}
|
}
|
||||||
@ -188,7 +189,8 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const
|
|||||||
if (m_returnParameters)
|
if (m_returnParameters)
|
||||||
m_returnParameters->accept(_visitor);
|
m_returnParameters->accept(_visitor);
|
||||||
listAccept(m_functionModifiers, _visitor);
|
listAccept(m_functionModifiers, _visitor);
|
||||||
m_body->accept(_visitor);
|
if (m_body)
|
||||||
|
m_body->accept(_visitor);
|
||||||
}
|
}
|
||||||
_visitor.endVisit(*this);
|
_visitor.endVisit(*this);
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,8 @@ void CompilerStack::compile(bool _optimize)
|
|||||||
for (ASTPointer<ASTNode> const& node: source->ast->getNodes())
|
for (ASTPointer<ASTNode> const& node: source->ast->getNodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
{
|
{
|
||||||
|
if (!contract->isFullyImplemented())
|
||||||
|
continue;
|
||||||
shared_ptr<Compiler> compiler = make_shared<Compiler>(_optimize);
|
shared_ptr<Compiler> compiler = make_shared<Compiler>(_optimize);
|
||||||
compiler->compileContract(*contract, contractBytecode);
|
compiler->compileContract(*contract, contractBytecode);
|
||||||
Contract& compiledContract = m_contracts[contract->getName()];
|
Contract& compiledContract = m_contracts[contract->getName()];
|
||||||
|
24
Parser.cpp
24
Parser.cpp
@ -164,8 +164,17 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
|||||||
}
|
}
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
expectToken(Token::RBrace);
|
expectToken(Token::RBrace);
|
||||||
return nodeFactory.createNode<ContractDefinition>(name, docString, baseContracts, structs, enums,
|
return nodeFactory.createNode<ContractDefinition>(
|
||||||
stateVariables, functions, modifiers, events);
|
name,
|
||||||
|
docString,
|
||||||
|
baseContracts,
|
||||||
|
structs,
|
||||||
|
enums,
|
||||||
|
stateVariables,
|
||||||
|
functions,
|
||||||
|
modifiers,
|
||||||
|
events
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
|
ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
|
||||||
@ -247,8 +256,15 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const*
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
returnParameters = createEmptyParameterList();
|
returnParameters = createEmptyParameterList();
|
||||||
ASTPointer<Block> block = parseBlock();
|
ASTPointer<Block> block = ASTPointer<Block>();
|
||||||
nodeFactory.setEndPositionFromNode(block);
|
nodeFactory.markEndPosition();
|
||||||
|
if (m_scanner->getCurrentToken() != Token::Semicolon)
|
||||||
|
{
|
||||||
|
block = parseBlock();
|
||||||
|
nodeFactory.setEndPositionFromNode(block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_scanner->next(); // just consume the ';'
|
||||||
bool const c_isConstructor = (_contractName && *name == *_contractName);
|
bool const c_isConstructor = (_contractName && *name == *_contractName);
|
||||||
return nodeFactory.createNode<FunctionDefinition>(name, visibility, c_isConstructor, docstring,
|
return nodeFactory.createNode<FunctionDefinition>(name, visibility, c_isConstructor, docstring,
|
||||||
parameters, isDeclaredConst, modifiers,
|
parameters, isDeclaredConst, modifiers,
|
||||||
|
Loading…
Reference in New Issue
Block a user