module T::Private::Methods::CallValidation

def self.validate_call(instance, original_method, method_sig, args, blk)

def self.validate_call(instance, original_method, method_sig, args, blk)
  # This method is called for every `sig`. It's critical to keep it fast and
  # reduce number of allocations that happen here.
  if method_sig.ever_failed && method_sig.generated
    return original_method.bind(instance).call(*args, &blk)
  end
  T::Profile.typecheck_sample_attempts -= 1
  should_sample = T::Profile.typecheck_sample_attempts == 0
  if should_sample
    T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
    T::Profile.typecheck_samples += 1
    t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  end
  if method_sig.bind
    message = method_sig.bind.error_message_for_obj(instance)
    if message
      CallValidation.report_error(
        method_sig,
        message,
        'Bind',
        nil,
        method_sig.bind,
        instance
      )
    end
  end
  # NOTE: We don't bother validating for missing or extra kwargs;
  # the method call itself will take care of that.
  method_sig.each_args_value_type(args) do |name, arg, type|
    message = type.error_message_for_obj(arg)
    if message
      CallValidation.report_error(
        method_sig,
        message,
        'Parameter',
        name,
        type,
        arg,
        caller_offset: 2
      )
    end
  end
  if method_sig.block_type
    message = method_sig.block_type.error_message_for_obj(blk)
    if message
      CallValidation.report_error(
        method_sig,
        message,
        'Block parameter',
        method_sig.block_name,
        method_sig.block_type,
        blk
      )
    end
  end
  if should_sample
    T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
  end
  # The following line breaks are intentional to show nice pry message
  # PRY note:
  # this code is sig validation code.
  # Please issue `finish` to step out of it
  return_value = original_method.bind(instance).call(*args, &blk)
  if should_sample
    t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  end
  # The only type that is allowed to change the return value is `.void`.
  # It ignores what you returned and changes it to be a private singleton.
  if method_sig.return_type.is_a?(T::Private::Types::Void)
    T::Private::Types::Void::VOID
  else
    message = method_sig.return_type.error_message_for_obj(return_value)
    if message
      CallValidation.report_error(
        method_sig,
        message,
        'Return value',
        nil,
        method_sig.return_type,
        return_value,
      )
    end
    if should_sample
      T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
    end
    return_value
  end
end