Handle not unique operators for user-defined type.

This commit is contained in:
wechman 2022-07-12 12:23:41 +02:00
parent 8272da0aea
commit 8307b670cb
4 changed files with 35 additions and 16 deletions

View File

@ -1790,18 +1790,18 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
_operation.annotation().isConstant = false; _operation.annotation().isConstant = false;
// Check if the operator is built-in or user-defined. // Check if the operator is built-in or user-defined.
FunctionDefinition const* userDefinedOperator = leftType->userDefinedOperator( FunctionDefinitionResult userDefinedOperatorResult = leftType->userDefinedOperator(
_operation.getOperator(), _operation.getOperator(),
*currentDefinitionScope(), *currentDefinitionScope(),
false // _unaryOperation false // _unaryOperation
); );
_operation.annotation().userDefinedFunction = userDefinedOperator; _operation.annotation().userDefinedFunction = userDefinedOperatorResult;
FunctionType const* userDefinedFunctionType = nullptr; FunctionType const* userDefinedFunctionType = nullptr;
if (userDefinedOperator) if (userDefinedOperatorResult)
userDefinedFunctionType = &dynamic_cast<FunctionType const&>( userDefinedFunctionType = &dynamic_cast<FunctionType const&>(
userDefinedOperator->libraryFunction() ? userDefinedOperatorResult.get()->libraryFunction() ?
*userDefinedOperator->typeViaContractName() : *userDefinedOperatorResult.get()->typeViaContractName() :
*userDefinedOperator->type() *userDefinedOperatorResult.get()->type()
); );
_operation.annotation().isPure = _operation.annotation().isPure =
*_operation.leftExpression().annotation().isPure && *_operation.leftExpression().annotation().isPure &&
@ -1812,9 +1812,9 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
Type const* commonType = leftType; Type const* commonType = leftType;
// Either the operator is user-defined or built-in. // Either the operator is user-defined or built-in.
solAssert(!userDefinedOperator || !builtinResult); solAssert(!userDefinedOperatorResult || !builtinResult);
if (!builtinResult && !userDefinedOperator) if (!builtinResult && !userDefinedOperatorResult)
m_errorReporter.typeError( m_errorReporter.typeError(
2271_error, 2271_error,
_operation.location(), _operation.location(),
@ -1824,12 +1824,13 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
leftType->humanReadableName() + leftType->humanReadableName() +
" and " + " and " +
rightType->humanReadableName() + "." + rightType->humanReadableName() + "." +
(!builtinResult.message().empty() ? " " + builtinResult.message() : "") (!builtinResult.message().empty() ? " " + builtinResult.message() : "") +
(!userDefinedOperatorResult.message().empty() ? " " + userDefinedOperatorResult.message() : "")
); );
if (builtinResult) if (builtinResult)
commonType = builtinResult.get(); commonType = builtinResult.get();
else if (userDefinedOperator) else if (userDefinedOperatorResult)
{ {
solAssert( solAssert(
userDefinedFunctionType->parameterTypes().size() == 2 && userDefinedFunctionType->parameterTypes().size() == 2 &&
@ -1845,7 +1846,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
TypeProvider::boolean() : TypeProvider::boolean() :
commonType; commonType;
if (userDefinedOperator) if (userDefinedOperatorResult)
solAssert( solAssert(
userDefinedFunctionType->returnParameterTypes().size() == 1 && userDefinedFunctionType->returnParameterTypes().size() == 1 &&
*userDefinedFunctionType->returnParameterTypes().front() == *_operation.annotation().type *userDefinedFunctionType->returnParameterTypes().front() == *_operation.annotation().type

View File

@ -384,9 +384,8 @@ vector<UsingForDirective const*> 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()) if (!typeDefinition())
return nullptr; return nullptr;
@ -409,11 +408,12 @@ FunctionDefinition const* Type::userDefinedOperator(Token _token, ASTNode const&
seenFunctions.insert(&function); seenFunctions.insert(&function);
} }
// TODO proper error handling.
if (seenFunctions.size() == 1) if (seenFunctions.size() == 1)
return *seenFunctions.begin(); return *seenFunctions.begin();
else if (seenFunctions.size() == 0)
return FunctionDefinitionResult::err("A user-defined operator not found.");
else else
return nullptr; return FunctionDefinitionResult::err("A user-defined operator not unique.");
} }

View File

@ -54,6 +54,7 @@ using TypePointers = std::vector<Type const*>;
using rational = boost::rational<bigint>; using rational = boost::rational<bigint>;
using TypeResult = util::Result<Type const*>; using TypeResult = util::Result<Type const*>;
using BoolResult = util::Result<bool>; using BoolResult = util::Result<bool>;
using FunctionDefinitionResult = util::Result<FunctionDefinition const*>;
} }
@ -377,7 +378,7 @@ public:
/// Clears all internally cached values (if any). /// Clears all internally cached values (if any).
virtual void clearCache() const; 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: private:
/// @returns a member list containing all members added to this type by `using for` directives. /// @returns a member list containing all members added to this type by `using for` directives.

View File

@ -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.