mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Parsing and type checking of libraries without inheritance.
This commit is contained in:
parent
c5b6d9d2a9
commit
337fde9d11
@ -103,6 +103,9 @@ void ContractDefinition::checkTypeRequirements()
|
|||||||
));
|
));
|
||||||
hashes.insert(hash);
|
hashes.insert(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isLibrary())
|
||||||
|
checkLibraryRequirements();
|
||||||
}
|
}
|
||||||
|
|
||||||
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
||||||
@ -332,6 +335,17 @@ void ContractDefinition::checkExternalTypeClashes() const
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContractDefinition::checkLibraryRequirements() const
|
||||||
|
{
|
||||||
|
solAssert(m_isLibrary, "");
|
||||||
|
if (!m_baseContracts.empty())
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Library is not allowed to inherit."));
|
||||||
|
|
||||||
|
for (auto const& var: m_stateVariables)
|
||||||
|
if (!var->isConstant())
|
||||||
|
BOOST_THROW_EXCEPTION(var->createTypeError("Library cannot have non-constant state variables"));
|
||||||
|
}
|
||||||
|
|
||||||
vector<ASTPointer<EventDefinition>> const& ContractDefinition::interfaceEvents() const
|
vector<ASTPointer<EventDefinition>> const& ContractDefinition::interfaceEvents() const
|
||||||
{
|
{
|
||||||
if (!m_interfaceEvents)
|
if (!m_interfaceEvents)
|
||||||
@ -449,6 +463,10 @@ void InheritanceSpecifier::checkTypeRequirements()
|
|||||||
|
|
||||||
ContractDefinition const* base = dynamic_cast<ContractDefinition const*>(&m_baseName->referencedDeclaration());
|
ContractDefinition const* base = dynamic_cast<ContractDefinition const*>(&m_baseName->referencedDeclaration());
|
||||||
solAssert(base, "Base contract not available.");
|
solAssert(base, "Base contract not available.");
|
||||||
|
|
||||||
|
if (base->isLibrary())
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Libraries cannot be inherited from."));
|
||||||
|
|
||||||
TypePointers parameterTypes = ContractType(*base).constructorType()->parameterTypes();
|
TypePointers parameterTypes = ContractType(*base).constructorType()->parameterTypes();
|
||||||
if (!m_arguments.empty() && parameterTypes.size() != m_arguments.size())
|
if (!m_arguments.empty() && parameterTypes.size() != m_arguments.size())
|
||||||
BOOST_THROW_EXCEPTION(createTypeError(
|
BOOST_THROW_EXCEPTION(createTypeError(
|
||||||
|
@ -215,7 +215,7 @@ protected:
|
|||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Definition of a contract. This is the only AST nodes where child nodes are not visited in
|
* Definition of a contract or library. This is the only AST nodes where child nodes are not visited in
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
@ -232,7 +232,8 @@ public:
|
|||||||
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
|
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
|
||||||
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions,
|
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions,
|
||||||
std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers,
|
std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers,
|
||||||
std::vector<ASTPointer<EventDefinition>> const& _events
|
std::vector<ASTPointer<EventDefinition>> const& _events,
|
||||||
|
bool _isLibrary
|
||||||
):
|
):
|
||||||
Declaration(_location, _name),
|
Declaration(_location, _name),
|
||||||
Documented(_documentation),
|
Documented(_documentation),
|
||||||
@ -243,7 +244,8 @@ public:
|
|||||||
m_stateVariables(_stateVariables),
|
m_stateVariables(_stateVariables),
|
||||||
m_definedFunctions(_definedFunctions),
|
m_definedFunctions(_definedFunctions),
|
||||||
m_functionModifiers(_functionModifiers),
|
m_functionModifiers(_functionModifiers),
|
||||||
m_events(_events)
|
m_events(_events),
|
||||||
|
m_isLibrary(_isLibrary)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual void accept(ASTVisitor& _visitor) override;
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
@ -257,6 +259,7 @@ public:
|
|||||||
std::vector<ASTPointer<FunctionDefinition>> const& definedFunctions() const { return m_definedFunctions; }
|
std::vector<ASTPointer<FunctionDefinition>> const& definedFunctions() const { return m_definedFunctions; }
|
||||||
std::vector<ASTPointer<EventDefinition>> const& events() const { return m_events; }
|
std::vector<ASTPointer<EventDefinition>> const& events() const { return m_events; }
|
||||||
std::vector<ASTPointer<EventDefinition>> const& interfaceEvents() const;
|
std::vector<ASTPointer<EventDefinition>> const& interfaceEvents() const;
|
||||||
|
bool isLibrary() const { return m_isLibrary; }
|
||||||
|
|
||||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
||||||
|
|
||||||
@ -297,6 +300,8 @@ private:
|
|||||||
/// Checks that different functions with external visibility end up having different
|
/// Checks that different functions with external visibility end up having different
|
||||||
/// external argument types (i.e. different signature).
|
/// external argument types (i.e. different signature).
|
||||||
void checkExternalTypeClashes() const;
|
void checkExternalTypeClashes() const;
|
||||||
|
/// Checks that all requirements for a library are fulfilled if this is a library.
|
||||||
|
void checkLibraryRequirements() const;
|
||||||
|
|
||||||
std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& interfaceFunctionList() const;
|
std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& interfaceFunctionList() const;
|
||||||
|
|
||||||
@ -307,6 +312,7 @@ private:
|
|||||||
std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
|
std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
|
||||||
std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers;
|
std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers;
|
||||||
std::vector<ASTPointer<EventDefinition>> m_events;
|
std::vector<ASTPointer<EventDefinition>> m_events;
|
||||||
|
bool m_isLibrary;
|
||||||
|
|
||||||
// parsed Natspec documentation of the contract.
|
// parsed Natspec documentation of the contract.
|
||||||
std::string m_userDocumentation;
|
std::string m_userDocumentation;
|
||||||
|
@ -71,13 +71,14 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
|
|||||||
vector<ASTPointer<ASTNode>> nodes;
|
vector<ASTPointer<ASTNode>> nodes;
|
||||||
while (m_scanner->currentToken() != Token::EOS)
|
while (m_scanner->currentToken() != Token::EOS)
|
||||||
{
|
{
|
||||||
switch (m_scanner->currentToken())
|
switch (auto token = m_scanner->currentToken())
|
||||||
{
|
{
|
||||||
case Token::Import:
|
case Token::Import:
|
||||||
nodes.push_back(parseImportDirective());
|
nodes.push_back(parseImportDirective());
|
||||||
break;
|
break;
|
||||||
case Token::Contract:
|
case Token::Contract:
|
||||||
nodes.push_back(parseContractDefinition());
|
case Token::Library:
|
||||||
|
nodes.push_back(parseContractDefinition(token == Token::Library));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_THROW_EXCEPTION(createParserError(std::string("Expected import directive or contract definition.")));
|
BOOST_THROW_EXCEPTION(createParserError(std::string("Expected import directive or contract definition.")));
|
||||||
@ -113,13 +114,13 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
|
|||||||
return nodeFactory.createNode<ImportDirective>(url);
|
return nodeFactory.createNode<ImportDirective>(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary)
|
||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
ASTPointer<ASTString> docString;
|
ASTPointer<ASTString> docString;
|
||||||
if (m_scanner->currentCommentLiteral() != "")
|
if (m_scanner->currentCommentLiteral() != "")
|
||||||
docString = make_shared<ASTString>(m_scanner->currentCommentLiteral());
|
docString = make_shared<ASTString>(m_scanner->currentCommentLiteral());
|
||||||
expectToken(Token::Contract);
|
expectToken(_isLibrary ? Token::Library : Token::Contract);
|
||||||
ASTPointer<ASTString> name = expectIdentifierToken();
|
ASTPointer<ASTString> name = expectIdentifierToken();
|
||||||
vector<ASTPointer<InheritanceSpecifier>> baseContracts;
|
vector<ASTPointer<InheritanceSpecifier>> baseContracts;
|
||||||
vector<ASTPointer<StructDefinition>> structs;
|
vector<ASTPointer<StructDefinition>> structs;
|
||||||
@ -177,7 +178,8 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
|||||||
stateVariables,
|
stateVariables,
|
||||||
functions,
|
functions,
|
||||||
modifiers,
|
modifiers,
|
||||||
events
|
events,
|
||||||
|
_isLibrary
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,15 +61,17 @@ private:
|
|||||||
///@{
|
///@{
|
||||||
///@name Parsing functions for the AST nodes
|
///@name Parsing functions for the AST nodes
|
||||||
ASTPointer<ImportDirective> parseImportDirective();
|
ASTPointer<ImportDirective> parseImportDirective();
|
||||||
ASTPointer<ContractDefinition> parseContractDefinition();
|
ASTPointer<ContractDefinition> parseContractDefinition(bool _isLibrary);
|
||||||
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
||||||
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
|
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
|
||||||
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
|
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
|
||||||
ASTPointer<StructDefinition> parseStructDefinition();
|
ASTPointer<StructDefinition> parseStructDefinition();
|
||||||
ASTPointer<EnumDefinition> parseEnumDefinition();
|
ASTPointer<EnumDefinition> parseEnumDefinition();
|
||||||
ASTPointer<EnumValue> parseEnumValue();
|
ASTPointer<EnumValue> parseEnumValue();
|
||||||
ASTPointer<VariableDeclaration> parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions(),
|
ASTPointer<VariableDeclaration> parseVariableDeclaration(
|
||||||
ASTPointer<TypeName> const& _lookAheadArrayType = ASTPointer<TypeName>());
|
VarDeclParserOptions const& _options = VarDeclParserOptions(),
|
||||||
|
ASTPointer<TypeName> const& _lookAheadArrayType = ASTPointer<TypeName>()
|
||||||
|
);
|
||||||
ASTPointer<ModifierDefinition> parseModifierDefinition();
|
ASTPointer<ModifierDefinition> parseModifierDefinition();
|
||||||
ASTPointer<EventDefinition> parseEventDefinition();
|
ASTPointer<EventDefinition> parseEventDefinition();
|
||||||
ASTPointer<ModifierInvocation> parseModifierInvocation();
|
ASTPointer<ModifierInvocation> parseModifierInvocation();
|
||||||
|
@ -160,6 +160,7 @@ namespace solidity
|
|||||||
K(Internal, "internal", 0) \
|
K(Internal, "internal", 0) \
|
||||||
K(Import, "import", 0) \
|
K(Import, "import", 0) \
|
||||||
K(Is, "is", 0) \
|
K(Is, "is", 0) \
|
||||||
|
K(Library, "library", 0) \
|
||||||
K(Mapping, "mapping", 0) \
|
K(Mapping, "mapping", 0) \
|
||||||
K(Memory, "memory", 0) \
|
K(Memory, "memory", 0) \
|
||||||
K(Modifier, "modifier", 0) \
|
K(Modifier, "modifier", 0) \
|
||||||
@ -305,7 +306,7 @@ namespace solidity
|
|||||||
/* Identifiers (not keywords or future reserved words). */ \
|
/* Identifiers (not keywords or future reserved words). */ \
|
||||||
T(Identifier, NULL, 0) \
|
T(Identifier, NULL, 0) \
|
||||||
\
|
\
|
||||||
/* Keywords reserved for future. use. */ \
|
/* Keywords reserved for future use. */ \
|
||||||
K(As, "as", 0) \
|
K(As, "as", 0) \
|
||||||
K(Case, "case", 0) \
|
K(Case, "case", 0) \
|
||||||
K(Catch, "catch", 0) \
|
K(Catch, "catch", 0) \
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
ContractDefinition = 'contract' Identifier
|
ContractDefinition = ( 'contract' | 'library' ) Identifier
|
||||||
( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )?
|
( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )?
|
||||||
'{' ContractPart* '}'
|
'{' ContractPart* '}'
|
||||||
ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition | FunctionDefinition | EnumDefinition
|
ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition | FunctionDefinition | EnumDefinition
|
||||||
|
@ -2194,6 +2194,39 @@ BOOST_AUTO_TEST_CASE(string_bytes_conversion)
|
|||||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inheriting_from_library)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
library Lib {}
|
||||||
|
contract Test is Lib {}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inheriting_library)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract Test {}
|
||||||
|
library Lib is Test {}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(library_having_variables)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
library Lib { uint x; }
|
||||||
|
)";
|
||||||
|
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(valid_library)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
library Lib { uint constant x = 9; }
|
||||||
|
)";
|
||||||
|
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(creating_contract_within_the_contract)
|
BOOST_AUTO_TEST_CASE(creating_contract_within_the_contract)
|
||||||
{
|
{
|
||||||
|
@ -924,6 +924,16 @@ BOOST_AUTO_TEST_CASE(empty_comment)
|
|||||||
BOOST_CHECK_NO_THROW(parseText(text));
|
BOOST_CHECK_NO_THROW(parseText(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(library_simple)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
library Lib {
|
||||||
|
function f() { }
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK_NO_THROW(parseText(text));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user