int (final Binding binding) { final BindingImpl b2 = (BindingImpl)binding; final BindingImpl b1 = this; int directoin = Binding.NONCOMPARABLE; boolean first = true; for (PsiTypeVariable boundVariable : myBoundVariables) { final int index = boundVariable.getIndex(); final PsiType x = normalize(b1.myBindings.get(index)); final PsiType y = normalize(b2.myBindings.get(index)); final int comp = new Object() { int compare(final PsiType x, final PsiType y) { final int[] kinds = new Object() { private static int classify(final PsiType type) { if (type == null) { return 0; } if (type instanceof PsiPrimitiveType) { return 1; } if (type instanceof PsiArrayType) { return 2; } if (type instanceof PsiClassType) { return 3; } return 4; // Bottom } int[] classify2(final PsiType x, final PsiType y) { return new int[]{classify(x), classify(y)}; } }.classify2(x, y); final int kindX = kinds[0]; final int kindY = kinds[1]; // Break your brain here... if (kindX + kindY == 0) { return Binding.SAME; } if (kindX * kindY == 0) { if (kindX == 0) { return Binding.WORSE; } return Binding.BETTER; } if (kindX * kindY == 1) { if (x.equals(y)) { return Binding.SAME; } return Binding.NONCOMPARABLE; } if (kindX != kindY) { if (kindX == 4) { return Binding.WORSE; } if (kindY == 4) { return Binding.BETTER; } if (kindX + kindY == 5) { try { final PsiElementFactory f = JavaPsiFacade.getElementFactory(myProject); final PsiType cloneable = f.createTypeFromText("java.lang.Cloneable", null); final PsiType object = f.createTypeFromText(CommonClassNames.JAVA_LANG_OBJECT, null); final PsiType serializable = f.createTypeFromText("java.io.Serializable", null); PsiType type; int flag; if (kindX == 3) { type = x; flag = Binding.WORSE; } else { type = y; flag = Binding.BETTER; } if (type.equals(object) || type.equals(cloneable) || type.equals(serializable)) { return flag; } } catch (IncorrectOperationException e) { LOG.error(e); } } return Binding.NONCOMPARABLE; } if (kindX == 2) { return compare(((PsiArrayType)x).getComponentType(), ((PsiArrayType)y).getComponentType()); } if (x.equals(y)) { return Binding.SAME; } // End of breaking... final PsiClassType.ClassResolveResult resultX = Util.resolveType(x); final PsiClassType.ClassResolveResult resultY = Util.resolveType(y); final PsiClass xClass = resultX.getElement(); final PsiClass yClass = resultY.getElement(); final PsiSubstitutor xSubst = resultX.getSubstitutor(); final PsiSubstitutor ySubst = resultY.getSubstitutor(); if (xClass == null || yClass == null) { return Binding.NONCOMPARABLE; } if (xClass.equals(yClass)) { boolean first = true; int direction = Binding.SAME; for (final PsiTypeParameter p : xSubst.getSubstitutionMap().keySet()) { final PsiType xParm = xSubst.substitute(p); final PsiType yParm = ySubst.substitute(p); final int comp = compare(xParm, yParm); if (comp == Binding.NONCOMPARABLE) { return Binding.NONCOMPARABLE; } if (first) { first = false; direction = comp; } if (direction != comp) { return Binding.NONCOMPARABLE; } } return direction; } else { if (InheritanceUtil.isInheritorOrSelf(xClass, yClass, true)) { return Binding.BETTER; } else if (InheritanceUtil.isInheritorOrSelf(yClass, xClass, true)) { return Binding.WORSE; } return Binding.NONCOMPARABLE; } } }.compare(x, y); if (comp == Binding.NONCOMPARABLE) { return Binding.NONCOMPARABLE; } if (first) { first = false; directoin = comp; } if (directoin != SAME) { if (comp != Binding.SAME && directoin != comp) { return Binding.NONCOMPARABLE; } } else if (comp != SAME) { directoin = comp; } } return directoin; }