Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3d1830f

Browse files
authored
Merge pull request argotorg#3232 from ethereum/simplifyConstant
Simplify ConstantEvaluator.
2 parents bfc5446 + e7ed9d8 commit 3d1830f

File tree

5 files changed

+80
-62
lines changed

5 files changed

+80
-62
lines changed

libsolidity/analysis/ConstantEvaluator.cpp

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -28,51 +28,42 @@ using namespace std;
2828
using namespace dev;
2929
using namespace dev::solidity;
3030

31-
/// FIXME: this is pretty much a copy of TypeChecker::endVisit(BinaryOperation)
3231
void ConstantEvaluator::endVisit(UnaryOperation const& _operation)
3332
{
34-
TypePointer const& subType = _operation.subExpression().annotation().type;
35-
if (!dynamic_cast<RationalNumberType const*>(subType.get()))
36-
m_errorReporter.fatalTypeError(_operation.subExpression().location(), "Invalid constant expression.");
37-
TypePointer t = subType->unaryOperatorResult(_operation.getOperator());
38-
_operation.annotation().type = t;
33+
auto sub = type(_operation.subExpression());
34+
if (sub)
35+
setType(_operation, sub->unaryOperatorResult(_operation.getOperator()));
3936
}
4037

41-
/// FIXME: this is pretty much a copy of TypeChecker::endVisit(BinaryOperation)
4238
void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
4339
{
44-
TypePointer const& leftType = _operation.leftExpression().annotation().type;
45-
TypePointer const& rightType = _operation.rightExpression().annotation().type;
46-
if (!dynamic_cast<RationalNumberType const*>(leftType.get()))
47-
m_errorReporter.fatalTypeError(_operation.leftExpression().location(), "Invalid constant expression.");
48-
if (!dynamic_cast<RationalNumberType const*>(rightType.get()))
49-
m_errorReporter.fatalTypeError(_operation.rightExpression().location(), "Invalid constant expression.");
50-
TypePointer commonType = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
51-
if (!commonType)
40+
auto left = type(_operation.leftExpression());
41+
auto right = type(_operation.rightExpression());
42+
if (left && right)
5243
{
53-
m_errorReporter.typeError(
54-
_operation.location(),
55-
"Operator " +
56-
string(Token::toString(_operation.getOperator())) +
57-
" not compatible with types " +
58-
leftType->toString() +
59-
" and " +
60-
rightType->toString()
44+
auto commonType = left->binaryOperatorResult(_operation.getOperator(), right);
45+
if (!commonType)
46+
m_errorReporter.fatalTypeError(
47+
_operation.location(),
48+
"Operator " +
49+
string(Token::toString(_operation.getOperator())) +
50+
" not compatible with types " +
51+
left->toString() +
52+
" and " +
53+
right->toString()
54+
);
55+
setType(
56+
_operation,
57+
Token::isCompareOp(_operation.getOperator()) ?
58+
make_shared<BoolType>() :
59+
commonType
6160
);
62-
commonType = leftType;
6361
}
64-
_operation.annotation().commonType = commonType;
65-
_operation.annotation().type =
66-
Token::isCompareOp(_operation.getOperator()) ?
67-
make_shared<BoolType>() :
68-
commonType;
6962
}
7063

7164
void ConstantEvaluator::endVisit(Literal const& _literal)
7265
{
73-
_literal.annotation().type = Type::forLiteral(_literal);
74-
if (!_literal.annotation().type)
75-
m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value.");
66+
setType(_literal, Type::forLiteral(_literal));
7667
}
7768

7869
void ConstantEvaluator::endVisit(Identifier const& _identifier)
@@ -81,18 +72,34 @@ void ConstantEvaluator::endVisit(Identifier const& _identifier)
8172
if (!variableDeclaration)
8273
return;
8374
if (!variableDeclaration->isConstant())
84-
m_errorReporter.fatalTypeError(_identifier.location(), "Identifier must be declared constant.");
75+
return;
8576

86-
ASTPointer<Expression> value = variableDeclaration->value();
77+
ASTPointer<Expression> const& value = variableDeclaration->value();
8778
if (!value)
88-
m_errorReporter.fatalTypeError(_identifier.location(), "Constant identifier declaration must have a constant value.");
89-
90-
if (!value->annotation().type)
79+
return;
80+
else if (!m_types->count(value.get()))
9181
{
9282
if (m_depth > 32)
9383
m_errorReporter.fatalTypeError(_identifier.location(), "Cyclic constant definition (or maximum recursion depth exhausted).");
94-
ConstantEvaluator e(*value, m_errorReporter, m_depth + 1);
84+
ConstantEvaluator(m_errorReporter, m_depth + 1, m_types).evaluate(*value);
9585
}
9686

97-
_identifier.annotation().type = value->annotation().type;
87+
setType(_identifier, type(*value));
88+
}
89+
90+
void ConstantEvaluator::setType(ASTNode const& _node, TypePointer const& _type)
91+
{
92+
if (_type && _type->category() == Type::Category::RationalNumber)
93+
(*m_types)[&_node] = _type;
94+
}
95+
96+
TypePointer ConstantEvaluator::type(ASTNode const& _node)
97+
{
98+
return (*m_types)[&_node];
99+
}
100+
101+
TypePointer ConstantEvaluator::evaluate(Expression const& _expr)
102+
{
103+
_expr.accept(*this);
104+
return type(_expr);
98105
}

