From b86056181469f00638b5bce6e3ffded5e0696d7a Mon Sep 17 00:00:00 2001 From: wechman Date: Wed, 3 Aug 2022 12:02:24 +0200 Subject: [PATCH] Simplify Type::userDefinedOperator function --- libsolidity/analysis/TypeChecker.cpp | 64 +++++++++++++++---- libsolidity/ast/Types.cpp | 6 -- .../operator_invalid_return_parameters.sol | 22 +++++-- 3 files changed, 66 insertions(+), 26 deletions(-) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index a8b644125..28cc69a04 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1750,13 +1750,37 @@ bool TypeChecker::visit(UnaryOperation const& _operation) solAssert(!builtinResult || !userDefinedOperatorResult); if (userDefinedOperatorResult) { - solAssert(userDefinedFunctionType->parameterTypes().size() == 1); - solAssert(userDefinedFunctionType->returnParameterTypes().size() == 1); - solAssert( - *userDefinedFunctionType->parameterTypes().at(0) == - *userDefinedFunctionType->returnParameterTypes().at(0) - ); - _operation.annotation().type = userDefinedFunctionType->returnParameterTypes().at(0); + if (userDefinedFunctionType->returnParameterTypes().size() != 1) + { + m_errorReporter.typeError( + 3138_error, + _operation.location(), + "User defined operator " + string(TokenTraits::toString(_operation.getOperator())) + + " needs to return exactly one value." + ); + _operation.annotation().type = subExprType; + } + else if (*userDefinedFunctionType->returnParameterTypes().front() != *userDefinedFunctionType->parameterTypes().front()) + { + m_errorReporter.typeError( + 7983_error, + _operation.location(), + "User defined operator " + string(TokenTraits::toString(_operation.getOperator())) + + " needs to return value of type " + + userDefinedFunctionType->parameterTypes().front()->humanReadableName() + "." + ); + _operation.annotation().type = subExprType; + } + else + { + solAssert(userDefinedFunctionType->parameterTypes().size() == 1); + solAssert( + *userDefinedFunctionType->parameterTypes().at(0) == + *userDefinedFunctionType->returnParameterTypes().at(0) + ); + _operation.annotation().type = userDefinedFunctionType->returnParameterTypes().at(0); + } + } else if (builtinResult) _operation.annotation().type = builtinResult; @@ -1840,7 +1864,8 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) *userDefinedFunctionType->parameterTypes().at(0) == *userDefinedFunctionType->parameterTypes().at(1) ); - commonType = userDefinedFunctionType->returnParameterTypes().at(0); + if (userDefinedFunctionType->returnParameterTypes().size() == 1) + commonType = userDefinedFunctionType->parameterTypes().at(0); } _operation.annotation().commonType = commonType; @@ -1850,11 +1875,24 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) commonType; if (userDefinedOperatorResult) - solAssert( - userDefinedFunctionType->returnParameterTypes().size() == 1 && - *userDefinedFunctionType->returnParameterTypes().front() == *_operation.annotation().type, - "User defined operator has an invalid return parameter." - ); + { + if (userDefinedFunctionType->returnParameterTypes().size() != 1) + m_errorReporter.typeError( + 1208_error, + _operation.location(), + "User defined operator " + string(TokenTraits::toString(_operation.getOperator())) + + " needs to return exactly one value." + ); + + else if (*userDefinedFunctionType->returnParameterTypes().front() != *_operation.annotation().type) + m_errorReporter.typeError( + 3841_error, + _operation.location(), + "User defined operator " + string(TokenTraits::toString(_operation.getOperator())) + + " needs to return value of type " + + _operation.annotation().type->humanReadableName() + "." + ); + } else if (_operation.getOperator() == Token::Exp || _operation.getOperator() == Token::SHL) { string operation = _operation.getOperator() == Token::Exp ? "exponentiation" : "shift"; diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 6bf311bab..b26f3e4aa 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -404,14 +404,8 @@ Result Type::userDefinedOperator(Token _token, ASTNod ); solAssert(functionType && !functionType->parameterTypes().empty()); - Type const* expectedReturnType = - TokenTraits::isCompareOp(_token) ? - TypeProvider::boolean() : functionType->parameterTypes().front(); - if ( 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) diff --git a/test/libsolidity/syntaxTests/operators/custom/operator_invalid_return_parameters.sol b/test/libsolidity/syntaxTests/operators/custom/operator_invalid_return_parameters.sol index c8ad3b8dd..7373edba1 100644 --- a/test/libsolidity/syntaxTests/operators/custom/operator_invalid_return_parameters.sol +++ b/test/libsolidity/syntaxTests/operators/custom/operator_invalid_return_parameters.sol @@ -4,6 +4,7 @@ using { add as +, div as /, unsub as -, + bitnot as ~, gt as >, lt as < } for Int; @@ -20,6 +21,10 @@ function unsub(Int) pure returns (Int, Int) { return (Int.wrap(0), Int.wrap(1)); } +function bitnot(Int) pure returns (int256) { + return 0; +} + function gt(Int, Int) pure returns (Int) { return Int.wrap(0); } @@ -32,6 +37,7 @@ 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) > Int.wrap(0); } @@ -40,10 +46,12 @@ function f() pure { // 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. No matching user-defined operator found. -// 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. +// TypeError 7743: (77-83): The function "bitnot" needs to return exactly one value of type Int to be used for the operator ~. +// TypeError 7995: (94-96): The function "gt" needs to return exactly one value of type bool to be used for the operator >. +// TypeError 7995: (107-109): The function "lt" needs to return exactly one value of type bool to be used for the operator <. +// TypeError 3841: (571-596): User defined operator + needs to return value of type Int. +// TypeError 1208: (602-627): User defined operator / needs to return exactly one value. +// TypeError 3138: (633-645): User defined operator - needs to return exactly one value. +// TypeError 7983: (651-663): User defined operator ~ needs to return value of type Int. +// TypeError 1208: (669-694): User defined operator < needs to return exactly one value. +// TypeError 3841: (700-725): User defined operator > needs to return value of type bool.