aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Beregszaszi <alex@rtfs.hu>2017-11-22 10:34:17 +0800
committerGitHub <noreply@github.com>2017-11-22 10:34:17 +0800
commit4e0723ce27b343b9dd7c423542b9261d7c48927b (patch)
treec9f709e54f729ed76df401b380ae4e245eb793df
parentf22ac8fc9647fbbef172f7c0a1f6799a5a0b38a8 (diff)
parent455e51a608910d60348adb4b464590d976ce7fd7 (diff)
downloaddexon-solidity-4e0723ce27b343b9dd7c423542b9261d7c48927b.tar
dexon-solidity-4e0723ce27b343b9dd7c423542b9261d7c48927b.tar.gz
dexon-solidity-4e0723ce27b343b9dd7c423542b9261d7c48927b.tar.bz2
dexon-solidity-4e0723ce27b343b9dd7c423542b9261d7c48927b.tar.lz
dexon-solidity-4e0723ce27b343b9dd7c423542b9261d7c48927b.tar.xz
dexon-solidity-4e0723ce27b343b9dd7c423542b9261d7c48927b.tar.zst
dexon-solidity-4e0723ce27b343b9dd7c423542b9261d7c48927b.zip
Merge pull request #3142 from Balajiganapathi/allow_constant_array_length
Allow constant integer variables as array lengths.
-rw-r--r--Changelog.md1
-rw-r--r--libsolidity/analysis/ConstantEvaluator.cpp22
-rw-r--r--libsolidity/analysis/ConstantEvaluator.h8
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp18
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp147
5 files changed, 193 insertions, 3 deletions
diff --git a/Changelog.md b/Changelog.md
index 2487b87c..a362138e 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,6 +1,7 @@
### 0.4.19 (unreleased)
Features:
+ * Allow constant variables to be used as array length
* Syntax Checker: Turn the usage of ``callcode`` into an error as experimental 0.5.0 feature.
* Type Checker: Improve address checksum warning.
* Type Checker: More detailed errors for invalid array lengths (such as division by zero).
diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp
index bc3b7cf1..4d546e68 100644
--- a/libsolidity/analysis/ConstantEvaluator.cpp
+++ b/libsolidity/analysis/ConstantEvaluator.cpp
@@ -74,3 +74,25 @@ void ConstantEvaluator::endVisit(Literal const& _literal)
if (!_literal.annotation().type)
m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value.");
}
+
+void ConstantEvaluator::endVisit(Identifier const& _identifier)
+{
+ VariableDeclaration const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration);
+ if (!variableDeclaration)
+ return;
+ if (!variableDeclaration->isConstant())
+ m_errorReporter.fatalTypeError(_identifier.location(), "Identifier must be declared constant.");
+
+ ASTPointer<Expression> value = variableDeclaration->value();
+ if (!value)
+ m_errorReporter.fatalTypeError(_identifier.location(), "Constant identifier declaration must have a constant value.");
+
+ if (!value->annotation().type)
+ {
+ if (m_depth > 32)
+ m_errorReporter.fatalTypeError(_identifier.location(), "Cyclic constant definition (or maximum recursion depth exhausted).");
+ ConstantEvaluator e(*value, m_errorReporter, m_depth + 1);
+ }
+
+ _identifier.annotation().type = value->annotation().type;
+}
diff --git a/libsolidity/analysis/ConstantEvaluator.h b/libsolidity/analysis/ConstantEvaluator.h
index 90bceb5d..6725d610 100644
--- a/libsolidity/analysis/ConstantEvaluator.h
+++ b/libsolidity/analysis/ConstantEvaluator.h
@@ -38,8 +38,9 @@ class TypeChecker;
class ConstantEvaluator: private ASTConstVisitor
{
public:
- ConstantEvaluator(Expression const& _expr, ErrorReporter& _errorReporter):
- m_errorReporter(_errorReporter)
+ ConstantEvaluator(Expression const& _expr, ErrorReporter& _errorReporter, size_t _newDepth = 0):
+ m_errorReporter(_errorReporter),
+ m_depth(_newDepth)
{
_expr.accept(*this);
}
@@ -48,8 +49,11 @@ private:
virtual void endVisit(BinaryOperation const& _operation);
virtual void endVisit(UnaryOperation const& _operation);
virtual void endVisit(Literal const& _literal);
+ virtual void endVisit(Identifier const& _identifier);
ErrorReporter& m_errorReporter;
+ /// Current recursion depth.
+ size_t m_depth;
};
}
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 9a837113..c2f96aaa 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -2345,6 +2345,24 @@ BOOST_AUTO_TEST_CASE(constructor_static_array_argument)
ABI_CHECK(callContractFunction("b(uint256)", u256(2)), encodeArgs(u256(4)));
}
+BOOST_AUTO_TEST_CASE(constant_var_as_array_length)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint constant LEN = 3;
+ uint[LEN] public a;
+
+ function C(uint[LEN] _a) {
+ a = _a;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C", encodeArgs(u256(1), u256(2), u256(3)));
+ ABI_CHECK(callContractFunction("a(uint256)", u256(0)), encodeArgs(u256(1)));
+ ABI_CHECK(callContractFunction("a(uint256)", u256(1)), encodeArgs(u256(2)));
+ ABI_CHECK(callContractFunction("a(uint256)", u256(2)), encodeArgs(u256(3)));
+}
+
BOOST_AUTO_TEST_CASE(functions_called_by_constructor)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 88ec58ee..73c1660e 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -2107,7 +2107,7 @@ BOOST_AUTO_TEST_CASE(array_with_nonconstant_length)
function f(uint a) public { uint8[a] x; }
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Identifier must be declared constant.");
}
BOOST_AUTO_TEST_CASE(array_with_negative_length)
@@ -7263,6 +7263,151 @@ BOOST_AUTO_TEST_CASE(array_length_not_convertible_to_integer)
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
}
+BOOST_AUTO_TEST_CASE(array_length_constant_var)
+{
+ char const* text = R"(
+ contract C {
+ uint constant LEN = 10;
+ uint[LEN] ids;
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
+BOOST_AUTO_TEST_CASE(array_length_non_integer_constant_var)
+{
+ char const* text = R"(
+ contract C {
+ bool constant LEN = true;
+ uint[LEN] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+}
+
+BOOST_AUTO_TEST_CASE(array_length_cannot_be_function)
+{
+ char const* text = R"(
+ contract C {
+ function f() {}
+ uint[f] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+}
+
+BOOST_AUTO_TEST_CASE(array_length_can_be_recursive_constant)
+{
+ char const* text = R"(
+ contract C {
+ uint constant L = 5;
+ uint constant LEN = L + 4 * L;
+ uint[LEN] ids;
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
+BOOST_AUTO_TEST_CASE(array_length_cannot_be_function_call)
+{
+ char const* text = R"(
+ contract C {
+ function f(uint x) {}
+ uint constant LEN = f();
+ uint[LEN] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+}
+
+BOOST_AUTO_TEST_CASE(array_length_const_cannot_be_fractional)
+{
+ char const* text = R"(
+ contract C {
+ fixed constant L = 10.5;
+ uint[L] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Array with fractional length specified");
+}
+
+BOOST_AUTO_TEST_CASE(array_length_can_be_constant_in_struct)
+{
+ char const* text = R"(
+ contract C {
+ uint constant LEN = 10;
+ struct Test {
+ uint[LEN] ids;
+ }
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
+BOOST_AUTO_TEST_CASE(array_length_can_be_constant_in_function)
+{
+ char const* text = R"(
+ contract C {
+ uint constant LEN = 10;
+ function f() {
+ uint[LEN] a;
+ }
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
+BOOST_AUTO_TEST_CASE(array_length_cannot_be_constant_function_parameter)
+{
+ char const* text = R"(
+ contract C {
+ function f(uint constant LEN) {
+ uint[LEN] a;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Constant identifier declaration must have a constant value.");
+}
+
+BOOST_AUTO_TEST_CASE(array_length_with_cyclic_constant)
+{
+ char const* text = R"(
+ contract C {
+ uint constant LEN = LEN;
+ function f() {
+ uint[LEN] a;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Cyclic constant definition (or maximum recursion depth exhausted).");
+}
+
+BOOST_AUTO_TEST_CASE(array_length_with_complex_cyclic_constant)
+{
+ char const* text = R"(
+ contract C {
+ uint constant L2 = LEN - 10;
+ uint constant L1 = L2 / 10;
+ uint constant LEN = 10 + L1 * 5;
+ function f() {
+ uint[LEN] a;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Cyclic constant definition (or maximum recursion depth exhausted).");
+}
+
+BOOST_AUTO_TEST_CASE(array_length_with_pure_functions)
+{
+ char const* text = R"(
+ contract C {
+ uint constant LEN = keccak256(ripemd160(33));
+ uint[LEN] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+}
+
BOOST_AUTO_TEST_CASE(array_length_invalid_expression)
{
char const* text = R"(