boolean (@NotNull final PsiType typeLeft, @NotNull final PsiType typeRight, final boolean allowUncheckedConversion) { if (typeLeft instanceof PsiWildcardType) { final PsiWildcardType leftWildcard = (PsiWildcardType)typeLeft; final PsiType leftBound = leftWildcard.getBound(); if (leftBound == null) return true; if (leftBound.equalsToText(JAVA_LANG_OBJECT)) { if (!leftWildcard.isSuper()) return true; if (typeRight.equalsToText(JAVA_LANG_OBJECT)) return true; } if (typeRight instanceof PsiWildcardType) { final PsiWildcardType rightWildcard = (PsiWildcardType)typeRight; PsiType bound = rightWildcard.getBound(); if (leftWildcard.isExtends() && bound != null) { return rightWildcard.isExtends() && isAssignable(leftBound, bound, allowUncheckedConversion, false); } else { //isSuper if (rightWildcard.isSuper() && bound != null) { NotNullComputable<Boolean> checkAssignable = () -> isAssignable(bound, leftBound, allowUncheckedConversion, false); final Boolean assignable = ourGuard.doPreventingRecursion(rightWildcard, true, checkAssignable); return assignable != null && assignable; } return false; } } else { if (leftWildcard.isExtends()) { return isAssignable(leftBound, typeRight, false, false); } else { // isSuper NotNullComputable<Boolean> checkAssignable = () -> isAssignable(typeRight, leftBound, false, false); final Boolean assignable = ourGuard.doPreventingRecursion(leftWildcard, true, checkAssignable); return assignable == null || assignable.booleanValue(); } } } else { return typeLeft.equals(typeRight); } }