diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index ed1bd1d30..fd6fc0587 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -46,12 +46,12 @@ NameAndTypeResolver::NameAndTypeResolver( m_scopes[nullptr]->registerDeclaration(*declaration); } -bool NameAndTypeResolver::registerDeclarations(ASTNode& _sourceUnit) +bool NameAndTypeResolver::registerDeclarations(ASTNode& _sourceUnit, ASTNode const* _currentScope) { // The helper registers all declarations in m_scopes as a side-effect of its construction. try { - DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit, m_errors); + DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit, m_errors, _currentScope); } catch (FatalError const&) { @@ -451,21 +451,22 @@ void NameAndTypeResolver::reportFatalTypeError(Error const& _e) DeclarationRegistrationHelper::DeclarationRegistrationHelper( map>& _scopes, ASTNode& _astRoot, - ErrorList& _errors + ErrorList& _errors, + ASTNode const* _currentScope ): m_scopes(_scopes), - m_currentScope(nullptr), + m_currentScope(_currentScope), m_errors(_errors) { _astRoot.accept(*this); - solAssert(m_currentScope == nullptr, "Scopes not correctly closed."); + solAssert(m_currentScope == _currentScope, "Scopes not correctly closed."); } bool DeclarationRegistrationHelper::visit(SourceUnit& _sourceUnit) { if (!m_scopes[&_sourceUnit]) // By importing, it is possible that the container already exists. - m_scopes[&_sourceUnit].reset(new DeclarationContainer(nullptr, m_scopes[nullptr].get())); + m_scopes[&_sourceUnit].reset(new DeclarationContainer(m_currentScope, m_scopes[m_currentScope].get())); m_currentScope = &_sourceUnit; return true; } diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h index 1c7af0c92..4de40e87a 100644 --- a/libsolidity/analysis/NameAndTypeResolver.h +++ b/libsolidity/analysis/NameAndTypeResolver.h @@ -49,7 +49,9 @@ public: ); /// Registers all declarations found in the AST node, usually a source unit. /// @returns false in case of error. - bool registerDeclarations(ASTNode& _sourceUnit); + /// @param _currentScope should be nullptr but can be used to inject new declarations into + /// existing scopes, used by the snippets feature. + bool registerDeclarations(ASTNode& _sourceUnit, ASTNode const* _currentScope = nullptr); /// Applies the effect of import directives. bool performImports(SourceUnit& _sourceUnit, std::map const& _sourceUnits); /// Resolves all names and types referenced from the given AST Node. @@ -130,10 +132,15 @@ private: class DeclarationRegistrationHelper: private ASTVisitor { public: + /// Registers declarations in their scopes and creates new scopes as a side-effect + /// of construction. + /// @param _currentScope should be nullptr if we start at SourceUnit, but can be different + /// to inject new declarations into an existing scope, used by snippets. DeclarationRegistrationHelper( std::map>& _scopes, ASTNode& _astRoot, - ErrorList& _errors + ErrorList& _errors, + ASTNode const* _currentScope = nullptr ); private: diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index be59d3d26..06a9e1cea 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -427,7 +427,12 @@ bool TypeChecker::visit(StructDefinition const& _struct) bool TypeChecker::visit(FunctionDefinition const& _function) { - bool isLibraryFunction = dynamic_cast(*_function.scope()).isLibrary(); + bool isLibraryFunction = false; + if ( + dynamic_cast(_function.scope()) && + dynamic_cast(_function.scope())->isLibrary() + ) + isLibraryFunction = true; if (_function.isPayable()) { if (isLibraryFunction)