diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index a63b3f27d..8ec9f649d 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1849,7 +1849,8 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) if (userDefinedOperatorResult) solAssert( userDefinedFunctionType->returnParameterTypes().size() == 1 && - *userDefinedFunctionType->returnParameterTypes().front() == *_operation.annotation().type + *userDefinedFunctionType->returnParameterTypes().front() == *_operation.annotation().type, + "User defined operator has an invalid return parameter." ); else if (_operation.getOperator() == Token::Exp || _operation.getOperator() == Token::SHL) { diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 13e6b8028..4841240c0 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -404,10 +404,19 @@ Result Type::userDefinedOperator(Token _token, ASTNod function.libraryFunction() ? function.typeViaContractName() : function.type() ); solAssert(functionType && !functionType->parameterTypes().empty()); - solAssert(isImplicitlyConvertibleTo(*functionType->parameterTypes().front())); + + Type const* expectedReturnType = + TokenTraits::isCompareOp(_token) ? + TypeProvider::boolean() : functionType->parameterTypes().front(); + if ( - (_unaryOperation && function.parameterList().parameters().size() == 1) || - (!_unaryOperation && function.parameterList().parameters().size() == 2) + isImplicitlyConvertibleTo(*functionType->parameterTypes().front()) && + function.returnParameterList()->parameters().size() == 1 && + function.returnParameterList()->parameters().front()->type()->isImplicitlyConvertibleTo(*expectedReturnType) && + ( + (_unaryOperation && function.parameterList().parameters().size() == 1) || + (!_unaryOperation && function.parameterList().parameters().size() == 2) + ) ) seenFunctions.insert(&function); } diff --git a/test/libsolidity/syntaxTests/operators/custom/operator_invalid_parameters.sol b/test/libsolidity/syntaxTests/operators/custom/operator_invalid_parameters.sol new file mode 100644 index 000000000..1a84fc47a --- /dev/null +++ b/test/libsolidity/syntaxTests/operators/custom/operator_invalid_parameters.sol @@ -0,0 +1,33 @@ +type Int is int256; + +using { + add as +, sub as -, div as / +} for Int; + +function add(Int) pure returns (Int) { + return Int.wrap(0); +} + +function sub(Int, Int, Int) pure returns (Int) { + return Int.wrap(1); +} + +function div(int256, int256) pure returns (Int) { + return Int.wrap(2); +} + +function f() pure { + Int.wrap(0) + Int.wrap(1); + Int.wrap(0) - Int.wrap(0); + Int.wrap(0) / Int.wrap(0); + Int.wrap(0) * Int.wrap(0); +} + +// ---- +// TypeError 1884: (33-36): The function "add" needs to have two parameters of equal type to be used for the operator +. +// TypeError 8112: (43-46): The function "sub" needs to have one or two parameters to be used for the operator -. +// TypeError 3100: (53-56): The function "div" cannot be bound to the type "Int" because the type cannot be implicitly converted to the first argument of the function ("int256"). +// TypeError 2271: (317-342): Operator + not compatible with types Int and Int. No matching user-defined operator found. +// TypeError 2271: (348-373): Operator - not compatible with types Int and Int. No matching user-defined operator found. +// TypeError 2271: (379-404): Operator / not compatible with types Int and Int. No matching user-defined operator found. +// TypeError 2271: (410-435): Operator * not compatible with types Int and Int. No matching user-defined operator found. diff --git a/test/libsolidity/syntaxTests/operators/custom/operator_invalid_return_parameters.sol b/test/libsolidity/syntaxTests/operators/custom/operator_invalid_return_parameters.sol new file mode 100644 index 000000000..7a97461da --- /dev/null +++ b/test/libsolidity/syntaxTests/operators/custom/operator_invalid_return_parameters.sol @@ -0,0 +1,49 @@ +type Int is int256; + +using { + add as +, + div as /, + unsub as -, + gt as >, + lt as < +} for Int; + +function add(Int x, Int y) pure returns (int256) { + return 0; +} + +function div(Int x, Int y) pure { + x = y; +} + +function unsub(Int) pure returns (Int, Int) { + return (Int.wrap(0), Int.wrap(1)); +} + +function gt(Int, Int) pure returns (Int) { + return Int.wrap(0); +} + +function lt(Int, Int) pure returns (bool, Int) { + return (true, Int.wrap(1)); +} + +function f() pure { + Int.wrap(0) + Int.wrap(1); + Int.wrap(0) / Int.wrap(0); + -Int.wrap(0); + Int.wrap(0) < Int.wrap(0); + Int.wrap(0) > Int.wrap(0); +} + +// ---- +// TypeError 7743: (33-36): The function "add" needs to return exactly one value of type Int to be used for the operator +. +// TypeError 7743: (47-50): The function "div" needs to return exactly one value of type Int to be used for the operator /. +// TypeError 7743: (61-66): The function "unsub" needs to return exactly one value of type Int to be used for the operator -. +// TypeError 7995: (77-79): The function "gt" needs to return exactly one value of type bool to be used for the operator >. +// TypeError 7995: (90-92): The function "lt" needs to return exactly one value of type bool to be used for the operator <. +// TypeError 2271: (492-517): Operator + not compatible with types Int and Int. No matching user-defined operator found. +// TypeError 2271: (523-548): Operator / not compatible with types Int and Int. No matching user-defined operator found. +// TypeError 4907: (554-566): Unary operator - cannot be applied to type Int +// TypeError 2271: (572-597): Operator < not compatible with types Int and Int. No matching user-defined operator found. +// TypeError 2271: (603-628): Operator > not compatible with types Int and Int. No matching user-defined operator found. diff --git a/test/libsolidity/syntaxTests/operators/custom/operator_wrong_number_params_return.sol b/test/libsolidity/syntaxTests/operators/custom/operator_wrong_number_params_return.sol deleted file mode 100644 index 34b69a259..000000000 --- a/test/libsolidity/syntaxTests/operators/custom/operator_wrong_number_params_return.sol +++ /dev/null @@ -1,39 +0,0 @@ -type Int is int256; - -using { - add as +, sub as -, - mul as *, div as /, - gt as >, lt as < -} for Int; - -function add(Int) pure returns (Int) { - return Int.wrap(0); -} - -function sub(Int, Int, Int) pure returns (Int) { - return Int.wrap(1); -} - -function mul(Int) pure returns (Int) { - return Int.wrap(2); -} - -function div(Int x, Int y) pure { - x = y; -} - -function gt(Int, Int) pure returns (Int) { - return Int.wrap(0); -} - -function lt(Int, Int) pure returns (bool, Int) { - return (true, Int.wrap(1)); -} - -// ---- -// TypeError 1884: (33-36): The function "add" needs to have two parameters of equal type to be used for the operator +. -// TypeError 8112: (43-46): The function "sub" needs to have one or two parameters to be used for the operator -. -// TypeError 1884: (57-60): The function "mul" needs to have two parameters of equal type to be used for the operator *. -// TypeError 7743: (67-70): The function "div" needs to return exactly one value of type Int to be used for the operator /. -// TypeError 7995: (81-83): The function "gt" needs to return exactly one value of type bool to be used for the operator >. -// TypeError 7995: (90-92): The function "lt" needs to return exactly one value of type bool to be used for the operator <.