boolean (PsiType type1, PsiType type2, int level) { if (type1 instanceof PsiWildcardType) { if (type2 instanceof PsiWildcardType) { return provablyDistinct((PsiWildcardType)type1, (PsiWildcardType)type2, true, level); } if (level > 1) return true; if (type2 instanceof PsiCapturedWildcardType) { return provablyDistinct((PsiWildcardType)type1, ((PsiCapturedWildcardType)type2).getWildcard(), false, level); } if (type2 instanceof PsiClassType) { final PsiClass psiClass2 = PsiUtil.resolveClassInType(type2); if (psiClass2 == null) return false; if (((PsiWildcardType)type1).isExtends()) { final PsiType extendsBound = ((PsiWildcardType)type1).getExtendsBound(); if (extendsBound instanceof PsiArrayType && proveArrayTypeDistinct((PsiArrayType)extendsBound, type2)) return true; final PsiClass boundClass1 = PsiUtil.resolveClassInType(extendsBound); if (boundClass1 == null) return false; if (CommonClassNames.JAVA_LANG_OBJECT.equals(psiClass2.getQualifiedName()) && !(boundClass1 instanceof PsiTypeParameter)) { return !CommonClassNames.JAVA_LANG_OBJECT.equals(boundClass1.getQualifiedName()); } return proveExtendsBoundsDistinct(type1, type2, boundClass1, psiClass2); } if (((PsiWildcardType)type1).isSuper()) { final PsiType superBound = ((PsiWildcardType)type1).getSuperBound(); if (superBound instanceof PsiArrayType && proveArrayTypeDistinct((PsiArrayType)superBound, type2)) return true; final PsiClass boundClass1 = PsiUtil.resolveClassInType(superBound); if (boundClass1 == null) return false; if (boundClass1 instanceof PsiTypeParameter) { final PsiClassType[] extendsListTypes = boundClass1.getExtendsListTypes(); for (PsiClassType classType : extendsListTypes) { final PsiClass psiClass = classType.resolve(); if (InheritanceUtil.isInheritorOrSelf(psiClass, psiClass2, true) || InheritanceUtil.isInheritorOrSelf(psiClass2, psiClass, true)) return false; } return extendsListTypes.length > 0; } return !InheritanceUtil.isInheritorOrSelf(boundClass1, psiClass2, true); } final PsiType bound = ((PsiWildcardType)type1).getBound(); return bound != null && !bound.equals(type2); } if (type2 instanceof PsiArrayType) { return proveArrayTypeDistinct((PsiArrayType)type2, type1); } } else { if (type2 instanceof PsiWildcardType) return provablyDistinct(type2, type1, level); if (type1 instanceof PsiCapturedWildcardType) return provablyDistinct(((PsiCapturedWildcardType)type1).getWildcard(), type2, level); if (type2 instanceof PsiCapturedWildcardType) return provablyDistinct(type2, type1, level); } final PsiClassType.ClassResolveResult classResolveResult1 = PsiUtil.resolveGenericsClassInType(type1); final PsiClassType.ClassResolveResult classResolveResult2 = PsiUtil.resolveGenericsClassInType(type2); final PsiClass boundClass1 = classResolveResult1.getElement(); final PsiClass boundClass2 = classResolveResult2.getElement(); if (boundClass1 instanceof PsiTypeParameter && level < 2) { if (!distinguishFromTypeParam((PsiTypeParameter)boundClass1, type1, type2)) return false; } if (boundClass2 instanceof PsiTypeParameter && level < 2) { if (!distinguishFromTypeParam((PsiTypeParameter)boundClass2, type2, type1)) return false; } if (Comparing.equal(TypeConversionUtil.erasure(type1), TypeConversionUtil.erasure(type2)) && !(boundClass1 instanceof PsiTypeParameter) && !(boundClass2 instanceof PsiTypeParameter)) { final PsiSubstitutor substitutor1 = classResolveResult1.getSubstitutor(); final PsiSubstitutor substitutor2 = classResolveResult2.getSubstitutor(); for (PsiTypeParameter parameter : substitutor1.getSubstitutionMap().keySet()) { final PsiType substitutedType1 = substitutor1.substitute(parameter); final PsiType substitutedType2 = substitutor2.substitute(parameter); if (substitutedType1 == null && substitutedType2 == null){ continue; } if (substitutedType1 == null) { if (type2 instanceof PsiClassType && ((PsiClassType)type2).hasParameters()) return true; } else if (substitutedType2 == null) { if (type1 instanceof PsiClassType && ((PsiClassType)type1).hasParameters()) return true; } else { if (provablyDistinct(substitutedType1, substitutedType2, level + 1)) return true; } } if (level < 2) return false; } if (boundClass1 == null || boundClass2 == null) { return type1 != null && type2 != null && !type1.equals(type2); } return type2 != null && type1 != null && !type1.equals(type2) && !(level == 0 && boundClass1.isInterface() && boundClass2.isInterface()) && (!InheritanceUtil.isInheritorOrSelf(boundClass1, boundClass2, true) || !InheritanceUtil.isInheritorOrSelf(boundClass2, boundClass1, true)); }