libsolidity/analysis/ConstantEvaluator.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,32 @@ class TypeChecker;
3838
class ConstantEvaluator: private ASTConstVisitor
3939
{
4040
public:
41-
ConstantEvaluator(Expression const& _expr, ErrorReporter& _errorReporter, size_t _newDepth = 0):
41+
ConstantEvaluator(
42+
ErrorReporter& _errorReporter,
43+
size_t _newDepth = 0,
44+
std::shared_ptr<std::map<ASTNode const*, TypePointer>> _types = std::make_shared<std::map<ASTNode const*, TypePointer>>()
45+
):
4246
m_errorReporter(_errorReporter),
43-
m_depth(_newDepth)
47+
m_depth(_newDepth),
48+
m_types(_types)
4449
{
45-
_expr.accept(*this);
4650
}
4751

52+
TypePointer evaluate(Expression const& _expr);
53+
4854
private:
4955
virtual void endVisit(BinaryOperation const& _operation);
5056
virtual void endVisit(UnaryOperation const& _operation);
5157
virtual void endVisit(Literal const& _literal);
5258
virtual void endVisit(Identifier const& _identifier);
5359

60+
void setType(ASTNode const& _node, TypePointer const& _type);
61+
TypePointer type(ASTNode const& _node);
62+
5463
ErrorReporter& m_errorReporter;
5564
/// Current recursion depth.
56-
size_t m_depth;
65+
size_t m_depth = 0;
66+
std::shared_ptr<std::map<ASTNode const*, TypePointer>> m_types;
5767
};
5868

5969
}

libsolidity/analysis/ReferencesResolver.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,12 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
146146
fatalTypeError(_typeName.baseType().location(), "Illegal base type of storage size zero for array.");
147147
if (Expression const* length = _typeName.length())
148148
{
149-
if (!length->annotation().type)
150-
ConstantEvaluator e(*length, m_errorReporter);
151-
auto const* lengthType = dynamic_cast<RationalNumberType const*>(length->annotation().type.get());
149+
TypePointer lengthTypeGeneric = length->annotation().type;
150+
if (!lengthTypeGeneric)
151+
lengthTypeGeneric = ConstantEvaluator(m_errorReporter).evaluate(*length);
152+
RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric.get());
152153
if (!lengthType || !lengthType->mobileType())
153-
fatalTypeError(length->location(), "Invalid array length, expected integer literal.");
154+
fatalTypeError(length->location(), "Invalid array length, expected integer literal or constant expression.");
154155
else if (lengthType->isFractional())
155156
fatalTypeError(length->location(), "Array with fractional length specified.");
156157
else if (lengthType->isNegative())

libsolidity/ast/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ class Type: private boost::noncopyable, public std::enable_shared_from_this<Type
257257
}
258258
virtual u256 literalValue(Literal const*) const
259259
{
260-
solAssert(false, "Literal value requested for type without literals.");
260+
solAssert(false, "Literal value requested for type without literals: " + toString(false));
261261
}
262262

263263
/// @returns a (simpler) type that is encoded in the same way for external function calls.

