From 8307b670cb81128b85fb9c65e2248f08439a3405 Mon Sep 17 00:00:00 2001 From: wechman Date: Tue, 12 Jul 2022 12:23:41 +0200 Subject: [PATCH] Handle not unique operators for user-defined type. --- libsolidity/analysis/TypeChecker.cpp | 23 ++++++++++--------- libsolidity/ast/Types.cpp | 8 +++---- libsolidity/ast/Types.h | 3 ++- .../two_functions_bound_to_operator.sol | 17 ++++++++++++++ 4 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 test/libsolidity/syntaxTests/operators/custom/two_functions_bound_to_operator.sol diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 31a4d9871..3035c136d 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1790,18 +1790,18 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) _operation.annotation().isConstant = false; // Check if the operator is built-in or user-defined. - FunctionDefinition const* userDefinedOperator = leftType->userDefinedOperator( + FunctionDefinitionResult userDefinedOperatorResult = leftType->userDefinedOperator( _operation.getOperator(), *currentDefinitionScope(), false // _unaryOperation ); - _operation.annotation().userDefinedFunction = userDefinedOperator; + _operation.annotation().userDefinedFunction = userDefinedOperatorResult; FunctionType const* userDefinedFunctionType = nullptr; - if (userDefinedOperator) + if (userDefinedOperatorResult) userDefinedFunctionType = &dynamic_cast( - userDefinedOperator->libraryFunction() ? - *userDefinedOperator->typeViaContractName() : - *userDefinedOperator->type() + userDefinedOperatorResult.get()->libraryFunction() ? + *userDefinedOperatorResult.get()->typeViaContractName() : + *userDefinedOperatorResult.get()->type() ); _operation.annotation().isPure = *_operation.leftExpression().annotation().isPure && @@ -1812,9 +1812,9 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) Type const* commonType = leftType; // Either the operator is user-defined or built-in. - solAssert(!userDefinedOperator || !builtinResult); + solAssert(!userDefinedOperatorResult || !builtinResult); - if (!builtinResult && !userDefinedOperator) + if (!builtinResult && !userDefinedOperatorResult) m_errorReporter.typeError( 2271_error, _operation.location(), @@ -1824,12 +1824,13 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) leftType->humanReadableName() + " and " + rightType->humanReadableName() + "." + - (!builtinResult.message().empty() ? " " + builtinResult.message() : "") + (!builtinResult.message().empty() ? " " + builtinResult.message() : "") + + (!userDefinedOperatorResult.message().empty() ? " " + userDefinedOperatorResult.message() : "") ); if (builtinResult) commonType = builtinResult.get(); - else if (userDefinedOperator) + else if (userDefinedOperatorResult) { solAssert( userDefinedFunctionType->parameterTypes().size() == 2 && @@ -1845,7 +1846,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) TypeProvider::boolean() : commonType; - if (userDefinedOperator) + if (userDefinedOperatorResult) solAssert( userDefinedFunctionType->returnParameterTypes().size() == 1 && *userDefinedFunctionType->returnParameterTypes().front() == *_operation.annotation().type diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index bc28d2253..3e26cedbd 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -384,9 +384,8 @@ vector usingForDirectivesForType(Type const& _type, AS } -FunctionDefinition const* Type::userDefinedOperator(Token _token, ASTNode const& _scope, bool _unaryOperation) const +FunctionDefinitionResult Type::userDefinedOperator(Token _token, ASTNode const& _scope, bool _unaryOperation) const { - // Check if it is a user-defined type. if (!typeDefinition()) return nullptr; @@ -409,11 +408,12 @@ FunctionDefinition const* Type::userDefinedOperator(Token _token, ASTNode const& seenFunctions.insert(&function); } - // TODO proper error handling. if (seenFunctions.size() == 1) return *seenFunctions.begin(); + else if (seenFunctions.size() == 0) + return FunctionDefinitionResult::err("A user-defined operator not found."); else - return nullptr; + return FunctionDefinitionResult::err("A user-defined operator not unique."); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index eec9974e0..818238b61 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -54,6 +54,7 @@ using TypePointers = std::vector; using rational = boost::rational; using TypeResult = util::Result; using BoolResult = util::Result; +using FunctionDefinitionResult = util::Result; } @@ -377,7 +378,7 @@ public: /// Clears all internally cached values (if any). virtual void clearCache() const; - FunctionDefinition const* userDefinedOperator(Token _token, ASTNode const& _scope, bool _unaryOperation) const; + FunctionDefinitionResult userDefinedOperator(Token _token, ASTNode const& _scope, bool _unaryOperation) const; private: /// @returns a member list containing all members added to this type by `using for` directives. diff --git a/test/libsolidity/syntaxTests/operators/custom/two_functions_bound_to_operator.sol b/test/libsolidity/syntaxTests/operators/custom/two_functions_bound_to_operator.sol new file mode 100644 index 000000000..959347435 --- /dev/null +++ b/test/libsolidity/syntaxTests/operators/custom/two_functions_bound_to_operator.sol @@ -0,0 +1,17 @@ +type Int is uint128; + +using {add as +, sub as +} for Int; + +function add(Int, Int) returns (Int) { + return Int.wrap(0); +} + +function sub(Int, Int) returns (Int) { + return Int.wrap(0); +} + +function test() { + Int.wrap(0) + Int.wrap(1); +} +// ---- +// TypeError 2271: (213-238): Operator + not compatible with types Int and Int. A user-defined operator not unique.