class Steep::Interface::Function::Params::PositionalParams

def self.build(required:, optional:, rest:)

def self.build(required:, optional:, rest:)
  params = rest ? self.rest(rest) : nil
  params = optional.reverse_each.inject(params) {|params, type| self.optional(type, params) }
  params = required.reverse_each.inject(params) {|params, type| self.required(type, params) }
  params
end

def self.merge_for_intersection(xs, ys)


Raises when failed.
Calculates xs & ys.
def self.merge_for_intersection(xs, ys)
  x = xs&.head
  y = ys&.head
  case
  when x.is_a?(Required) && y.is_a?(Required)
    xs or raise
    ys or raise
    required(
      intersection(x.type, y.type),
      merge_for_intersection(xs.tail, ys.tail)
    )
  when x.is_a?(Required) && !y
    raise
  when x.is_a?(Required) && y.is_a?(Optional)
    xs or raise
    ys or raise
    required(
      intersection(x.type, y.type),
      merge_for_intersection(xs.tail, ys.tail)
    )
  when x.is_a?(Required) && y.is_a?(Rest)
    xs or raise
    ys or raise
    required(
      intersection(x.type, y.type),
      merge_for_intersection(xs.tail, ys)
    )
  when !x && y.is_a?(Required)
    raise
  when !x && !y
    nil
  when !x && y.is_a?(Optional)
    nil
  when !x && y.is_a?(Rest)
    nil
  when x.is_a?(Optional) && y.is_a?(Required)
    xs or raise
    ys or raise
    required(
      intersection(x.type, y.type),
      merge_for_intersection(xs.tail, ys.tail)
    )
  when x.is_a?(Optional) && !y
    nil
  when x.is_a?(Optional) && y.is_a?(Optional)
    xs or raise
    ys or raise
    optional(
      intersection(x.type, y.type),
      merge_for_intersection(xs.tail, ys.tail)
    )
  when x.is_a?(Optional) && y.is_a?(Rest)
    xs or raise
    ys or raise
    optional(
      intersection(x.type, y.type),
      merge_for_intersection(xs.tail, ys)
    )
  when x.is_a?(Rest) && y.is_a?(Required)
    xs or raise
    ys or raise
    required(
      intersection(x.type, y.type),
      merge_for_intersection(xs, ys.tail)
    )
  when x.is_a?(Rest) && !y
    nil
  when x.is_a?(Rest) && y.is_a?(Optional)
    xs or raise
    ys or raise
    optional(
      intersection(x.type, y.type),
      merge_for_intersection(xs, ys.tail)
    )
  when x.is_a?(Rest) && y.is_a?(Rest)
    rest(intersection(x.type, y.type))
  end
end

def self.merge_for_overload(xs, ys)

Never fails.
Calculates xs + ys.
def self.merge_for_overload(xs, ys)
  x = xs&.head
  y = ys&.head
  case
  when x.is_a?(Required) && y.is_a?(Required)
    xs or raise
    ys or raise
    required(
      union(x.type, y.type),
      merge_for_overload(xs.tail, ys.tail)
    )
  when x.is_a?(Required) && y.is_a?(Optional)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type, null: true),
      merge_for_overload(xs.tail, ys.tail)
    )
  when x.is_a?(Required) && y.is_a?(Rest)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type, null: true),
      merge_for_overload(xs.tail, ys)
    )
  when x.is_a?(Required) && !y
    xs or raise
    optional(
      union(x.type, null: true),
      merge_for_overload(xs.tail, nil)
    )
  when x.is_a?(Optional) && y.is_a?(Required)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type, null: true),
      merge_for_overload(xs.tail, ys.tail)
    )
  when x.is_a?(Optional) && y.is_a?(Optional)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type),
      merge_for_overload(xs.tail, ys.tail)
    )
  when x.is_a?(Optional) && y.is_a?(Rest)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type),
      merge_for_overload(xs.tail, ys)
    )
  when x.is_a?(Optional) && !y
    xs or raise
    optional(
      x.type,
      merge_for_overload(xs.tail, nil)
    )  # == xs
  when x.is_a?(Rest) && y.is_a?(Required)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type, null: true),
      merge_for_overload(xs, ys.tail)
    )
  when x.is_a?(Rest) && y.is_a?(Optional)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type),
      merge_for_overload(xs, ys.tail)
    )
  when x.is_a?(Rest) && y.is_a?(Rest)
    xs or raise
    ys or raise
    rest(union(x.type, y.type))
  when x.is_a?(Rest) && !y
    xs or raise
  when !x && y.is_a?(Required)
    ys or raise
    optional(
      union(y.type, null: true),
      merge_for_overload(nil, ys.tail)
    )
  when !x && y.is_a?(Optional)
    ys or raise
    optional(
      y.type,
      merge_for_overload(nil, ys.tail)
    )  # == ys
  when !x && y.is_a?(Rest)
    ys or raise
  when !x && !y
    nil
  end
