class TypedRb::Types::TyEither

Attributes

options[RW]

Public Class Methods

new(node=nil) click to toggle source
Calls superclass method
# File lib/typed/types/ty_either.rb, line 5
def initialize(node=nil)
  super(NilClass, node)
  @options = { :normal => TypedRb::Types::TyUnit.new }
end
wrap(type) click to toggle source
# File lib/typed/types/ty_either.rb, line 10
def self.wrap(type)
  if type.either?
    type
  elsif type.stack_jump?
    either = TyEither.new(type.node)
    either[type.jump_kind] = type
    either
  else
    either = TyEither.new(type.node)
    either[:normal] = type
    either
  end
end

Public Instance Methods

[](kind) click to toggle source
# File lib/typed/types/ty_either.rb, line 64
def [](kind)
  valid_kind?(kind)
  options[kind]
end
[]=(kind, value) click to toggle source
# File lib/typed/types/ty_either.rb, line 69
def []=(kind, value)
  valid_kind?(kind)
  options[kind] = value
end
all_kinds() click to toggle source
# File lib/typed/types/ty_either.rb, line 60
def all_kinds
  [:normal] + kinds
end
apply_bindings(bindings_map) click to toggle source
# File lib/typed/types/ty_either.rb, line 106
def apply_bindings(bindings_map)
  all_kinds.each do |kind|
    if self[kind]
      if self[kind].is_a?(Polymorphism::TypeVariable)
        self[kind].apply_bindings(bindings_map)
        self[kind] = self[kind].bound if self[kind].bound
      elsif self[kind].is_a?(TyGenericSingletonObject) || self[kind].is_a?(TyGenericObject)
        self[kind].apply_bindings(bindings_map)
      end
    end
  end
  self
end
break?() click to toggle source
# File lib/typed/types/ty_either.rb, line 44
def break?
  !options[:break].nil? && options[:break].break?
end
check_type(context, types=[:return]) click to toggle source
# File lib/typed/types/ty_either.rb, line 74
def check_type(context, types=[:return])
  relevant_types = types.map { |type| self[type] }.reject(&:nil?)
  relevant_types = relevant_types.map { |type| type.stack_jump? ? type.wrapped_type : type }
  relevant_types = relevant_types.map { |type| type.check_type(context) }
  relevant_types.max rescue relevant_types.reduce { |type_a, type_b| type_a.union(type_b) }
end
compatible?(other_type, relation = :lt) click to toggle source

This compatible function is to use the normal wrapped type in regular comparisons

# File lib/typed/types/ty_either.rb, line 82
def compatible?(other_type, relation = :lt)
  (options[:normal] || TyUnit.new(node)).compatible?(other_type, relation)
end
compatible_either?(other_type) click to toggle source

This compatible function is to build the comparison in conditional terms

# File lib/typed/types/ty_either.rb, line 87
def compatible_either?(other_type)
  if other_type.either? # either vs either
    kinds.each do |kind|
      check_jump_kind(kind, other_type[kind])
    end
    check_normal_kind(other_type[:normal])
  elsif other_type.stack_jump? # either vs jump
    check_jump_kind(other_type.jump_kind, other_type)
  else # either vs normal flow
    check_normal_kind(other_type)
  end
  self
end
either?() click to toggle source
# File lib/typed/types/ty_either.rb, line 36
def either?
  true
end
has_jump?() click to toggle source
# File lib/typed/types/ty_either.rb, line 52
def has_jump?
  !(options[:return] || options[:next] || options[:break]).nil?
end
kinds() click to toggle source
# File lib/typed/types/ty_either.rb, line 56
def kinds
  [:return, :next, :break]
end
next?() click to toggle source
# File lib/typed/types/ty_either.rb, line 48
def next?
  !options[:next].nil? && options[:next].next?
end
return?() click to toggle source
# File lib/typed/types/ty_either.rb, line 40
def return?
  !options[:return].nil? && options[:return].return?
end
to_s() click to toggle source
# File lib/typed/types/ty_either.rb, line 101
def to_s
  vals = options.to_a.reject {|(k,v)| v.nil? }.map{ |k,v| "#{k}:#{v}" }.join(" | ")
  "Either[#{vals}]"
end
unwrap() click to toggle source
# File lib/typed/types/ty_either.rb, line 24
def unwrap
  normal = self[:normal].is_a?(TypedRb::Types::TyUnit) ? nil : self[:normal]
  wrapped_types = [normal, self[:return], self[:break], self[:next]].compact
  if wrapped_types.count > 1
    self
  elsif wrapped_types.count == 1
    wrapped_types.first
  else
    TypedRb::Types::TyUnit.new
  end
end

Private Instance Methods

check_jump_kind(kind, other_type) click to toggle source
# File lib/typed/types/ty_either.rb, line 122
def check_jump_kind(kind, other_type)
  if self[kind].nil? && other_type
    self[kind] = other_type
  elsif self[kind] && other_type
    max_type = max(self[kind].wrapped_type, other_type.wrapped_type)
    self[kind] = TyStackJump.new(kind, max_type)
  end
end
check_normal_kind(other_type) click to toggle source
# File lib/typed/types/ty_either.rb, line 131
def check_normal_kind(other_type)
  self[:normal] = max(self[:normal], other_type)
end
max(type_a, type_b) click to toggle source
# File lib/typed/types/ty_either.rb, line 135
def max(type_a, type_b)
  return (type_a || type_b) if type_a.nil? || type_b.nil?
  return type_b if type_a.is_a?(Types::TyDynamic) || type_a.is_a?(Types::TyDynamicFunction)
  return type_a if type_b.is_a?(Types::TyDynamic) || type_b.is_a?(Types::TyDynamicFunction)
  return type_b if type_a.is_a?(Types::TyError)
  return type_a if type_b.is_a?(Types::TyError)

  type_vars = [type_a, type_b].select { |type| type.is_a?(Polymorphism::TypeVariable) }
  if type_vars.count == 2
    type_vars[0].compatible?(type_vars[1], :lt)
    type_vars[1].compatible?(type_vars[0], :lt)
    type_vars[0]
  elsif type_vars.count == 1
    type_var = type_vars.first
    non_type_var = ([type_a, type_b] - type_vars).first
    type_var.compatible?(non_type_var, :gt)
    type_var
  else
    begin
      [type_a, type_b].max
    rescue Exception => ex
      type_a.union(type_b)
    end
  end
end
valid_kind?(kind) click to toggle source
# File lib/typed/types/ty_either.rb, line 161
def valid_kind?(kind)
  unless kind == :normal || kinds.include?(kind)
    fail Exception, "Invalid kind of either type #{kind}"
  end
end