123456789_123456789_123456789_123456789_123456789_

Class: TypeProf::Type::Union

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: TypeProf::Type
Defined in: lib/typeprof/type.rb

Constant Summary

::TypeProf::Type - Inherited

Builtin, DummySubstitution

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(tys, elems) ⇒ Union

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 250

def initialize(tys, elems)
  raise unless tys.is_a?(Utils::Set)
  @types = tys # Set

  # invariant check
  local = nil
  tys.each do |ty|
    raise ty.inspect unless ty.is_a?(Type)
    local = true if ty.is_a?(Local)
  end
  raise if local && elems

  @elems = elems
  raise elems.inspect if elems && !elems.is_a?(::Hash)
end

Class Method Details

.create(tys, elems)

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 219

def self.create(tys, elems)
  if tys.size == 1 && !elems
    tys.each {|ty| return ty }
  elsif tys.size == 0
    if elems && elems.size == 1
      (container_kind, base_type), nelems = elems.first
      # container_kind = Type::Array or Type::Hash
      container_kind.new(nelems, base_type)
    else
      new(tys, elems)
    end
  else
    class_instances = []
    non_class_instances = []
    degenerated = false
    tys.each do |ty|
      if ty != Type::Instance.new(Type::Builtin[:nil]) && ty.is_a?(Type::Instance) && ty.klass.kind == :class
        class_instances << ty
        degenerated = true if ty.include_subclasses
      else
        non_class_instances << ty
      end
    end
    if (Config.current.options[:union_width_limit] >= 2 && class_instances.size >= Config.current.options[:union_width_limit]) || (degenerated && class_instances.size >= 2)
      create(Utils::Set[Instance.new_degenerate(class_instances), *non_class_instances], elems)
    else
      new(tys, elems)
    end
  end
end

Instance Attribute Details

#elems (readonly)

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 284

attr_reader :types, :elems

#types (readonly)

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 284

attr_reader :types, :elems

Instance Method Details

#consistent?(_other) ⇒ Boolean

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 385

def consistent?(_other)
  raise "should not be called"
end

#each_child(&blk)

local

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 286

def each_child(&blk) # local
  @types.each(&blk)
  raise if @elems
end

#each_child_global(&blk)

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 291

def each_child_global(&blk)
  @types.each(&blk)
  @elems&.each do |(container_kind, base_type), elems|
    yield container_kind.new(elems, base_type)
  end
end

#each_free_type_variable(&blk)

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 266

def each_free_type_variable(&blk)
  each_child_global do |ty|
    ty.each_free_type_variable(&blk)
  end
end

#globalize(env, visited, depth)

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 344

def globalize(env, visited, depth)
  return Type.any if depth <= 0
  tys = Utils::Set[]
  if @elems
    # XXX: If @elems is non nil, the Union type should global, so calling globalize against such a type should not occur.
    # However, currently, ActualArguments may contain global types for flag_args_kw_splat case.
    # This should be fixed in future in ActualArguments side. See Scratch#setup_actual_arguments.
    #raise
  end

  elems = @elems ? @elems.dup : {}
  @types.each do |ty|
    ty = ty.globalize(env, visited, depth - 1)
    case ty
    when Type::Array, Type::Hash
      key = [ty.class, ty.base_type]
      elems[key] = union_elems(elems[key], ty.elems)
    else
      tys = tys.add(ty)
    end
  end
  elems = nil if elems.empty?

  Type::Union.create(tys, elems)
end

#include_untyped?(scratch) ⇒ Boolean

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 412

def include_untyped?(scratch)
  @types.each do |ty|
    return true if ty.include_untyped?(scratch)
  end
  @elems&.each do |(container_kind, base_type), elems|
    return true if base_type.include_untyped?(scratch)
    return true if elems.include_untyped?(scratch)
  end
  false
end

#inspect

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 298

def inspect
  a = []
  a << "Type::Union{#{ @types.to_a.map {|ty| ty.inspect }.join(", ") }"
  @elems&.each do |(container_kind, base_type), elems|
    a << ", #{ container_kind.new(elems, base_type).inspect }"
  end
  a << "}"
  a.join
end

#limit_size(limit)

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 272

def limit_size(limit)
  return Type.any if limit <= 0
  tys = Utils::Set[]
  @types.each do |ty|
    tys = tys.add(ty.limit_size(limit - 1))
  end
  elems = @elems&.to_h do |key, elems|
    [key, elems.limit_size(limit - 1)]
  end
  Union.new(tys, elems)
end

#localize(env, alloc_site, depth)

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 370

def localize(env, alloc_site, depth)
  return env, Type.any if depth <= 0
  tys = @types.map do |ty|
    env, ty2 = ty.localize(env, alloc_site, depth - 1)
    ty2
  end
  @elems&.each do |(container_kind, base_type), elems|
    ty = container_kind.new(elems, base_type)
    env, ty = ty.localize(env, alloc_site, depth - 1)
    tys = tys.add(ty)
  end
  ty = Union.create(tys, nil)
  return env, ty
end

#screen_name(scratch)

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 308

def screen_name(scratch)
  types = @types.to_a
  @elems&.each do |(container_kind, base_type), elems|
    types << container_kind.new(elems, base_type)
  end
  if types.size == 0
    "bot"
  else
    types = types.to_a
    optional = !!types.delete(Type::Instance.new(Type::Builtin[:nil]))
    bool = false
    if types.include?(Type::Instance.new(Type::Builtin[:false])) &&
       types.include?(Type::Instance.new(Type::Builtin[:true]))
      types.delete(Type::Instance.new(Type::Builtin[:false]))
      types.delete(Type::Instance.new(Type::Builtin[:true]))
      bool = true
    end
    types.delete(Type.any) unless Config.current.options[:show_untyped]
    proc_tys, types = types.partition {|ty| ty.is_a?(Proc) }
    types = types.map {|ty| ty.screen_name(scratch) }
    types << scratch.show_proc_signature(proc_tys) unless proc_tys.empty?
    types << "bool" if bool
    types = types.sort
    if optional
      case types.size
      when 0 then "nil"
      when 1 then types.first + "?"
      else
        "(#{ types.join (" | ") })?"
      end
    else
      types.join (" | ")
    end
  end
end

#substitute(subst, depth)

[ GitHub ]

  
# File 'lib/typeprof/type.rb', line 389

def substitute(subst, depth)
  return Type.any if depth <= 0
  unions = []
  tys = Utils::Set[]
  @types.each do |ty|
    ty = ty.substitute(subst, depth - 1)
    case ty
    when Union
      unions << ty
    else
      tys = tys.add(ty)
    end
  end
  elems = @elems&.to_h do |(container_kind, base_type), elems|
    [[container_kind, base_type], elems.substitute(subst, depth - 1)]
  end
  ty = Union.create(tys, elems)
  unions.each do |ty0|
    ty = ty.union(ty0)
  end
  ty
end