From 41948b13097a8fed084dbdc8ff970cf1d49c40b1 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 16 Dec 2014 23:45:24 +0100 Subject: [PATCH] Fix: Resolve function types of all contracts before checking types inside functions. --- libsolidity/CompilerStack.cpp | 9 +++++++++ libsolidity/NameAndTypeResolver.cpp | 13 +++++++------ libsolidity/NameAndTypeResolver.h | 2 ++ test/solidityCompiler.cpp | 8 ++++++-- test/solidityExpressionCompiler.cpp | 7 ++++++- test/solidityNameAndTypeResolution.cpp | 18 ++++++++++++++++++ 6 files changed, 48 insertions(+), 9 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 23f5fd68f..1242c0aba 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -73,6 +73,15 @@ void CompilerStack::parse() resolver.resolveNamesAndTypes(*contract); m_contracts[contract->getName()].contract = contract; } + for (Source const* source: m_sourceOrder) + for (ASTPointer const& node: source->ast->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { + m_globalContext->setCurrentContract(*contract); + resolver.updateDeclaration(*m_globalContext->getCurrentThis()); + resolver.checkTypeRequirements(*contract); + m_contracts[contract->getName()].contract = contract; + } m_parseSuccessful = true; } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 2ad276801..80732615c 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -49,8 +49,6 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) m_currentScope = &m_scopes[&_contract]; for (ASTPointer const& structDef: _contract.getDefinedStructs()) ReferencesResolver resolver(*structDef, *this, nullptr); - for (ASTPointer const& structDef: _contract.getDefinedStructs()) - structDef->checkValidityOfMembers(); for (ASTPointer const& variable: _contract.getStateVariables()) ReferencesResolver resolver(*variable, *this, nullptr); for (ASTPointer const& function: _contract.getDefinedFunctions()) @@ -59,13 +57,16 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) ReferencesResolver referencesResolver(*function, *this, function->getReturnParameterList().get()); } - // First, the parameter types of all functions need to be resolved before we can check - // the types, since it is possible to call functions that are only defined later - // in the source. - _contract.checkTypeRequirements(); m_currentScope = &m_scopes[nullptr]; } +void NameAndTypeResolver::checkTypeRequirements(ContractDefinition& _contract) +{ + for (ASTPointer const& structDef: _contract.getDefinedStructs()) + structDef->checkValidityOfMembers(); + _contract.checkTypeRequirements(); +} + void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) { m_scopes[nullptr].registerDeclaration(_declaration, true); diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 1ff9febf0..23ac5fe77 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -46,6 +46,8 @@ public: void registerDeclarations(SourceUnit& _sourceUnit); /// Resolves all names and types referenced from the given contract. void resolveNamesAndTypes(ContractDefinition& _contract); + /// Check all type requirements in the given contract. + void checkTypeRequirements(ContractDefinition& _contract); /// Updates the given global declaration (used for "this"). Not to be used with declarations /// that create their own scope. void updateDeclaration(Declaration const& _declaration); diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 29f61454a..9ae8ff50b 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -52,9 +52,13 @@ bytes compileContract(const string& _sourceCode) resolver.registerDeclarations(*sourceUnit); for (ASTPointer const& node: sourceUnit->getNodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) - { BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); - + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract)); + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { Compiler compiler; compiler.compileContract(*contract, {}, {}); // debug diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp index c05db25d4..2bdc38421 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -95,8 +95,13 @@ bytes compileFirstExpression(const string& _sourceCode, vector> _ resolver.registerDeclarations(*sourceUnit); for (ASTPointer const& node: sourceUnit->getNodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) - { BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract)); + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { FirstExpressionExtractor extractor(*contract); BOOST_REQUIRE(extractor.getExpression() != nullptr); diff --git a/test/solidityNameAndTypeResolution.cpp b/test/solidityNameAndTypeResolution.cpp index 0ea6e51b9..0bda0a1fd 100644 --- a/test/solidityNameAndTypeResolution.cpp +++ b/test/solidityNameAndTypeResolution.cpp @@ -47,6 +47,9 @@ void parseTextAndResolveNames(std::string const& _source) for (ASTPointer const& node: sourceUnit->getNodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) resolver.resolveNamesAndTypes(*contract); + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + resolver.checkTypeRequirements(*contract); } } @@ -293,6 +296,21 @@ BOOST_AUTO_TEST_CASE(returns_in_constructor) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +BOOST_AUTO_TEST_CASE(forward_function_reference) +{ + char const* text = "contract First {\n" + " function fun() returns (bool ret) {\n" + " return Second(1).fun(1, true, 3) > 0;\n" + " }\n" + "}\n" + "contract Second {\n" + " function fun(uint a, bool b, uint c) returns (uint ret) {\n" + " if (First(2).fun() == true) return 1;\n" + " }\n" + "}\n"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + BOOST_AUTO_TEST_SUITE_END() }