mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Support for abstract contracts.
This commit is contained in:
parent
106d8ec3b6
commit
62950a9234
@ -391,6 +391,19 @@ void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _con
|
||||
_contract.annotation().unimplementedFunctions.push_back(function);
|
||||
break;
|
||||
}
|
||||
|
||||
if (_contract.abstract() && _contract.contractKind() != ContractDefinition::ContractKind::Contract)
|
||||
m_errorReporter.typeError(_contract.location(), "Only contracts can be abstract.");
|
||||
|
||||
if (
|
||||
_contract.contractKind() == ContractDefinition::ContractKind::Contract &&
|
||||
!_contract.annotation().unimplementedFunctions.empty() &&
|
||||
!_contract.abstract()
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
_contract.location(),
|
||||
"Contract \"" + _contract.annotation().canonicalName + "\" should be marked as abstract."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -88,7 +88,6 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
|
||||
for (auto const& n: _contract.subNodes())
|
||||
n->accept(*this);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2152,21 +2151,10 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
m_errorReporter.fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
|
||||
if (contract->isInterface())
|
||||
m_errorReporter.fatalTypeError(_newExpression.location(), "Cannot instantiate an interface.");
|
||||
if (!contract->annotation().unimplementedFunctions.empty())
|
||||
{
|
||||
SecondarySourceLocation ssl;
|
||||
for (auto function: contract->annotation().unimplementedFunctions)
|
||||
ssl.append("Missing implementation:", function->location());
|
||||
string msg = "Trying to create an instance of an abstract contract.";
|
||||
ssl.limitSize(msg);
|
||||
m_errorReporter.typeError(
|
||||
_newExpression.location(),
|
||||
ssl,
|
||||
msg
|
||||
);
|
||||
}
|
||||
if (!contract->constructorIsPublic())
|
||||
m_errorReporter.typeError(_newExpression.location(), "Contract with internal constructor cannot be created directly.");
|
||||
if (contract->abstract() || !contract->annotation().unimplementedFunctions.empty())
|
||||
m_errorReporter.typeError(_newExpression.location(), "Cannot instantiate an abstract contract.");
|
||||
|
||||
solAssert(!!m_scope, "");
|
||||
m_scope->annotation().contractDependencies.insert(contract);
|
||||
|
@ -151,7 +151,7 @@ bool ContractDefinition::constructorIsPublic() const
|
||||
|
||||
bool ContractDefinition::canBeDeployed() const
|
||||
{
|
||||
return constructorIsPublic() && annotation().unimplementedFunctions.empty();
|
||||
return constructorIsPublic() && annotation().unimplementedFunctions.empty() && !abstract();
|
||||
}
|
||||
|
||||
FunctionDefinition const* ContractDefinition::fallbackFunction() const
|
||||
|
@ -388,13 +388,15 @@ public:
|
||||
ASTPointer<ASTString> const& _documentation,
|
||||
std::vector<ASTPointer<InheritanceSpecifier>> const& _baseContracts,
|
||||
std::vector<ASTPointer<ASTNode>> const& _subNodes,
|
||||
ContractKind _contractKind = ContractKind::Contract
|
||||
ContractKind _contractKind = ContractKind::Contract,
|
||||
bool _abstract = false
|
||||
):
|
||||
Declaration(_location, _name),
|
||||
Documented(_documentation),
|
||||
m_baseContracts(_baseContracts),
|
||||
m_subNodes(_subNodes),
|
||||
m_contractKind(_contractKind)
|
||||
m_contractKind(_contractKind),
|
||||
m_abstract(_abstract)
|
||||
{}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
@ -441,10 +443,13 @@ public:
|
||||
|
||||
ContractKind contractKind() const { return m_contractKind; }
|
||||
|
||||
bool abstract() const { return m_abstract; }
|
||||
|
||||
private:
|
||||
std::vector<ASTPointer<InheritanceSpecifier>> m_baseContracts;
|
||||
std::vector<ASTPointer<ASTNode>> m_subNodes;
|
||||
ContractKind m_contractKind;
|
||||
bool m_abstract{false};
|
||||
|
||||
mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList;
|
||||
mutable std::unique_ptr<std::vector<EventDefinition const*>> m_interfaceEvents;
|
||||
|
@ -260,6 +260,7 @@ bool ASTJsonConverter::visit(ContractDefinition const& _node)
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("documentation", _node.documentation() ? Json::Value(*_node.documentation()) : Json::nullValue),
|
||||
make_pair("contractKind", contractKind(_node.contractKind())),
|
||||
make_pair("abstract", _node.abstract()),
|
||||
make_pair("fullyImplemented", _node.annotation().unimplementedFunctions.empty()),
|
||||
make_pair("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)),
|
||||
make_pair("baseContracts", toJson(_node.baseContracts())),
|
||||
|
@ -91,6 +91,7 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
|
||||
case Token::Import:
|
||||
nodes.push_back(parseImportDirective());
|
||||
break;
|
||||
case Token::Abstract:
|
||||
case Token::Interface:
|
||||
case Token::Contract:
|
||||
case Token::Library:
|
||||
@ -244,9 +245,15 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
|
||||
return nodeFactory.createNode<ImportDirective>(path, unitAlias, move(symbolAliases));
|
||||
}
|
||||
|
||||
ContractDefinition::ContractKind Parser::parseContractKind()
|
||||
std::pair<ContractDefinition::ContractKind, bool> Parser::parseContractKind()
|
||||
{
|
||||
ContractDefinition::ContractKind kind;
|
||||
bool abstract = false;
|
||||
if (m_scanner->currentToken() == Token::Abstract)
|
||||
{
|
||||
abstract = true;
|
||||
m_scanner->next();
|
||||
}
|
||||
switch(m_scanner->currentToken())
|
||||
{
|
||||
case Token::Interface:
|
||||
@ -262,7 +269,7 @@ ContractDefinition::ContractKind Parser::parseContractKind()
|
||||
solAssert(false, "Invalid contract kind.");
|
||||
}
|
||||
m_scanner->next();
|
||||
return kind;
|
||||
return std::make_pair(kind, abstract);
|
||||
}
|
||||
|
||||
ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||
@ -273,7 +280,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||
ASTPointer<ASTString> docString;
|
||||
vector<ASTPointer<InheritanceSpecifier>> baseContracts;
|
||||
vector<ASTPointer<ASTNode>> subNodes;
|
||||
ContractDefinition::ContractKind contractKind = ContractDefinition::ContractKind::Contract;
|
||||
std::pair<ContractDefinition::ContractKind, bool> contractKind{};
|
||||
try
|
||||
{
|
||||
if (m_scanner->currentCommentLiteral() != "")
|
||||
@ -343,7 +350,8 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||
docString,
|
||||
baseContracts,
|
||||
subNodes,
|
||||
contractKind
|
||||
contractKind.first,
|
||||
contractKind.second
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,9 @@ private:
|
||||
void parsePragmaVersion(langutil::SourceLocation const& _location, std::vector<Token> const& _tokens, std::vector<std::string> const& _literals);
|
||||
ASTPointer<PragmaDirective> parsePragmaDirective();
|
||||
ASTPointer<ImportDirective> parseImportDirective();
|
||||
ContractDefinition::ContractKind parseContractKind();
|
||||
/// @returns an std::pair<ContractDefinition::ContractKind, bool>, where
|
||||
/// result.second is set to true, if an abstract contract was parsed, false otherwise.
|
||||
std::pair<ContractDefinition::ContractKind, bool> parseContractKind();
|
||||
ASTPointer<ContractDefinition> parseContractDefinition();
|
||||
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
||||
Declaration::Visibility parseVisibilitySpecifier();
|
||||
|
Loading…
Reference in New Issue
Block a user