diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst index 782519644..ad78dd40f 100644 --- a/docs/contracts/using-for.rst +++ b/docs/contracts/using-for.rst @@ -45,7 +45,7 @@ Note that private library functions can only be specified when ``using for`` is If you define an operator (e.g. ``using {f as +} for T``), then the type (``T``) must be a :ref:`user-defined value type `. -The definition of an operator must be a function with the types of all parameters and +The definition of an operator must be a ``pure`` function with the types of all parameters and the return value matching ``T``, except for comparison operators, where the return value must be of type ``bool``. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index c43fff136..f90d72e7c 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -4001,6 +4001,13 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor) } solAssert(usingForType->typeDefinition()); + if (functionType->stateMutability() != StateMutability::Pure) + m_errorReporter.typeError( + 7775_error, + path->location(), + "Only pure functions can be used to define operators." + ); + bool identicalFirstTwoParameters = (parameterCount < 2 || *parameterTypes.at(0) == *parameterTypes.at(1)); bool isUnaryOnlyOperator = (!TokenTraits::isBinaryOp(*operator_) && TokenTraits::isUnaryOp(*operator_)); bool isBinaryOnlyOperator = diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index c2688728f..9db0873fc 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -653,7 +653,7 @@ private: * all functions, and this is checked at the point of the using statement. For versions 1 and * 2, this check is only done when a function is called. * - * For version 4, T has to be user-defined value type. + * For version 4, T has to be user-defined value type and the function must be pure. * All parameters and return value of all the functions have to be of type T. * This version can be combined with version 3 - a single directive may attach functions to the * type and define operators on it at the same time. diff --git a/test/libsolidity/semanticTests/operators/userDefined/calling_operator_that_makes_external_call.sol b/test/libsolidity/syntaxTests/operators/userDefined/calling_operator_that_makes_external_call.sol similarity index 81% rename from test/libsolidity/semanticTests/operators/userDefined/calling_operator_that_makes_external_call.sol rename to test/libsolidity/syntaxTests/operators/userDefined/calling_operator_that_makes_external_call.sol index dedf88b56..99f4f11c3 100644 --- a/test/libsolidity/semanticTests/operators/userDefined/calling_operator_that_makes_external_call.sol +++ b/test/libsolidity/syntaxTests/operators/userDefined/calling_operator_that_makes_external_call.sol @@ -21,5 +21,4 @@ contract C { } } // ---- -// test() -> 3 -// gas legacy: 119695 +// TypeError 7775: (27-30): Only pure functions can be used to define operators. diff --git a/test/libsolidity/syntaxTests/operators/userDefined/implementing_operator_with_non_pure_function.sol b/test/libsolidity/syntaxTests/operators/userDefined/implementing_operator_with_non_pure_function.sol new file mode 100644 index 000000000..5b29a0941 --- /dev/null +++ b/test/libsolidity/syntaxTests/operators/userDefined/implementing_operator_with_non_pure_function.sol @@ -0,0 +1,12 @@ +using {add as +, sub as -, mul as *} for A; + +function add(A, A) view returns (A) {} +function sub(A, A) returns (A) {} +function mul(A, A) payable returns (A) {} + +type A is address payable; +// ---- +// TypeError 7775: (7-10): Only pure functions can be used to define operators. +// TypeError 7775: (17-20): Only pure functions can be used to define operators. +// TypeError 7775: (27-30): Only pure functions can be used to define operators. +// TypeError 9559: (118-159): Free functions cannot be payable. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/user_operator_with_view_modifier.sol b/test/libsolidity/syntaxTests/viewPureChecker/user_operator_with_view_modifier.sol deleted file mode 100644 index dbe7796f6..000000000 --- a/test/libsolidity/syntaxTests/viewPureChecker/user_operator_with_view_modifier.sol +++ /dev/null @@ -1,17 +0,0 @@ -type Int is uint8; - -using { - add as + -} for Int; - - -function f_view() view {} - -function add(Int, Int) view returns (Int) { - f_view(); - return Int.wrap(0); -} - -function f() view { - Int.wrap(0) + Int.wrap(0); -} diff --git a/test/libsolidity/syntaxTests/viewPureChecker/user_operator_with_view_modifier_can_be_restricted.sol b/test/libsolidity/syntaxTests/viewPureChecker/user_operator_with_view_modifier_can_be_restricted.sol deleted file mode 100644 index 95063d44c..000000000 --- a/test/libsolidity/syntaxTests/viewPureChecker/user_operator_with_view_modifier_can_be_restricted.sol +++ /dev/null @@ -1,28 +0,0 @@ -type Int is uint8; - -using { - add as + -} for Int; - - -function f_view() view {} - -function add(Int, Int) view returns (Int) { - f_view(); - return Int.wrap(0); -} - -function f() view { - Int.wrap(0) + Int.wrap(0); -} - -function g() { - Int.wrap(0) + Int.wrap(0); -} - -function h() pure { - Int.wrap(0) + Int.wrap(0); -} -// ---- -// Warning 2018: (220-267): Function state mutability can be restricted to view -// TypeError 2527: (293-318): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".