aboutsummaryrefslogtreecommitdiffstats
path: root/test/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'test/libsolidity')
-rw-r--r--test/libsolidity/ASTJSON.cpp31
-rw-r--r--test/libsolidity/Assembly.cpp6
-rw-r--r--test/libsolidity/SolidityABIJSON.cpp28
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp562
-rw-r--r--test/libsolidity/SolidityExpressionCompiler.cpp37
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp225
-rw-r--r--test/libsolidity/SolidityOptimizer.cpp28
-rw-r--r--test/libsolidity/SolidityParser.cpp109
8 files changed, 977 insertions, 49 deletions
diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp
index 6c062ee8..b88218e7 100644
--- a/test/libsolidity/ASTJSON.cpp
+++ b/test/libsolidity/ASTJSON.cpp
@@ -197,6 +197,37 @@ BOOST_AUTO_TEST_CASE(non_utf8)
BOOST_CHECK(literal["attributes"]["type"].asString().find("invalid") != string::npos);
}
+BOOST_AUTO_TEST_CASE(function_type)
+{
+ CompilerStack c;
+ c.addSource("a",
+ "contract C { function f(function() external payable returns (uint) x) "
+ "returns (function() external constant returns (uint)) {} }"
+ );
+ c.parse();
+ map<string, unsigned> sourceIndices;
+ sourceIndices["a"] = 1;
+ Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value fun = astJson["children"][0]["children"][0];
+ BOOST_CHECK_EQUAL(fun["name"], "FunctionDefinition");
+ Json::Value argument = fun["children"][0]["children"][0];
+ BOOST_CHECK_EQUAL(argument["name"], "VariableDeclaration");
+ BOOST_CHECK_EQUAL(argument["attributes"]["name"], "x");
+ BOOST_CHECK_EQUAL(argument["attributes"]["type"], "function () payable external returns (uint256)");
+ Json::Value funType = argument["children"][0];
+ BOOST_CHECK_EQUAL(funType["attributes"]["constant"], false);
+ BOOST_CHECK_EQUAL(funType["attributes"]["payable"], true);
+ BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external");
+ Json::Value retval = fun["children"][1]["children"][0];
+ BOOST_CHECK_EQUAL(retval["name"], "VariableDeclaration");
+ BOOST_CHECK_EQUAL(retval["attributes"]["name"], "");
+ BOOST_CHECK_EQUAL(retval["attributes"]["type"], "function () constant external returns (uint256)");
+ funType = retval["children"][0];
+ BOOST_CHECK_EQUAL(funType["attributes"]["constant"], true);
+ BOOST_CHECK_EQUAL(funType["attributes"]["payable"], false);
+ BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp
index eddba5e1..e5ce691b 100644
--- a/test/libsolidity/Assembly.cpp
+++ b/test/libsolidity/Assembly.cpp
@@ -116,10 +116,10 @@ BOOST_AUTO_TEST_CASE(location_test)
shared_ptr<string const> n = make_shared<string>("");
AssemblyItems items = compileContract(sourceCode);
vector<SourceLocation> locations =
- vector<SourceLocation>(18, SourceLocation(2, 75, n)) +
- vector<SourceLocation>(31, SourceLocation(20, 72, n)) +
+ vector<SourceLocation>(16, SourceLocation(2, 75, n)) +
+ vector<SourceLocation>(27, SourceLocation(20, 72, n)) +
vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} +
- vector<SourceLocation>(4, SourceLocation(58, 67, n)) +
+ vector<SourceLocation>(2, SourceLocation(58, 67, n)) +
vector<SourceLocation>(3, SourceLocation(20, 72, n));
checkAssemblyLocations(items, locations);
}
diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp
index 0ad9e928..5cabb7fa 100644
--- a/test/libsolidity/SolidityABIJSON.cpp
+++ b/test/libsolidity/SolidityABIJSON.cpp
@@ -684,7 +684,7 @@ BOOST_AUTO_TEST_CASE(payable_function)
checkInterface(sourceCode, interface);
}
-BOOST_AUTO_TEST_CASE(payable_fallback_unction)
+BOOST_AUTO_TEST_CASE(payable_fallback_function)
{
char const* sourceCode = R"(
contract test {
@@ -703,6 +703,32 @@ BOOST_AUTO_TEST_CASE(payable_fallback_unction)
checkInterface(sourceCode, interface);
}
+BOOST_AUTO_TEST_CASE(function_type)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function g(function(uint) external returns (uint) x) {}
+ }
+ )";
+
+ char const* interface = R"(
+ [
+ {
+ "constant" : false,
+ "payable": false,
+ "inputs": [{
+ "name": "x",
+ "type": "function"
+ }],
+ "name": "g",
+ "outputs": [],
+ "type" : "function"
+ }
+ ]
+ )";
+ checkInterface(sourceCode, interface);
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index d8924250..ed95d687 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -7606,6 +7606,568 @@ BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call)
BOOST_CHECK(callContractFunction("f(address)", cAddrOpt) == encodeArgs(u256(7)));
}
+BOOST_AUTO_TEST_CASE(calling_uninitialized_function)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function intern() returns (uint) {
+ function (uint) internal returns (uint) x;
+ x(2);
+ return 7;
+ }
+ function extern() returns (uint) {
+ function (uint) external returns (uint) x;
+ x(2);
+ return 7;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ // This should throw exceptions
+ BOOST_CHECK(callContractFunction("intern()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("extern()") == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(calling_uninitialized_function_in_detail)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function() internal returns (uint) x;
+ int mutex;
+ function t() returns (uint) {
+ if (mutex > 0)
+ return 7;
+ mutex = 1;
+ // Avoid re-executing this function if we jump somewhere.
+ x();
+ return 2;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("t()") == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(pass_function_types_internally)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f(uint x) returns (uint) {
+ return eval(g, x);
+ }
+ function eval(function(uint) returns (uint) x, uint a) internal returns (uint) {
+ return x(a);
+ }
+ function g(uint x) returns (uint) { return x + 1; }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(uint256)", 7) == encodeArgs(u256(8)));
+}
+
+BOOST_AUTO_TEST_CASE(pass_function_types_externally)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f(uint x) returns (uint) {
+ return this.eval(this.g, x);
+ }
+ function f2(uint x) returns (uint) {
+ return eval(this.g, x);
+ }
+ function eval(function(uint) external returns (uint) x, uint a) returns (uint) {
+ return x(a);
+ }
+ function g(uint x) returns (uint) { return x + 1; }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(uint256)", 7) == encodeArgs(u256(8)));
+ BOOST_CHECK(callContractFunction("f2(uint256)", 7) == encodeArgs(u256(8)));
+}
+
+BOOST_AUTO_TEST_CASE(receive_external_function_type)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function g() returns (uint) { return 7; }
+ function f(function() external returns (uint) g) returns (uint) {
+ return g();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction(
+ "f(function)",
+ m_contractAddress.asBytes() + FixedHash<4>(dev::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0)
+ ) == encodeArgs(u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(return_external_function_type)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function g() {}
+ function f() returns (function() external) {
+ return this.g;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(
+ callContractFunction("f()") ==
+ m_contractAddress.asBytes() + FixedHash<4>(dev::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0)
+ );
+}
+
+BOOST_AUTO_TEST_CASE(store_function)
+{
+ char const* sourceCode = R"(
+ contract Other {
+ function addTwo(uint x) returns (uint) { return x + 2; }
+ }
+ contract C {
+ function (function (uint) external returns (uint)) returns (uint) ev;
+ function (uint) external returns (uint) x;
+ function store(function(uint) external returns (uint) y) {
+ x = y;
+ }
+ function eval(function(uint) external returns (uint) y) returns (uint) {
+ return y(7);
+ }
+ function t() returns (uint) {
+ ev = eval;
+ this.store((new Other()).addTwo);
+ return ev(x);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(9)));
+}
+
+BOOST_AUTO_TEST_CASE(store_function_in_constructor)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint public result_in_constructor;
+ function (uint) internal returns (uint) x;
+ function C () {
+ x = double;
+ result_in_constructor = use(2);
+ }
+ function double(uint _arg) returns (uint _ret) {
+ _ret = _arg * 2;
+ }
+ function use(uint _arg) returns (uint) {
+ return x(_arg);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("use(uint256)", encodeArgs(u256(3))) == encodeArgs(u256(6)));
+ BOOST_CHECK(callContractFunction("result_in_constructor()") == encodeArgs(u256(4)));
+}
+
+// TODO: store bound internal library functions
+
+BOOST_AUTO_TEST_CASE(store_internal_unused_function_in_constructor)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function () internal returns (uint) x;
+ function C () {
+ x = unused;
+ }
+ function unused() internal returns (uint) {
+ return 7;
+ }
+ function t() returns (uint) {
+ return x();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(store_internal_unused_library_function_in_constructor)
+{
+ char const* sourceCode = R"(
+ library L { function x() internal returns (uint) { return 7; } }
+ contract C {
+ function () internal returns (uint) x;
+ function C () {
+ x = L.x;
+ }
+ function t() returns (uint) {
+ return x();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint public initial;
+ function C() {
+ initial = double(2);
+ }
+ function double(uint _arg) returns (uint _ret) {
+ _ret = _arg * 2;
+ }
+ function runtime(uint _arg) returns (uint) {
+ return double(_arg);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("runtime(uint256)", encodeArgs(u256(3))) == encodeArgs(u256(6)));
+ BOOST_CHECK(callContractFunction("initial()") == encodeArgs(u256(4)));
+}
+
+BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime_equality_check)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function (uint) internal returns (uint) x;
+ function C() {
+ x = double;
+ }
+ function test() returns (bool) {
+ return x == double;
+ }
+ function double(uint _arg) returns (uint _ret) {
+ _ret = _arg * 2;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(true));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_library_internal)
+{
+ char const* sourceCode = R"(
+ library Utils {
+ function reduce(uint[] memory array, function(uint, uint) returns (uint) f, uint init) internal returns (uint) {
+ for (uint i = 0; i < array.length; i++) {
+ init = f(array[i], init);
+ }
+ return init;
+ }
+ function sum(uint a, uint b) internal returns (uint) {
+ return a + b;
+ }
+ }
+ contract C {
+ function f(uint[] x) returns (uint) {
+ return Utils.reduce(x, Utils.sum, 0);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(uint256[])", 0x20, 3, u256(1), u256(7), u256(3)) == encodeArgs(u256(11)));
+}
+
+
+BOOST_AUTO_TEST_CASE(call_function_returning_function)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f0() returns (uint) {
+ return 2;
+ }
+ function f1() internal returns (function() returns (uint)) {
+ return f0;
+ }
+ function f2() internal returns (function() returns (function () returns (uint))) {
+ return f1;
+ }
+ function f3() internal returns (function() returns (function () returns (function () returns (uint))))
+ {
+ return f2;
+ }
+ function f() returns (uint) {
+ function() returns(function() returns(function() returns(function() returns(uint)))) x;
+ x = f3;
+ return x()()()();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "test");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(2)));
+}
+
+BOOST_AUTO_TEST_CASE(mapping_of_functions)
+{
+ char const* sourceCode = R"(
+ contract Flow {
+ bool public success;
+
+ mapping (address => function () internal) stages;
+
+ function stage0() internal {
+ stages[msg.sender] = stage1;
+ }
+
+ function stage1() internal {
+ stages[msg.sender] = stage2;
+ }
+
+ function stage2() internal {
+ success = true;
+ }
+
+ function Flow() {
+ stages[msg.sender] = stage0;
+ }
+
+ function f() returns (uint) {
+ stages[msg.sender]();
+ return 7;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "Flow");
+ BOOST_CHECK(callContractFunction("success()") == encodeArgs(false));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("success()") == encodeArgs(false));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("success()") == encodeArgs(true));
+}
+
+BOOST_AUTO_TEST_CASE(packed_functions)
+{
+ char const* sourceCode = R"(
+ contract C {
+ // these should take the same slot
+ function() returns (uint) a;
+ function() external returns (uint) b;
+ function() external returns (uint) c;
+ function() returns (uint) d;
+ uint8 public x;
+
+ function set() {
+ x = 2;
+ d = g;
+ c = this.h;
+ b = this.h;
+ a = g;
+ }
+ function t1() returns (uint) {
+ return a();
+ }
+ function t2() returns (uint) {
+ return b();
+ }
+ function t3() returns (uint) {
+ return a();
+ }
+ function t4() returns (uint) {
+ return b();
+ }
+ function g() returns (uint) {
+ return 7;
+ }
+ function h() returns (uint) {
+ return 8;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("set()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("t1()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("t2()") == encodeArgs(u256(8)));
+ BOOST_CHECK(callContractFunction("t3()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("t4()") == encodeArgs(u256(8)));
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(2)));
+}
+
+BOOST_AUTO_TEST_CASE(function_memory_array)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function a(uint x) returns (uint) { return x + 1; }
+ function b(uint x) returns (uint) { return x + 2; }
+ function c(uint x) returns (uint) { return x + 3; }
+ function d(uint x) returns (uint) { return x + 5; }
+ function e(uint x) returns (uint) { return x + 8; }
+ function test(uint x, uint i) returns (uint) {
+ function(uint) internal returns (uint)[] memory arr =
+ new function(uint) internal returns (uint)[](10);
+ arr[0] = a;
+ arr[1] = b;
+ arr[2] = c;
+ arr[3] = d;
+ arr[4] = e;
+ return arr[i](x);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(0)) == encodeArgs(u256(11)));
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(1)) == encodeArgs(u256(12)));
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(2)) == encodeArgs(u256(13)));
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(3)) == encodeArgs(u256(15)));
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(4)) == encodeArgs(u256(18)));
+ BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(5)) == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(function_delete_storage)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function a() returns (uint) { return 7; }
+ function() internal returns (uint) y;
+ function set() returns (uint) {
+ y = a;
+ return y();
+ }
+ function d() returns (uint) {
+ delete y;
+ return 1;
+ }
+ function ca() returns (uint) {
+ return y();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("set()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("ca()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("d()") == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("ca()") == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(function_delete_stack)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function a() returns (uint) { return 7; }
+ function test() returns (uint) {
+ var y = a;
+ delete y;
+ y();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(copy_function_storage_array)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function() internal returns (uint)[] x;
+ function() internal returns (uint)[] y;
+ function test() returns (uint) {
+ x.length = 10;
+ x[9] = a;
+ y = x;
+ return y[9]();
+ }
+ function a() returns (uint) {
+ return 7;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(function_array_cross_calls)
+{
+ char const* sourceCode = R"(
+ contract D {
+ function f(function() external returns (function() external returns (uint))[] x)
+ returns (function() external returns (uint)[3] r)
+ {
+ r[0] = x[0]();
+ r[1] = x[1]();
+ r[2] = x[2]();
+ }
+ }
+ contract C {
+ function test() returns (uint, uint, uint) {
+ function() external returns (function() external returns (uint))[] memory x =
+ new function() external returns (function() external returns (uint))[](10);
+ for (uint i = 0; i < x.length; i ++)
+ x[i] = this.h;
+ x[0] = this.htwo;
+ var y = (new D()).f(x);
+ return (y[0](), y[1](), y[2]());
+ }
+ function e() returns (uint) { return 5; }
+ function f() returns (uint) { return 6; }
+ function g() returns (uint) { return 7; }
+ uint counter;
+ function h() returns (function() external returns (uint)) {
+ return counter++ == 0 ? this.f : this.g;
+ }
+ function htwo() returns (function() external returns (uint)) {
+ return this.e;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(5), u256(6), u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(copy_internal_function_array_to_storage)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function() internal returns (uint)[20] x;
+ int mutex;
+ function one() returns (uint) {
+ function() internal returns (uint)[20] xmem;
+ x = xmem;
+ return 3;
+ }
+ function two() returns (uint) {
+ if (mutex > 0)
+ return 7;
+ mutex = 1;
+ // If this test fails, it might re-execute this function.
+ x[0]();
+ return 2;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("one()") == encodeArgs(u256(3)));
+ BOOST_CHECK(callContractFunction("two()") == encodeArgs());
+}
+
BOOST_AUTO_TEST_CASE(shift_constant_left)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp
index e9a05745..91edfefd 100644
--- a/test/libsolidity/SolidityExpressionCompiler.cpp
+++ b/test/libsolidity/SolidityExpressionCompiler.cpp
@@ -325,12 +325,12 @@ BOOST_AUTO_TEST_CASE(arithmetics)
byte(Instruction::ADD),
byte(Instruction::DUP2),
byte(Instruction::ISZERO),
- byte(Instruction::PUSH1), 0x2,
+ byte(Instruction::PUSH1), 0x0,
byte(Instruction::JUMPI),
byte(Instruction::MOD),
byte(Instruction::DUP2),
byte(Instruction::ISZERO),
- byte(Instruction::PUSH1), 0x2,
+ byte(Instruction::PUSH1), 0x0,
byte(Instruction::JUMPI),
byte(Instruction::DIV),
byte(Instruction::MUL)});
@@ -425,39 +425,6 @@ BOOST_AUTO_TEST_CASE(assignment)
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
-BOOST_AUTO_TEST_CASE(function_call)
-{
- char const* sourceCode = "contract test {\n"
- " function f(uint a, uint b) { a += g(a + 1, b) * 2; }\n"
- " function g(uint a, uint b) returns (uint c) {}\n"
- "}\n";
- bytes code = compileFirstExpression(sourceCode, {{"test", "g"}},
- {{"test", "f", "a"}, {"test", "f", "b"}});
-
- // Stack: a, b
- bytes expectation({byte(Instruction::PUSH1), 0x02,
- byte(Instruction::PUSH1), 0x0c,
- byte(Instruction::PUSH1), 0x01,
- byte(Instruction::DUP5),
- byte(Instruction::ADD),
- // Stack here: a b 2 <ret label> (a+1)
- byte(Instruction::DUP4),
- byte(Instruction::PUSH1), 0x13,
- byte(Instruction::JUMP),
- byte(Instruction::JUMPDEST),
- // Stack here: a b 2 g(a+1, b)
- byte(Instruction::MUL),
- // Stack here: a b g(a+1, b)*2
- byte(Instruction::DUP3),
- byte(Instruction::ADD),
- // Stack here: a b a+g(a+1, b)*2
- byte(Instruction::SWAP2),
- byte(Instruction::POP),
- byte(Instruction::DUP2),
- byte(Instruction::JUMPDEST)});
- BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
-}
-
BOOST_AUTO_TEST_CASE(negative_literals_8bits)
{
char const* sourceCode = "contract test {\n"
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index f498a0b9..865eb7ce 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -4132,6 +4132,231 @@ BOOST_AUTO_TEST_CASE(using_directive_for_missing_selftype)
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
+BOOST_AUTO_TEST_CASE(function_type)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ function(uint) returns (uint) x;
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_parameter)
+{
+ char const* text = R"(
+ contract C {
+ function f(function(uint) external returns (uint) g) returns (function(uint) external returns (uint)) {
+ return g;
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_returned)
+{
+ char const* text = R"(
+ contract C {
+ function f() returns (function(uint) external returns (uint) g) {
+ return g;
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(private_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ function(uint) private returns (uint) x;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(public_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ function(uint) public returns (uint) x;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(payable_internal_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function (uint) internal payable returns (uint) x;
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(call_value_on_non_payable_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function (uint) external returns (uint) x;
+ function f() {
+ x.value(2)();
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(external_function_type_returning_internal)
+{
+ char const* text = R"(
+ contract C {
+ function() external returns (function () internal) x;
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(external_function_type_taking_internal)
+{
+ char const* text = R"(
+ contract C {
+ function(function () internal) external x;
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(call_value_on_payable_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function (uint) external payable returns (uint) x;
+ function f() {
+ x.value(2)(1);
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter)
+{
+ // It should not be possible to give internal functions
+ // as parameters to external functions.
+ char const* text = R"(
+ contract C {
+ function f(function(uint) internal returns (uint) x) {
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(internal_function_returned_from_public_function)
+{
+ // It should not be possible to return internal functions from external functions.
+ char const* text = R"(
+ contract C {
+ function f() returns (function(uint) internal returns (uint) x) {
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter_in_library_internal)
+{
+ char const* text = R"(
+ library L {
+ function f(function(uint) internal returns (uint) x) internal {
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter_in_library_external)
+{
+ char const* text = R"(
+ library L {
+ function f(function(uint) internal returns (uint) x) {
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(function_type_arrays)
+{
+ char const* text = R"(
+ contract C {
+ function(uint) external returns (uint)[] public x;
+ function(uint) internal returns (uint)[10] y;
+ function f() {
+ function(uint) returns (uint)[10] memory a;
+ function(uint) returns (uint)[10] storage b = y;
+ function(uint) external returns (uint)[] memory c;
+ c = new function(uint) external returns (uint)[](200);
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(delete_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function(uint) external returns (uint) x;
+ function(uint) internal returns (uint) y;
+ function f() {
+ delete x;
+ var a = y;
+ delete a;
+ delete y;
+ var c = f;
+ delete c;
+ function(uint) internal returns (uint) g;
+ delete g;
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(delete_function_type_invalid)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ delete f;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(delete_external_function_type_invalid)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ delete this.f;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
+}
+
BOOST_AUTO_TEST_CASE(invalid_fixed_point_literal)
{
char const* text = R"(
diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp
index 562b7859..4991cf24 100644
--- a/test/libsolidity/SolidityOptimizer.cpp
+++ b/test/libsolidity/SolidityOptimizer.cpp
@@ -365,16 +365,6 @@ BOOST_AUTO_TEST_CASE(store_tags_as_unions)
// BOOST_CHECK_EQUAL(2, numSHA3s);
}
-BOOST_AUTO_TEST_CASE(successor_not_found_bug)
-{
- // This bug was caused because MSVC chose to use the u256->bool conversion
- // instead of u256->unsigned
- char const* sourceCode = R"(
- contract greeter { function greeter() {} }
- )";
- compileBothVersions(sourceCode);
-}
-
BOOST_AUTO_TEST_CASE(incorrect_storage_access_bug)
{
// This bug appeared because a sha3 operation with too low sequence number was used,
@@ -1238,6 +1228,24 @@ BOOST_AUTO_TEST_CASE(inconsistency)
compareVersions("trigger()");
}
+BOOST_AUTO_TEST_CASE(dead_code_elimination_across_assemblies)
+{
+ // This tests that a runtime-function that is stored in storage in the constructor
+ // is not removed as part of dead code elimination.
+ char const* sourceCode = R"(
+ contract DCE {
+ function () internal returns (uint) stored;
+ function DCE() {
+ stored = f;
+ }
+ function f() internal returns (uint) { return 7; }
+ function test() returns (uint) { return stored(); }
+ }
+ )";
+ compileBothVersions(sourceCode);
+ compareVersions("test()");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index ec23d5fd..914dbc30 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -1241,6 +1241,115 @@ BOOST_AUTO_TEST_CASE(payable_accessor)
BOOST_CHECK(!successParse(text));
}
+BOOST_AUTO_TEST_CASE(function_type_in_expression)
+{
+ char const* text = R"(
+ contract test {
+ function f(uint x, uint y) returns (uint a) {}
+ function g() {
+ function (uint, uint) internal returns (uint) f1 = f;
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_as_storage_variable)
+{
+ char const* text = R"(
+ contract test {
+ function (uint, uint) internal returns (uint) f1;
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_as_storage_variable_with_modifiers)
+{
+ char const* text = R"(
+ contract test {
+ function (uint, uint) modifier1() returns (uint) f1;
+ }
+ )";
+ BOOST_CHECK(!successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_as_storage_variable_with_assignment)
+{
+ char const* text = R"(
+ contract test {
+ function f(uint x, uint y) returns (uint a) {}
+ function (uint, uint) internal returns (uint) f1 = f;
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_in_struct)
+{
+ char const* text = R"(
+ contract test {
+ struct S {
+ function (uint x, uint y) internal returns (uint a) f;
+ function (uint, uint) external returns (uint) g;
+ uint d;
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_as_parameter)
+{
+ char const* text = R"(
+ contract test {
+ function f(function(uint) external returns (uint) g) internal returns (uint a) {
+ return g(1);
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(calling_function)
+{
+ char const* text = R"(
+ contract test {
+ function f() {
+ function() returns(function() returns(function() returns(function() returns(uint)))) x;
+ uint y;
+ y = x()()()();
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(mapping_and_array_of_functions)
+{
+ char const* text = R"(
+ contract test {
+ mapping (address => function() internal returns (uint)) a;
+ mapping (address => function() external) b;
+ mapping (address => function() external[]) c;
+ function() external[] d;
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_state_variable)
+{
+ char const* text = R"(
+ contract test {
+ function() x;
+ function() y = x;
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+
BOOST_AUTO_TEST_SUITE_END()
}