class Steep::TypeInference::SendArgs::PositionalArgs

def consume(n, node:)

def consume(n, node:)
  # @type var ps: Array[Interface::Function::Params::PositionalParams::param]
  ps = []
  params = consume0(n, node: node, params: positional_params, ps: ps)
  case params
  when UnexpectedArg
    [
      params,
      update(index: index+1, positional_params: nil)
    ]
  else
    [ps, update(index: index+1, positional_params: params)]
  end
end

def consume0(n, node:, params:, ps:)

def consume0(n, node:, params:, ps:)
  case n
  when 0
    params
  else
    head = params&.head
    case head
    when nil
      UnexpectedArg.new(node: node)
    when Interface::Function::Params::PositionalParams::Required, Interface::Function::Params::PositionalParams::Optional
      ps << head
      consume0(n-1, node: node, params: params&.tail, ps: ps)
    when Interface::Function::Params::PositionalParams::Rest
      ps << head
      consume0(n-1, node: node, params: params, ps: ps)
    end
  end
end

def following_args

def following_args
  args[index..] or raise
end

def initialize(args:, index:, positional_params:, uniform: false)

def initialize(args:, index:, positional_params:, uniform: false)
  @args = args
  @index = index
  @positional_params = positional_params
  @uniform = uniform
end

def next()

def next()
  case
  when node && node.type == :forwarded_args
    # If the node is a `:forwarded_args`, abort
    nil
  when !node && param.is_a?(Interface::Function::Params::PositionalParams::Required)
    [
      MissingArg.new(params: positional_params),
      update(index: index, positional_params: nil)
    ]
  when !node && param.is_a?(Interface::Function::Params::PositionalParams::Optional)
    nil
  when !node && param.is_a?(Interface::Function::Params::PositionalParams::Rest)
    nil
  when !node && !param
    nil
  when node && node.type != :splat && param.is_a?(Interface::Function::Params::PositionalParams::Required)
    [
      NodeParamPair.new(node: node, param: param),
      update(index: index+1, positional_params: positional_params&.tail)
    ]
  when node && node.type != :splat && param.is_a?(Interface::Function::Params::PositionalParams::Optional)
    [
      NodeParamPair.new(node: node, param: param),
      update(index: index+1, positional_params: positional_params&.tail)
    ]
  when node && node.type != :splat && param.is_a?(Interface::Function::Params::PositionalParams::Rest)
    [
      NodeParamPair.new(node: node, param: param),
      update(index: index+1)
    ]
  when node && node.type != :splat && !param
    [
      UnexpectedArg.new(node: node),
      update(index: index + 1)
    ]
  when node && node.type == :splat
    [
      SplatArg.new(node: node),
      self
    ]
  end
end

def node

def node
  args[index]
end

def param

def param
  positional_params&.head
end

def uniform_type

def uniform_type
  return nil unless positional_params
  if positional_params.each.any? {|param| param.is_a?(Interface::Function::Params::PositionalParams::Rest) }
    AST::Types::Intersection.build(types: positional_params.each.map(&:type))
  end
end

def update(index: self.index, positional_params: self.positional_params, uniform: self.uniform)

def update(index: self.index, positional_params: self.positional_params, uniform: self.uniform)
  PositionalArgs.new(args: args, index: index, positional_params: positional_params, uniform: uniform)
end