diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 25bd4a915197..36f26e49d5d7 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1632,10 +1632,13 @@ bool TypeChecker::visit(UnaryOperation const& _operation) resultType = builtinResult; else if (!matchingDefinitions.empty()) { - // This is checked along with `using for` directive but the error is not fatal. - if (matchingDefinitions.size() != 1) - solAssert(m_errorReporter.hasErrors()); - + // Duplicate user-defined operator bindings are flagged later by + // endVisit(UsingForDirective) (error 4705). When a function body that + // uses the operator is type-checked before the directive is fully + // processed (e.g. for self-referential `using for` definitions), no + // error has been emitted yet and the previous solAssert(hasErrors()) + // triggered an ICE. Pick the first match and let the directive's own + // duplicate check surface the error. operatorDefinition = *matchingDefinitions.begin(); } else @@ -1697,10 +1700,13 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) commonType = builtinResult.get(); else if (!matchingDefinitions.empty()) { - // This is checked along with `using for` directive but the error is not fatal. - if (matchingDefinitions.size() != 1) - solAssert(m_errorReporter.hasErrors()); - + // Duplicate user-defined operator bindings are flagged later by + // endVisit(UsingForDirective) (error 4705). When a function body that + // uses the operator is type-checked before the directive is fully + // processed (e.g. for self-referential `using for` definitions), no + // error has been emitted yet and the previous solAssert(hasErrors()) + // triggered an ICE. Pick the first match and let the directive's own + // duplicate check surface the error. operatorDefinition = *matchingDefinitions.begin(); // Set common type to the type used in the `using for` directive. diff --git a/test/libsolidity/syntaxTests/operators/userDefined/duplicate_binary_operator_self_referential.sol b/test/libsolidity/syntaxTests/operators/userDefined/duplicate_binary_operator_self_referential.sol new file mode 100644 index 000000000000..c9b71266f712 --- /dev/null +++ b/test/libsolidity/syntaxTests/operators/userDefined/duplicate_binary_operator_self_referential.sol @@ -0,0 +1,11 @@ +// Used to cause ICE in TypeChecker::endVisit(BinaryOperation) when a +// function body referenced an operator that had multiple matching +// `using for` definitions before the directive's own duplicate check +// (error 4705) had a chance to run. +type T is int256; +function sub(T a, T b) pure returns (T) {} +function add(T a, T b) pure returns (T) { T c = a + b; c; } +using {sub as +, add as +} for T global; +// ---- +// TypeError 4705: (267-270): User-defined binary operator + has more than one definition matching the operand type visible in the current scope. +// TypeError 4705: (277-280): User-defined binary operator + has more than one definition matching the operand type visible in the current scope. diff --git a/test/libsolidity/syntaxTests/operators/userDefined/duplicate_unary_operator_self_referential.sol b/test/libsolidity/syntaxTests/operators/userDefined/duplicate_unary_operator_self_referential.sol new file mode 100644 index 000000000000..536d50b15542 --- /dev/null +++ b/test/libsolidity/syntaxTests/operators/userDefined/duplicate_unary_operator_self_referential.sol @@ -0,0 +1,11 @@ +// Used to cause ICE in TypeChecker::visit(UnaryOperation) when a function +// body referenced an operator that had multiple matching `using for` +// definitions before the directive's own duplicate check (error 4705) +// had a chance to run. +type T is int256; +function neg1(T a) pure returns (T) { return -a; } +function neg2(T a) pure returns (T) { return a; } +using {neg1 as -, neg2 as -} for T global; +// ---- +// TypeError 4705: (262-266): User-defined unary operator - has more than one definition matching the operand type visible in the current scope. +// TypeError 4705: (273-277): User-defined unary operator - has more than one definition matching the operand type visible in the current scope.