From c19d10321a116bec4ed08aabf3b3c8d74bf61608 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 15 Apr 2015 17:40:50 +0200 Subject: [PATCH] Fixed function overloads. Added tests, disallowed non-calling usage of non-unique function references. --- SolidityEndToEndTest.cpp | 202 +++++++++++++----------------- SolidityNameAndTypeResolution.cpp | 74 ++++++++++- 2 files changed, 161 insertions(+), 115 deletions(-) diff --git a/SolidityEndToEndTest.cpp b/SolidityEndToEndTest.cpp index 8218a2524..c18b3c562 100644 --- a/SolidityEndToEndTest.cpp +++ b/SolidityEndToEndTest.cpp @@ -304,7 +304,6 @@ BOOST_AUTO_TEST_CASE(for_loop_simple_init_expr) BOOST_AUTO_TEST_CASE(calling_other_functions) { - // note that the index of a function is its index in the sorted sequence of functions char const* sourceCode = "contract collatz {\n" " function run(uint x) returns(uint y) {\n" " while ((y = x) > 1) {\n" @@ -1095,26 +1094,6 @@ BOOST_AUTO_TEST_CASE(now) BOOST_CHECK(callContractFunction("someInfo()") == encodeArgs(true)); } -BOOST_AUTO_TEST_CASE(function_types) -{ - char const* sourceCode = "contract test {\n" - " function a(bool selector) returns (uint b) {\n" - " var f = fun1;\n" - " if (selector) f = fun2;\n" - " return f(9);\n" - " }\n" - " function fun1(uint x) returns (uint b) {\n" - " return 11;\n" - " }\n" - " function fun2(uint x) returns (uint b) {\n" - " return 12;\n" - " }\n" - "}\n"; - compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("a(bool)", false) == encodeArgs(11)); - BOOST_CHECK(callContractFunction("a(bool)", true) == encodeArgs(12)); -} - BOOST_AUTO_TEST_CASE(type_conversions_cleanup) { // 22-byte integer converted to a contract (i.e. address, 20 bytes), converted to a 32 byte @@ -3571,99 +3550,6 @@ BOOST_AUTO_TEST_CASE(packed_storage_structs_bytes) BOOST_CHECK(callContractFunction("test()") == encodeArgs(true)); } -BOOST_AUTO_TEST_CASE(overloaded_function_call_resolve_to_first) -{ - char const* sourceCode = R"( - contract test { - function f(uint k) returns(uint d) { return k; } - function f(uint a, uint b) returns(uint d) { return a + b; } - function g() returns(uint d) { return f(3); } - } - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("g()") == encodeArgs(3)); -} - -BOOST_AUTO_TEST_CASE(overloaded_function_call_resolve_to_second) -{ - char const* sourceCode = R"( - contract test { - function f(uint a, uint b) returns(uint d) { return a + b; } - function f(uint k) returns(uint d) { return k; } - function g() returns(uint d) { return f(3, 7); } - } - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("g()") == encodeArgs(10)); -} - -BOOST_AUTO_TEST_CASE(overloaded_function_call_with_if_else) -{ - char const* sourceCode = R"( - contract test { - function f(uint a, uint b) returns(uint d) { return a + b; } - function f(uint k) returns(uint d) { return k; } - function g(bool flag) returns(uint d) { - if (flag) - return f(3); - else - return f(3, 7); - } - } - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("g(bool)", true) == encodeArgs(3)); - BOOST_CHECK(callContractFunction("g(bool)", false) == encodeArgs(10)); -} - -BOOST_AUTO_TEST_CASE(overloaded_function_with_var) -{ - char const* sourceCode = R"( - contract test { - function f(uint k) returns(uint d) { return k; } - function f(uint a, uint b) returns(uint d) { return a + b; } - function g(bool flag) returns(uint d) { - var x = f; - if (flag) - return x(3); - else - return x(3, 7); - } - } - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("g(bool)", true) == encodeArgs(3)); - BOOST_CHECK(callContractFunction("g(bool)", false) == encodeArgs(10)); -} - -BOOST_AUTO_TEST_CASE(derived_overload_base_function_direct) -{ - char const* sourceCode = R"( - contract B { function f() returns(uint) { return 10; } } - contract C is B { - function f(uint i) returns(uint) { return 2 * i; } - function g() returns(uint) { return f(1); } - } - )"; - compileAndRun(sourceCode, 0, "C"); - BOOST_CHECK(callContractFunction("g()") == encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(derived_overload_base_function_indirect) -{ - char const* sourceCode = R"( - contract A { function f(uint a) returns(uint) { return 2 * a; } } - contract B { function f() returns(uint) { return 10; } } - contract C is A, B { - function g() returns(uint) { return f(); } - function h() returns(uint) { return f(1); } - } - )"; - compileAndRun(sourceCode, 0, "C"); - BOOST_CHECK(callContractFunction("g()") == encodeArgs(10)); - BOOST_CHECK(callContractFunction("h()") == encodeArgs(2)); -} - BOOST_AUTO_TEST_CASE(packed_storage_structs_delete) { char const* sourceCode = R"( @@ -3719,6 +3605,94 @@ BOOST_AUTO_TEST_CASE(packed_storage_structs_with_bytes0) BOOST_CHECK(callContractFunction("test()") == encodeArgs(true)); } +BOOST_AUTO_TEST_CASE(overloaded_function_call_resolve_to_first) +{ + char const* sourceCode = R"( + contract test { + function f(uint k) returns(uint d) { return k; } + function f(uint a, uint b) returns(uint d) { return a + b; } + function g() returns(uint d) { return f(3); } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("g()") == encodeArgs(3)); +} + +BOOST_AUTO_TEST_CASE(overloaded_function_call_resolve_to_second) +{ + char const* sourceCode = R"( + contract test { + function f(uint a, uint b) returns(uint d) { return a + b; } + function f(uint k) returns(uint d) { return k; } + function g() returns(uint d) { return f(3, 7); } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("g()") == encodeArgs(10)); +} + +BOOST_AUTO_TEST_CASE(overloaded_function_call_with_if_else) +{ + char const* sourceCode = R"( + contract test { + function f(uint a, uint b) returns(uint d) { return a + b; } + function f(uint k) returns(uint d) { return k; } + function g(bool flag) returns(uint d) { + if (flag) + return f(3); + else + return f(3, 7); + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("g(bool)", true) == encodeArgs(3)); + BOOST_CHECK(callContractFunction("g(bool)", false) == encodeArgs(10)); +} + +BOOST_AUTO_TEST_CASE(derived_overload_base_function_direct) +{ + char const* sourceCode = R"( + contract B { function f() returns(uint) { return 10; } } + contract C is B { + function f(uint i) returns(uint) { return 2 * i; } + function g() returns(uint) { return f(1); } + } + )"; + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("g()") == encodeArgs(2)); +} + +BOOST_AUTO_TEST_CASE(derived_overload_base_function_indirect) +{ + char const* sourceCode = R"( + contract A { function f(uint a) returns(uint) { return 2 * a; } } + contract B { function f() returns(uint) { return 10; } } + contract C is A, B { + function g() returns(uint) { return f(); } + function h() returns(uint) { return f(1); } + } + )"; + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("g()") == encodeArgs(10)); + BOOST_CHECK(callContractFunction("h()") == encodeArgs(2)); +} + +BOOST_AUTO_TEST_CASE(super_overload) +{ + char const* sourceCode = R"( + contract A { function f(uint a) returns(uint) { return 2 * a; } } + contract B { function f(bool b) returns(uint) { return 10; } } + contract C is A, B { + function g() returns(uint) { return super.f(true); } + function h() returns(uint) { return super.f(1); } + } + )"; + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("g()") == encodeArgs(10)); + BOOST_CHECK(callContractFunction("h()") == encodeArgs(2)); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/SolidityNameAndTypeResolution.cpp b/SolidityNameAndTypeResolution.cpp index 6bde9fd24..fd439fc84 100644 --- a/SolidityNameAndTypeResolution.cpp +++ b/SolidityNameAndTypeResolution.cpp @@ -1637,7 +1637,7 @@ BOOST_AUTO_TEST_CASE(overloaded_function_cannot_resolve) BOOST_AUTO_TEST_CASE(ambiguous_overloaded_function) { - // literal 1 can be both converted to uint8 and uint8, so it's ambiguous. + // literal 1 can be both converted to uint and uint8, so the call is ambiguous. char const* sourceCode = R"( contract test { function f(uint8 a) returns(uint) { return a; } @@ -1648,6 +1648,78 @@ BOOST_AUTO_TEST_CASE(ambiguous_overloaded_function) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(assignment_of_nonoverloaded_function) +{ + char const* sourceCode = R"( + contract test { + function f(uint a) returns(uint) { return 2 * a; } + function g() returns(uint) { var x = f; return x(7); } + } + )"; + ETH_TEST_REQUIRE_NO_THROW(parseTextAndResolveNames(sourceCode), "Type resolving failed"); +} + +BOOST_AUTO_TEST_CASE(assignment_of_overloaded_function) +{ + char const* sourceCode = R"( + contract test { + function f() returns(uint) { return 1; } + function f(uint a) returns(uint) { return 2 * a; } + function g() returns(uint) { var x = f; return x(7); } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(external_types_clash) +{ + char const* sourceCode = R"( + contract base { + enum a { X } + function f(a) { } + } + contract test is base { + function f(uint8 a) { } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(override_changes_return_types) +{ + char const* sourceCode = R"( + contract base { + function f(uint a) returns (uint) { } + } + contract test is base { + function f(uint a) returns (uint8) { } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(multiple_constructors) +{ + char const* sourceCode = R"( + contract test { + function test(uint a) { } + function test() {} + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), DeclarationError); +} + +BOOST_AUTO_TEST_CASE(equal_overload) +{ + char const* sourceCode = R"( + contract test { + function test(uint a) returns (uint b) { } + function test(uint a) external {} + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), DeclarationError); +} + BOOST_AUTO_TEST_SUITE_END() }