diff --git a/libsolidity/AST.h b/libsolidity/AST.h index fde0b71b0..be118be3d 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -1217,10 +1217,10 @@ public: } Declaration const& getReferencedDeclaration() const; - /// Stores a set of possible declarations referenced by this identifier. Has to be resolved + /// Stores a possible declarations referenced by this identifier. Has to be resolved /// providing argument types using overloadResolution before the referenced declaration /// is accessed. - void setOverloadedDeclarations(std::set const& _declarations) + void setOverloadedDeclarations(std::vector const& _declarations) { m_overloadedDeclarations = _declarations; } @@ -1237,8 +1237,8 @@ private: /// Stores a reference to the current contract. This is needed because types of base contracts /// change depending on the context. ContractDefinition const* m_currentContract = nullptr; - /// A set of overloaded declarations, right now only FunctionDefinition has overloaded declarations. - std::set m_overloadedDeclarations; + /// A vector of overloaded declarations, right now only FunctionDefinition has overloaded declarations. + std::vector m_overloadedDeclarations; }; /** diff --git a/libsolidity/DeclarationContainer.cpp b/libsolidity/DeclarationContainer.cpp index c836663c7..ec8a59bb6 100644 --- a/libsolidity/DeclarationContainer.cpp +++ b/libsolidity/DeclarationContainer.cpp @@ -37,6 +37,7 @@ Declaration const* DeclarationContainer::conflictingDeclaration(Declaration cons declarations += m_declarations.at(name); if (m_invisibleDeclarations.count(name)) declarations += m_invisibleDeclarations.at(name); + if (dynamic_cast(&_declaration)) { // check that all other declarations with the same name are functions @@ -66,14 +67,13 @@ bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, return false; if (_invisible) - m_invisibleDeclarations[name].insert(&_declaration); + m_invisibleDeclarations[name].push_back(&_declaration); else - m_declarations[name].insert(&_declaration); - + m_declarations[name].push_back(&_declaration); return true; } -set DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const +std::vector DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const { solAssert(!_name.empty(), "Attempt to resolve empty name."); auto result = m_declarations.find(_name); @@ -81,5 +81,5 @@ set DeclarationContainer::resolveName(ASTString const& _name return result->second; if (_recursive && m_enclosingContainer) return m_enclosingContainer->resolveName(_name, true); - return set({}); + return vector({}); } diff --git a/libsolidity/DeclarationContainer.h b/libsolidity/DeclarationContainer.h index 94545eefb..0f0b57179 100644 --- a/libsolidity/DeclarationContainer.h +++ b/libsolidity/DeclarationContainer.h @@ -48,17 +48,17 @@ public: /// @param _update if true, replaces a potential declaration that is already present /// @returns false if the name was already declared. bool registerDeclaration(Declaration const& _declaration, bool _invisible = false, bool _update = false); - std::set resolveName(ASTString const& _name, bool _recursive = false) const; + std::vector resolveName(ASTString const& _name, bool _recursive = false) const; Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; } - std::map> const& getDeclarations() const { return m_declarations; } + std::map> const& getDeclarations() const { return m_declarations; } /// @returns whether declaration is valid, and if not also returns previous declaration. Declaration const* conflictingDeclaration(Declaration const& _declaration) const; private: Declaration const* m_enclosingDeclaration; DeclarationContainer const* m_enclosingContainer; - std::map> m_declarations; - std::map> m_invisibleDeclarations; + std::map> m_declarations; + std::map> m_invisibleDeclarations; }; } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 9aebbf054..4d33048dc 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -53,9 +53,13 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) m_currentScope = &m_scopes[&_contract]; linearizeBaseContracts(_contract); - // we first import non-functions only as we do not yet know the argument types - for (ContractDefinition const* base: _contract.getLinearizedBaseContracts()) - importInheritedScope(*base, false); // import non-functions + std::vector realBases( + ++_contract.getLinearizedBaseContracts().begin(), + _contract.getLinearizedBaseContracts().end() + ); + + for (ContractDefinition const* base: realBases) + importInheritedScope(*base); for (ASTPointer const& structDef: _contract.getDefinedStructs()) ReferencesResolver resolver(*structDef, *this, &_contract, nullptr); @@ -80,8 +84,6 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) } m_currentScope = &m_scopes[&_contract]; - for (ContractDefinition const* base: _contract.getLinearizedBaseContracts()) - importInheritedScope(*base, true); // import functions // now resolve references inside the code for (ASTPointer const& modifier: _contract.getFunctionModifiers()) @@ -115,20 +117,41 @@ void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) solAssert(_declaration.getScope() == nullptr, "Updated declaration outside global scope."); } -set NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const +vector NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const { auto iterator = m_scopes.find(_scope); if (iterator == end(m_scopes)) - return set({}); + return vector({}); return iterator->second.resolveName(_name, false); } -set NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) +vector NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) { return m_currentScope->resolveName(_name, _recursive); } -void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base, bool _importFunctions) +vector NameAndTypeResolver::cleanupedDeclarations(Identifier const& _identifier) +{ + vector result; + for (auto declaration : m_currentScope->resolveName(_identifier.getName())) + { + solAssert(declaration, ""); + // the declaration is functionDefinition while declarations > 1 + FunctionDefinition const& functionDefinition = dynamic_cast(*declaration); + FunctionType functionType(functionDefinition); + for(auto parameter: functionType.getParameterTypes() + functionType.getReturnParameterTypes()) + if (!parameter) + BOOST_THROW_EXCEPTION( + DeclarationError() << + errinfo_sourceLocation(_identifier.getLocation()) << + errinfo_comment("Function type can not be used in this context") + ); + //////////delete repitations. check by hasequalparameter types of function type + } + return result; +} + +void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) { auto iterator = m_scopes.find(&_base); solAssert(iterator != end(m_scopes), ""); @@ -136,30 +159,7 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base, for (auto const& declaration: nameAndDeclaration.second) // Import if it was declared in the base, is not the constructor and is visible in derived classes if (declaration->getScope() == &_base && declaration->isVisibleInDerivedContracts()) - { - auto function = dynamic_cast(declaration); - if ((function == nullptr) == _importFunctions) - continue; - if (!!function) - { - FunctionType functionType(*function); - // only import if a function with the same arguments does not exist yet - bool functionWithEqualArgumentsFound = false; - for (auto knownDeclaration: m_currentScope->resolveName(nameAndDeclaration.first)) - { - auto knownFunction = dynamic_cast(knownDeclaration); - if (!knownFunction) - continue; // this is not legal, but will be caught later - if (!FunctionType(*knownFunction).hasEqualArgumentTypes(functionType)) - continue; - functionWithEqualArgumentsFound = true; - break; - } - if (functionWithEqualArgumentsFound) - continue; - } m_currentScope->registerDeclaration(*declaration); - } } void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) const @@ -465,10 +465,9 @@ bool ReferencesResolver::visit(Identifier& _identifier) errinfo_comment("Undeclared identifier.") ); else if (declarations.size() == 1) - _identifier.setReferencedDeclaration(**declarations.begin(), m_currentContract); + _identifier.setReferencedDeclaration(*declarations.front(), m_currentContract); else - // Duplicate declaration will be checked in checkTypeRequirements() - _identifier.setOverloadedDeclarations(declarations); + _identifier.setOverloadedDeclarations(m_resolver.cleanupedDeclarations(_identifier)); return false; } diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 6528bbef2..21857352c 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -56,19 +56,20 @@ public: /// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted, /// the global scope is used (i.e. the one containing only the contract). /// @returns a pointer to the declaration on success or nullptr on failure. - std::set resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; + std::vector resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; /// Resolves a name in the "current" scope. Should only be called during the initial /// resolving phase. - std::set getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); + std::vector getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); + + std::vector cleanupedDeclarations(Identifier const& _identifier); private: void reset(); - /// Either imports all non-function members or all function members declared directly in the - /// given contract (i.e. does not import inherited members) into the current scope if they are - ///not present already. - void importInheritedScope(ContractDefinition const& _base, bool _importFunctions); + /// Imports all members declared directly in the given contract (i.e. does not import inherited members) + /// into the current scope if they are not present already. + void importInheritedScope(ContractDefinition const& _base); /// Computes "C3-Linearization" of base contracts and stores it inside the contract. void linearizeBaseContracts(ContractDefinition& _contract) const; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 65a6867d6..5b95e5567 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -617,6 +617,7 @@ public: /// @returns true if this function can take the given argument types (possibly /// after implicit conversion). bool canTakeArguments(TypePointers const& _arguments) const; + /// @returns true if the types of parameters are equal(does't check return parameter types) bool hasEqualArgumentTypes(FunctionType const& _other) const; Location const& getLocation() const { return m_location; }