diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java
index 5451d98720d9..09d53f29f2f5 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java
@@ -68,15 +68,17 @@ public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExp
return PyBuiltinCache.getInstance(this).getBoolType();
}
PyType callResultType = PyCallExpressionHelper.getCallType(this, context, key);
- if (callResultType != null) {
- boolean bothOperandsAreKnown = operandIsKnown(getLeftExpression(), context) && operandIsKnown(getRightExpression(), context);
- // TODO requires weak union. See PyTypeCheckerInspectionTest#testBinaryExpressionWithUnknownOperand
- return bothOperandsAreKnown ? callResultType : PyUnionType.createWeakType(callResultType);
+ if (callResultType == null) {
+ if (referencedName != null && PyNames.COMPARISON_OPERATORS.contains(referencedName)) {
+ // we don't know if it was explicit or not, so we form an unsafe union of Any and bool
+ // TODO: when { explicit Any -> Any, Unknown -> UnsafeUnion[bool | Any] }
+ return PyUnsafeUnionType.unsafeUnion(null, PyBuiltinCache.getInstance(this).getBoolType());
+ }
+ return null;
}
- if (referencedName != null && PyNames.COMPARISON_OPERATORS.contains(referencedName)) {
- return PyBuiltinCache.getInstance(this).getBoolType();
- }
- return null;
+ boolean bothOperandsAreKnown = operandIsKnown(getLeftExpression(), context) && operandIsKnown(getRightExpression(), context);
+ // TODO requires weak union. See PyTypeCheckerInspectionTest#testBinaryExpressionWithUnknownOperand
+ return bothOperandsAreKnown ? callResultType : PyUnionType.createWeakType(callResultType);
}
private static boolean operandIsKnown(@Nullable PyExpression operand, @NotNull TypeEvalContext context) {
diff --git a/python/testData/inspections/PyTypeCheckerInspection/ComparisonOperators.py b/python/testData/inspections/PyTypeCheckerInspection/ComparisonOperators.py
index 3b745411b446..0f9b83515070 100644
--- a/python/testData/inspections/PyTypeCheckerInspection/ComparisonOperators.py
+++ b/python/testData/inspections/PyTypeCheckerInspection/ComparisonOperators.py
@@ -11,7 +11,7 @@ def test():
c = C()
f(1 < 2)
f(o == o)
- f(o >= o)
+ f(o >= o)
f('foo' > 'bar')
f(c < 1)
f(c > 1)
diff --git a/python/testSrc/com/jetbrains/python/Py3TypeTest.java b/python/testSrc/com/jetbrains/python/Py3TypeTest.java
index b512b53957a9..696c8396a105 100644
--- a/python/testSrc/com/jetbrains/python/Py3TypeTest.java
+++ b/python/testSrc/com/jetbrains/python/Py3TypeTest.java
@@ -1,6 +1,7 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python;
+import com.intellij.idea.TestFor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.fixtures.PyTestCase;
@@ -3975,6 +3976,20 @@ public class Py3TypeTest extends PyTestCase {
""");
}
+ @TestFor(issues="PY-81651")
+ public void testEqWithAny() {
+ // the actual result is `Any`, but we don't have the technology yet
+ doTest("UnsafeUnion[Any, bool]", """
+ from typing import Any
+
+ class A:
+ def __eq__(self, other) -> Any:
+ return "hello :)"
+
+ expr = A() == 1
+ """);
+ }
+
private void doTest(final String expectedType, final String text) {
myFixture.configureByText(PythonFileType.INSTANCE, text);
final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);