diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 4ec0a2669c64..3925a378b010 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -301,23 +301,31 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { if (classTypes.isEmpty()) { return null; } - return Collections.max(classTypes, new Comparator() { - @Override - public int compare(@Nullable PyClassLikeType t1, @Nullable PyClassLikeType t2) { - if (t1 == t2 || t1 != null && t1.equals(t2)) { - return 0; + try { + return Collections.max(classTypes, new Comparator() { + @Override + public int compare(@Nullable PyClassLikeType t1, @Nullable PyClassLikeType t2) { + if (t1 == t2 || t1 != null && t1.equals(t2)) { + return 0; + } + else if (t2 == null || t1 != null && Sets.newHashSet(t1.getAncestorTypes(context)).contains(t2)) { + return 1; + } + else if (t1 == null || Sets.newHashSet(t2.getAncestorTypes(context)).contains(t1)) { + return -1; + } + else { + throw new NotDerivedClassTypeException(); + } } - if (t1 != null && Sets.newHashSet(t1.getAncestorTypes(context)).contains(t2)) { - return 1; - } - else if (t2 != null && Sets.newHashSet(t2.getAncestorTypes(context)).contains(t1)) { - return -1; - } - else { - return 0; - } - } - }); + }); + } + catch (NotDerivedClassTypeException ignored) { + return null; + } + } + + private static final class NotDerivedClassTypeException extends RuntimeException { } private List getAllExplicitMetaClassTypes(@NotNull TypeEvalContext context) { diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/noMostDerivedMetaClass.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/noMostDerivedMetaClass.py new file mode 100644 index 000000000000..1358b7826617 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection3K/noMostDerivedMetaClass.py @@ -0,0 +1,24 @@ +class M1(type): + def foo(cls): + pass + + +class M2(type): + def bar(cls): + pass + + +class C1(metaclass=M1): + pass + + +class C2(metaclass=M2): + pass + + +class D(C1, C2): + pass + + +print(D.foo()()) +print(D.bar()) diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java index aa34e4f15df1..42696bac3d23 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java @@ -132,4 +132,9 @@ public class Py3UnresolvedReferencesInspectionTest extends PyTestCase { public void testMostDerivedMetaClass() { doTest(); } + + // PY-17841 + public void testNoMostDerivedMetaClass() { + doTest(); + } }