end

def self.merge_for_union(xs, ys)

xs | ys
def self.merge_for_union(xs, ys)
  x = xs&.head
  y = ys&.head
  case
  when x.is_a?(Required) && y.is_a?(Required)
    xs or raise
    ys or raise
    required(
      union(x.type, y.type),
      merge_for_union(xs.tail, ys.tail)
    )
  when x.is_a?(Required) && !y
    xs or raise
    optional(
      x.type,
      merge_for_union(xs.tail, nil)
    )
  when x.is_a?(Required) && y.is_a?(Optional)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type),
      merge_for_union(xs.tail, ys.tail)
    )
  when x.is_a?(Required) && y.is_a?(Rest)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type),
      merge_for_union(xs.tail, ys)
    )
  when !x && y.is_a?(Required)
    ys or raise
    optional(
      y.type,
      merge_for_union(nil, ys.tail)
    )
  when !x && !y
    nil
  when !x && y.is_a?(Optional)
    ys or raise
    PositionalParams.new(head: y, tail: merge_for_union(nil, ys.tail))
  when !x && y.is_a?(Rest)
    ys or raise
  when x.is_a?(Optional) && y.is_a?(Required)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type),
      merge_for_union(xs.tail, ys.tail)
    )
  when x.is_a?(Optional) && !y
    xs or raise
    PositionalParams.new(head: x, tail: merge_for_union(xs.tail, nil)) # == xs
  when x.is_a?(Optional) && y.is_a?(Optional)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type),
      merge_for_union(xs.tail, ys.tail)
    )
  when x.is_a?(Optional) && y.is_a?(Rest)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type),
      merge_for_union(xs.tail, ys.tail)
    )
  when x.is_a?(Rest) && y.is_a?(Required)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type),
      merge_for_union(xs, ys.tail)
    )
  when x.is_a?(Rest) && !y
    xs or raise
  when x.is_a?(Rest) && y.is_a?(Optional)
    xs or raise
    ys or raise
    optional(
      union(x.type, y.type),
      merge_for_union(xs, ys.tail)
    )
  when x.is_a?(Rest) && y.is_a?(Rest)
    xs or raise
    ys or raise
    rest(
      union(x.type, y.type)
    )
  end
end

def self.optional(type, tail = nil)

def self.optional(type, tail = nil)
  PositionalParams.new(head: Optional.new(type), tail: tail)
end

def self.required(type, tail = nil)

def self.required(type, tail = nil)
  PositionalParams.new(head: Required.new(type), tail: tail)
end

def self.rest(type, tail = nil)

def self.rest(type, tail = nil)
  PositionalParams.new(head: Rest.new(type), tail: tail)
end

def ==(other)

def ==(other)
  other.is_a?(PositionalParams) && other.head == head && other.tail == tail
end

def each(&block)

def each(&block)
  if block
    yield head
    tail&.each(&block)
  else
    enum_for(:each)
  end
end

def each_type

def each_type
  if block_given?
    each do |param|
      yield param.type
    end
  else
    enum_for :each_type
  end
end

def hash

def hash
  self.class.hash ^ head.hash ^ tail.hash
end

def initialize(head:, tail:)

def initialize(head:, tail:)
  @head = head
  @tail = tail
end

def map(&block)

def map(&block)
  hd = yield(head)
  tl = tail&.map(&block)
  if head == hd && tail == tl
    self
  else
    PositionalParams.new(head: hd, tail: tl)
  end
end

def map_type(&block)

def map_type(&block)
  if block
    map {|param| param.map_type(&block) }
  else
    enum_for :map_type
  end
end

def size

def size
  1 + (tail&.size || 0)
end

def subst(s)

def subst(s)
  map_type do |type|
    ty = type.subst(s)
    if ty == type
      type
    else
      ty
    end
  end
end

def to_ary

def to_ary
  [head, tail]
end