diff options
author | chriseth <chris@ethereum.org> | 2017-03-22 00:54:05 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-22 00:54:05 +0800 |
commit | 6fb27dee635748110a27654a5a2c322d865b8578 (patch) | |
tree | 67b44c12852f074d93497d8f7129b95d89e43c73 /libsolidity | |
parent | 2cde2f9203f05b26bc0ffa45cb77c84a991f7d76 (diff) | |
parent | 5ced3af3a0579e4e0d5e0d923b3e9d3f21197bfa (diff) | |
download | dexon-solidity-6fb27dee635748110a27654a5a2c322d865b8578.tar.gz dexon-solidity-6fb27dee635748110a27654a5a2c322d865b8578.tar.zst dexon-solidity-6fb27dee635748110a27654a5a2c322d865b8578.zip |
Merge pull request #1688 from ethereum/interface-keyword
Support strict interface contracts
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 35 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.h | 1 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 12 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 26 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.h | 3 | ||||
-rw-r--r-- | libsolidity/parsing/Token.h | 2 |
6 files changed, 66 insertions, 13 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 34ed8129..30e84f11 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -64,8 +64,10 @@ bool TypeChecker::visit(ContractDefinition const& _contract) { m_scope = &_contract; - // We force our own visiting order here. - //@TODO structs will be visited again below, but it is probably fine. + // We force our own visiting order here. The structs have to be excluded below. + set<ASTNode const*> visited; + for (auto const& s: _contract.definedStructs()) + visited.insert(s); ASTNode::listAccept(_contract.definedStructs(), *this); ASTNode::listAccept(_contract.baseContracts(), *this); @@ -113,7 +115,9 @@ bool TypeChecker::visit(ContractDefinition const& _contract) _contract.annotation().isFullyImplemented = false; } - ASTNode::listAccept(_contract.subNodes(), *this); + for (auto const& n: _contract.subNodes()) + if (!visited.count(n.get())) + n->accept(*this); checkContractExternalTypeClashes(_contract); // check for hash collisions in function signatures @@ -354,6 +358,9 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name())); solAssert(base, "Base contract not available."); + if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface) + typeError(_inheritance.location(), "Interfaces cannot inherit."); + if (base->isLibrary()) typeError(_inheritance.location(), "Libraries cannot be inherited from."); @@ -396,6 +403,9 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor) bool TypeChecker::visit(StructDefinition const& _struct) { + if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface) + typeError(_struct.location(), "Structs cannot be defined in interfaces."); + for (ASTPointer<VariableDeclaration> const& member: _struct.members()) if (!type(*member)->canBeStored()) typeError(member->location(), "Type cannot be used in struct."); @@ -451,6 +461,15 @@ bool TypeChecker::visit(FunctionDefinition const& _function) dynamic_cast<ContractDefinition const&>(*_function.scope()).annotation().linearizedBaseContracts : vector<ContractDefinition const*>() ); + if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface) + { + if (_function.isImplemented()) + typeError(_function.location(), "Functions in interfaces cannot have an implementation."); + if (_function.visibility() < FunctionDefinition::Visibility::Public) + typeError(_function.location(), "Functions in interfaces cannot be internal or private."); + if (_function.isConstructor()) + typeError(_function.location(), "Constructor cannot be defined in interfaces."); + } if (_function.isImplemented()) _function.body().accept(*this); return false; @@ -458,6 +477,9 @@ bool TypeChecker::visit(FunctionDefinition const& _function) bool TypeChecker::visit(VariableDeclaration const& _variable) { + if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface) + typeError(_variable.location(), "Variables cannot be declared in interfaces."); + // Variables can be declared without type (with "var"), in which case the first assignment // sets the type. // Note that assignments before the first declaration are legal because of the special scoping @@ -504,6 +526,13 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) return false; } +bool TypeChecker::visit(EnumDefinition const& _enum) +{ + if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface) + typeError(_enum.location(), "Enumerable cannot be declared in interfaces."); + return false; +} + void TypeChecker::visitManually( ModifierInvocation const& _modifier, vector<ContractDefinition const*> const& _bases diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 46d8230a..88559f44 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -83,6 +83,7 @@ private: virtual bool visit(StructDefinition const& _struct) override; virtual bool visit(FunctionDefinition const& _function) override; virtual bool visit(VariableDeclaration const& _variable) override; + virtual bool visit(EnumDefinition const& _enum) override; /// We need to do this manually because we want to pass the bases of the current contract in /// case this is a base constructor call. void visitManually(ModifierInvocation const& _modifier, std::vector<ContractDefinition const*> const& _bases); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 8031760d..02234ffc 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -316,19 +316,21 @@ protected: class ContractDefinition: public Declaration, public Documented { public: + enum class ContractKind { Interface, Contract, Library }; + ContractDefinition( SourceLocation const& _location, ASTPointer<ASTString> const& _name, ASTPointer<ASTString> const& _documentation, std::vector<ASTPointer<InheritanceSpecifier>> const& _baseContracts, std::vector<ASTPointer<ASTNode>> const& _subNodes, - bool _isLibrary + ContractKind _contractKind = ContractKind::Contract ): Declaration(_location, _name), Documented(_documentation), m_baseContracts(_baseContracts), m_subNodes(_subNodes), - m_isLibrary(_isLibrary) + m_contractKind(_contractKind) {} virtual void accept(ASTVisitor& _visitor) override; @@ -344,7 +346,7 @@ public: std::vector<FunctionDefinition const*> definedFunctions() const { return filteredNodes<FunctionDefinition>(m_subNodes); } std::vector<EventDefinition const*> events() const { return filteredNodes<EventDefinition>(m_subNodes); } std::vector<EventDefinition const*> const& interfaceEvents() const; - bool isLibrary() const { return m_isLibrary; } + bool isLibrary() const { return m_contractKind == ContractKind::Library; } /// @returns a map of canonical function signatures to FunctionDefinitions /// as intended for use by the ABI. @@ -371,10 +373,12 @@ public: virtual ContractDefinitionAnnotation& annotation() const override; + ContractKind contractKind() const { return m_contractKind; } + private: std::vector<ASTPointer<InheritanceSpecifier>> m_baseContracts; std::vector<ASTPointer<ASTNode>> m_subNodes; - bool m_isLibrary; + ContractKind m_contractKind; // parsed Natspec documentation of the contract. Json::Value m_userDocumentation; diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index e26e2908..b5130c8a 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -82,9 +82,10 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner) case Token::Import: nodes.push_back(parseImportDirective()); break; + case Token::Interface: case Token::Contract: case Token::Library: - nodes.push_back(parseContractDefinition(token == Token::Library)); + nodes.push_back(parseContractDefinition(token)); break; default: fatalParserError(string("Expected import directive or contract definition.")); @@ -193,13 +194,30 @@ ASTPointer<ImportDirective> Parser::parseImportDirective() return nodeFactory.createNode<ImportDirective>(path, unitAlias, move(symbolAliases)); } -ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary) +ContractDefinition::ContractKind Parser::tokenToContractKind(Token::Value _token) +{ + switch(_token) + { + case Token::Interface: + return ContractDefinition::ContractKind::Interface; + case Token::Contract: + return ContractDefinition::ContractKind::Contract; + case Token::Library: + return ContractDefinition::ContractKind::Library; + default: + fatalParserError("Unsupported contract type."); + } + // FIXME: fatalParserError is not considered as throwing here + return ContractDefinition::ContractKind::Contract; +} + +ASTPointer<ContractDefinition> Parser::parseContractDefinition(Token::Value _expectedKind) { ASTNodeFactory nodeFactory(*this); ASTPointer<ASTString> docString; if (m_scanner->currentCommentLiteral() != "") docString = make_shared<ASTString>(m_scanner->currentCommentLiteral()); - expectToken(_isLibrary ? Token::Library : Token::Contract); + expectToken(_expectedKind); ASTPointer<ASTString> name = expectIdentifierToken(); vector<ASTPointer<InheritanceSpecifier>> baseContracts; if (m_scanner->currentToken() == Token::Is) @@ -252,7 +270,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary) docString, baseContracts, subNodes, - _isLibrary + tokenToContractKind(_expectedKind) ); } diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 79d1d1d4..282617ab 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -69,7 +69,8 @@ private: ///@name Parsing functions for the AST nodes ASTPointer<PragmaDirective> parsePragmaDirective(); ASTPointer<ImportDirective> parseImportDirective(); - ASTPointer<ContractDefinition> parseContractDefinition(bool _isLibrary); + ContractDefinition::ContractKind tokenToContractKind(Token::Value _token); + ASTPointer<ContractDefinition> parseContractDefinition(Token::Value _expectedKind); ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier(); Declaration::Visibility parseVisibilitySpecifier(Token::Value _token); FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers); diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h index c6d050bb..9a557ebd 100644 --- a/libsolidity/parsing/Token.h +++ b/libsolidity/parsing/Token.h @@ -157,6 +157,7 @@ namespace solidity K(Hex, "hex", 0) \ K(If, "if", 0) \ K(Indexed, "indexed", 0) \ + K(Interface, "interface", 0) \ K(Internal, "internal", 0) \ K(Import, "import", 0) \ K(Is, "is", 0) \ @@ -225,7 +226,6 @@ namespace solidity K(Final, "final", 0) \ K(In, "in", 0) \ K(Inline, "inline", 0) \ - K(Interface, "interface", 0) \ K(Let, "let", 0) \ K(Match, "match", 0) \ K(NullLiteral, "null", 0) \ |