class RuboCop::Cop::Lint::IncompatibleIoSelectWithFiberScheduler


io.wait_writable(timeout)
# good
IO.select([], [io], [], timeout)
# bad
io.wait_readable(timeout)
# good<br><br>IO.select(, [], [], timeout)
# bad
@example
if ‘require ’io/wait’‘ is not called.
This cop’s autocorrection is unsafe because ‘NoMethodError` occurs
@safety
It’s up to user how to handle the return value.
They are not autocorrected when assigning a return value because these types are different.
and the return value of ‘io.wait_readable` and `io.wait_writable` are `self`.
NOTE: When the method is successful the return value of `IO.select` is `[[IO]]`,
is used as an argument, there is no alternative API, so offenses are not registered.
When an array of IO objects waiting for an exception (the third argument of `IO.select`)
Checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0.

def on_send(node)

def on_send(node)
  read, write, excepts, timeout = *io_select(node)
  return if excepts && !excepts.children.empty?
  return unless scheduler_compatible?(read, write) || scheduler_compatible?(write, read)
  preferred = preferred_method(read, write, timeout)
  message = format(MSG, preferred: preferred, current: node.source)
  add_offense(node, message: message) do |corrector|
    next if node.parent&.assignment?
    corrector.replace(node, preferred)
  end
end

def preferred_method(read, write, timeout)

def preferred_method(read, write, timeout)
  timeout_argument = timeout.nil? ? '' : "(#{timeout.source})"
  if read.array_type? && read.values[0]
    "#{read.values[0].source}.wait_readable#{timeout_argument}"
  else
    "#{write.values[0].source}.wait_writable#{timeout_argument}"
  end
end

def scheduler_compatible?(io1, io2)

def scheduler_compatible?(io1, io2)
  return false unless io1&.array_type? && io1.values.size == 1
  io2&.array_type? ? io2.values.empty? : (io2.nil? || io2.nil_type?)
end