test/libsolidity/SolidityNameAndTypeResolution.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,7 +2109,7 @@ BOOST_AUTO_TEST_CASE(array_with_nonconstant_length)
21092109
function f(uint a) public { uint8[a] x; }
21102110
}
21112111
)";
2112-
CHECK_ERROR(text, TypeError, "Identifier must be declared constant.");
2112+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
21132113
}
21142114

21152115
BOOST_AUTO_TEST_CASE(array_with_negative_length)
@@ -4398,7 +4398,7 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_signed_fixed_type)
43984398
}
43994399
}
44004400
)";
4401-
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
4401+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
44024402
}
44034403

44044404
BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type)
@@ -4410,7 +4410,7 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type)
44104410
}
44114411
}
44124412
)";
4413-
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
4413+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
44144414
}
44154415

44164416
BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion)
@@ -7254,7 +7254,7 @@ BOOST_AUTO_TEST_CASE(array_length_too_large)
72547254
uint[8**90] ids;
72557255
}
72567256
)";
7257-
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
7257+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
72587258
}
72597259

72607260
BOOST_AUTO_TEST_CASE(array_length_not_convertible_to_integer)
@@ -7264,7 +7264,7 @@ BOOST_AUTO_TEST_CASE(array_length_not_convertible_to_integer)
72647264
uint[true] ids;
72657265
}
72667266
)";
7267-
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
7267+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
72687268
}
72697269

72707270
BOOST_AUTO_TEST_CASE(array_length_constant_var)
@@ -7286,7 +7286,7 @@ BOOST_AUTO_TEST_CASE(array_length_non_integer_constant_var)
72867286
uint[LEN] ids;
72877287
}
72887288
)";
7289-
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
7289+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
72907290
}
72917291

72927292
BOOST_AUTO_TEST_CASE(array_length_cannot_be_function)
@@ -7297,7 +7297,7 @@ BOOST_AUTO_TEST_CASE(array_length_cannot_be_function)
72977297
uint[f] ids;
72987298
}
72997299
)";
7300-
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
7300+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
73017301
}
73027302

73037303
BOOST_AUTO_TEST_CASE(array_length_can_be_recursive_constant)
@@ -7321,7 +7321,7 @@ BOOST_AUTO_TEST_CASE(array_length_cannot_be_function_call)
73217321
uint[LEN] ids;
73227322
}
73237323
)";
7324-
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
7324+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
73257325
}
73267326

73277327
BOOST_AUTO_TEST_CASE(array_length_const_cannot_be_fractional)
@@ -7370,7 +7370,7 @@ BOOST_AUTO_TEST_CASE(array_length_cannot_be_constant_function_parameter)
73707370
}
73717371
}
73727372
)";
7373-
CHECK_ERROR(text, TypeError, "Constant identifier declaration must have a constant value.");
7373+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
73747374
}
73757375

73767376
BOOST_AUTO_TEST_CASE(array_length_with_cyclic_constant)
@@ -7409,7 +7409,7 @@ BOOST_AUTO_TEST_CASE(array_length_with_pure_functions)
74097409
uint[LEN] ids;
74107410
}
74117411
)";
7412-
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
7412+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
74137413
}
74147414

74157415
BOOST_AUTO_TEST_CASE(array_length_invalid_expression)
@@ -7419,25 +7419,25 @@ BOOST_AUTO_TEST_CASE(array_length_invalid_expression)
74197419
uint[-true] ids;
74207420
}
74217421
)";
7422-
CHECK_ERROR(text, TypeError, "Invalid constant expression.");
7422+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
74237423
text = R"(
74247424
contract C {
74257425
uint[true/1] ids;
74267426
}
74277427
)";
7428-
CHECK_ERROR(text, TypeError, "Invalid constant expression.");
7428+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
74297429
text = R"(
74307430
contract C {
74317431
uint[1/true] ids;
74327432
}
74337433
)";
7434-
CHECK_ERROR(text, TypeError, "Invalid constant expression.");
7434+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
74357435
text = R"(
74367436
contract C {
74377437
uint[1.111111E1111111111111] ids;
74387438
}
74397439
)";
7440-
CHECK_ERROR(text, TypeError, "Invalid literal value.");
7440+
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
74417441
text = R"(
74427442
contract C {
74437443
uint[3/0] ids;

0 commit comments

Comments
 (0)