diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp index d00affb91..b5655d3a3 100644 --- a/libsolidity/analysis/ConstantEvaluator.cpp +++ b/libsolidity/analysis/ConstantEvaluator.cpp @@ -25,8 +25,11 @@ #include #include + #include +#include + using namespace std; using namespace solidity; using namespace solidity::frontend; @@ -71,6 +74,11 @@ void ConstantEvaluator::endVisit(Literal const& _literal) setType(_literal, TypeProvider::forLiteral(_literal)); } +bool ConstantEvaluator::evaluated(ASTNode const& _node) const noexcept +{ + return m_evaluations.count(&_node) != 0; +} + void ConstantEvaluator::endVisit(Identifier const& _identifier) { VariableDeclaration const* variableDeclaration = dynamic_cast(_identifier.annotation().referencedDeclaration); @@ -82,11 +90,12 @@ void ConstantEvaluator::endVisit(Identifier const& _identifier) ASTPointer const& value = variableDeclaration->value(); if (!value) return; - else if (!m_types->count(value.get())) + else if (!evaluated(*value)) { if (m_depth > 32) m_errorReporter.fatalTypeError(5210_error, _identifier.location(), "Cyclic constant definition (or maximum recursion depth exhausted)."); - ConstantEvaluator(m_errorReporter, m_depth + 1, m_types).evaluate(*value); + + evaluate(*value); } setType(_identifier, type(*value)); @@ -101,16 +110,29 @@ void ConstantEvaluator::endVisit(TupleExpression const& _tuple) void ConstantEvaluator::setType(ASTNode const& _node, TypePointer const& _type) { if (_type && _type->category() == Type::Category::RationalNumber) - (*m_types)[&_node] = _type; + m_evaluations[&_node] = _type; } TypePointer ConstantEvaluator::type(ASTNode const& _node) { - return (*m_types)[&_node]; + if (auto p = m_evaluations.find(&_node); p != m_evaluations.end()) + return p->second; + return nullptr; +} + +TypePointer ConstantEvaluator::evaluate(langutil::ErrorReporter& _errorReporter, Expression const& _expr) +{ + EvaluationMap evaluations; + ConstantEvaluator evaluator(_errorReporter, evaluations); + return evaluator.evaluate(_expr); } TypePointer ConstantEvaluator::evaluate(Expression const& _expr) { + m_depth++; + ScopeGuard _([&]() { m_depth--; }); + _expr.accept(*this); + return type(_expr); } diff --git a/libsolidity/analysis/ConstantEvaluator.h b/libsolidity/analysis/ConstantEvaluator.h index 521f46338..70eeefb96 100644 --- a/libsolidity/analysis/ConstantEvaluator.h +++ b/libsolidity/analysis/ConstantEvaluator.h @@ -43,17 +43,20 @@ class TypeChecker; class ConstantEvaluator: private ASTConstVisitor { public: - ConstantEvaluator( - langutil::ErrorReporter& _errorReporter, - size_t _newDepth = 0, - std::shared_ptr> _types = std::make_shared>() - ): - m_errorReporter(_errorReporter), - m_depth(_newDepth), - m_types(std::move(_types)) + using EvaluationMap = std::map; + + ConstantEvaluator(langutil::ErrorReporter& _errorReporter, EvaluationMap& _evaluations): + m_errorReporter{ _errorReporter }, + m_evaluations{ _evaluations }, + m_depth{ 0 } { } + static TypePointer evaluate( + langutil::ErrorReporter& _errorReporter, + Expression const& _expr + ); + TypePointer evaluate(Expression const& _expr); private: @@ -63,13 +66,16 @@ private: void endVisit(Identifier const& _identifier) override; void endVisit(TupleExpression const& _tuple) override; - void setType(ASTNode const& _node, TypePointer const& _type); + void setType(ASTNode const& _node, TypePointer const& _value); + TypePointer type(ASTNode const& _node); + bool evaluated(ASTNode const& _node) const noexcept; + langutil::ErrorReporter& m_errorReporter; + EvaluationMap& m_evaluations; /// Current recursion depth. size_t m_depth = 0; - std::shared_ptr> m_types; }; } diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index 97bf923b1..be09ef10a 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -249,7 +249,7 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName) { TypePointer& lengthTypeGeneric = length->annotation().type; if (!lengthTypeGeneric) - lengthTypeGeneric = ConstantEvaluator(m_errorReporter).evaluate(*length); + lengthTypeGeneric = ConstantEvaluator::evaluate(m_errorReporter, *length); RationalNumberType const* lengthType = dynamic_cast(lengthTypeGeneric); u256 lengthValue = 0; if (!lengthType || !lengthType->mobileType()) diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp index abfeae23d..0d7b1604f 100644 --- a/libsolidity/analysis/StaticAnalyzer.cpp +++ b/libsolidity/analysis/StaticAnalyzer.cpp @@ -291,7 +291,7 @@ bool StaticAnalyzer::visit(BinaryOperation const& _operation) (_operation.getOperator() == Token::Div || _operation.getOperator() == Token::Mod) ) if (auto rhs = dynamic_cast( - ConstantEvaluator(m_errorReporter).evaluate(_operation.rightExpression()) + ConstantEvaluator::evaluate(m_errorReporter, _operation.rightExpression()) )) if (rhs->isZero()) m_errorReporter.typeError( @@ -314,7 +314,7 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall) solAssert(_functionCall.arguments().size() == 3, ""); if (*_functionCall.arguments()[2]->annotation().isPure) if (auto lastArg = dynamic_cast( - ConstantEvaluator(m_errorReporter).evaluate(*(_functionCall.arguments())[2]) + ConstantEvaluator::evaluate(m_errorReporter, *(_functionCall.arguments())[2]) )) if (lastArg->isZero()) m_errorReporter.typeError( diff --git a/libsolidity/ast/TypeProvider.cpp b/libsolidity/ast/TypeProvider.cpp index 3a06b2339..843ff9b09 100644 --- a/libsolidity/ast/TypeProvider.cpp +++ b/libsolidity/ast/TypeProvider.cpp @@ -347,6 +347,8 @@ TypePointer TypeProvider::forLiteral(Literal const& _literal) case Token::FalseLiteral: return boolean(); case Token::Number: + // TODO: return IntegerType, smallest fitting type in number of bits. + //return integer(8, IntegerType::Modifier::Unsigned); // XXX return rationalNumber(_literal); case Token::StringLiteral: case Token::UnicodeStringLiteral: diff --git a/test/libsolidity/syntaxTests/array/length/complex_cyclic_constant.sol b/test/libsolidity/syntaxTests/array/length/complex_cyclic_constant.sol index 38018165c..48599ad9c 100644 --- a/test/libsolidity/syntaxTests/array/length/complex_cyclic_constant.sol +++ b/test/libsolidity/syntaxTests/array/length/complex_cyclic_constant.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// TypeError 5210: (36-39): Cyclic constant definition (or maximum recursion depth exhausted). +// TypeError 5210: (69-71): Cyclic constant definition (or maximum recursion depth exhausted).