class IRB::TypeCompletion::Types::SingletonType::InstanceType

Constants

ARRAY
CLASS
COMPLEX
FALSE
FLOAT
HASH
INTEGER
MODULE
NIL
OBJECT
PROC
RANGE
RATIONAL
REGEXP
STRING
SYMBOL
TRUE

Attributes

klass[R]
params[R]

Public Class Methods

new(klass, params = {}) click to toggle source
# File irb/type_completion/types.rb, line 174
def initialize(klass, params = {})
  @klass = klass
  @params = params
end

Public Instance Methods

all_methods() click to toggle source
# File irb/type_completion/types.rb, line 180
  def all_methods() = rbs_methods.keys | @klass.instance_methods | @klass.private_instance_methods
  def constants() = []
  def types() = [self]
  def nillable?() = (@klass == NilClass)
  def nonnillable() = self
  def rbs_methods
    name = Types.class_name_of(@klass)
    return {} unless name && Types.rbs_builder

    type_name = RBS::TypeName(name).absolute!
    Types.rbs_builder.build_instance(type_name).methods rescue {}
  end
  def inspect
    if params.empty?
      inspect_without_params
    else
      params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
      "#{inspect_without_params}#{params_string}"
    end
  end
  def inspect_without_params
    if klass == NilClass
      'nil'
    elsif klass == TrueClass
      'true'
    elsif klass == FalseClass
      'false'
    else
      klass.singleton_class? ? klass.superclass.to_s : klass.to_s
    end
  end
end

NIL = InstanceType.new NilClass
OBJECT = InstanceType.new Object
TRUE = InstanceType.new TrueClass
FALSE = InstanceType.new FalseClass
SYMBOL = InstanceType.new Symbol
STRING = InstanceType.new String
INTEGER = InstanceType.new Integer
RANGE = InstanceType.new Range
REGEXP = InstanceType.new Regexp
FLOAT = InstanceType.new Float
RATIONAL = InstanceType.new Rational
COMPLEX = InstanceType.new Complex
ARRAY = InstanceType.new Array
HASH = InstanceType.new Hash
CLASS = InstanceType.new Class
MODULE = InstanceType.new Module
PROC = InstanceType.new Proc

class UnionType
  attr_reader :types

  def initialize(*types)
    @types = []
    singletons = []
    instances = {}
    collect = -> type do
      case type
      in UnionType
        type.types.each(&collect)
      in InstanceType
        params = (instances[type.klass] ||= {})
        type.params.each do |k, v|
          (params[k] ||= []) << v
        end
      in SingletonType
        singletons << type
      end
    end
    types.each(&collect)
    @types = singletons.uniq + instances.map do |klass, params|
      InstanceType.new(klass, params.transform_values { |v| UnionType[*v] })
    end
  end

  def transform(&block)
    UnionType[*types.map(&block)]
  end

  def nillable?
    types.any?(&:nillable?)
  end

  def nonnillable
    UnionType[*types.reject { _1.is_a?(InstanceType) && _1.klass == NilClass }]
  end

  def self.[](*types)
    type = new(*types)
    if type.types.empty?
      OBJECT
    elsif type.types.size == 1
      type.types.first
    else
      type
    end
  end

  def methods() = @types.flat_map(&:methods).uniq
  def all_methods() = @types.flat_map(&:all_methods).uniq
  def constants() = @types.flat_map(&:constants).uniq
  def inspect() = @types.map(&:inspect).join(' | ')
end

BOOLEAN = UnionType[TRUE, FALSE]

def self.array_of(*types)
  type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
  InstanceType.new Array, Elem: type
end

def self.from_rbs_type(return_type, self_type, extra_vars = {})
  case return_type
  when RBS::Types::Bases::Self
    self_type
  when RBS::Types::Bases::Bottom, RBS::Types::Bases::Nil
    NIL
  when RBS::Types::Bases::Any, RBS::Types::Bases::Void
    OBJECT
  when RBS::Types::Bases::Class
    self_type.transform do |type|
      case type
      in SingletonType
        InstanceType.new(self_type.module_or_class.is_a?(Class) ? Class : Module)
      in InstanceType
        SingletonType.new type.klass
      end
    end
    UnionType[*types]
  when RBS::Types::Bases::Bool
    BOOLEAN
  when RBS::Types::Bases::Instance
    self_type.transform do |type|
      if type.is_a?(SingletonType) && type.module_or_class.is_a?(Class)
        InstanceType.new type.module_or_class
      else
        OBJECT
      end
    end
  when RBS::Types::Union
    UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
  when RBS::Types::Proc
    PROC
  when RBS::Types::Tuple
    elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
    InstanceType.new Array, Elem: elem
  when RBS::Types::Record
    InstanceType.new Hash, K: SYMBOL, V: OBJECT
  when RBS::Types::Literal
    InstanceType.new return_type.literal.class
  when RBS::Types::Variable
    if extra_vars.key? return_type.name
      extra_vars[return_type.name]
    elsif self_type.is_a? InstanceType
      self_type.params[return_type.name] || OBJECT
    elsif self_type.is_a? UnionType
      types = self_type.types.filter_map do |t|
        t.params[return_type.name] if t.is_a? InstanceType
      end
      UnionType[*types]
    else
      OBJECT
    end
  when RBS::Types::Optional
    UnionType[from_rbs_type(return_type.type, self_type, extra_vars), NIL]
  when RBS::Types::Alias
    case return_type.name.name
    when :int
      INTEGER
    when :boolish
      BOOLEAN
    when :string
      STRING
    else
      # TODO: ???
      OBJECT
    end
  when RBS::Types::Interface
    # unimplemented
    OBJECT
  when RBS::Types::ClassInstance
    klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
    if return_type.args
      args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
      names = rbs_builder.build_singleton(return_type.name).type_params
      params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
    end
    InstanceType.new klass, params || {}
  end
end

def self.method_return_bottom?(method)
  method.type.return_type.is_a? RBS::Types::Bases::Bottom
end

def self.match_free_variables(vars, types, values)
  accumulator = {}
  types.zip values do |t, v|
    _match_free_variable(vars, t, v, accumulator) if v
  end
  accumulator.transform_values { UnionType[*_1] }
end

def self._match_free_variable(vars, rbs_type, value, accumulator)
  case [rbs_type, value]
  in [RBS::Types::Variable,]
    (accumulator[rbs_type.name] ||= []) << value if vars.include? rbs_type.name
  in [RBS::Types::ClassInstance, InstanceType]
    names = rbs_builder.build_singleton(rbs_type.name).type_params
    names.zip(rbs_type.args).each do |name, arg|
      v = value.params[name]
      _match_free_variable vars, arg, v, accumulator if v
    end
  in [RBS::Types::Tuple, InstanceType] if value.klass == Array
    v = value.params[:Elem]
    rbs_type.types.each do |t|
      _match_free_variable vars, t, v, accumulator
    end
  in [RBS::Types::Record, InstanceType] if value.klass == Hash
    # TODO
  in [RBS::Types::Interface,]
    definition = rbs_builder.build_interface rbs_type.name
    convert = {}
    definition.type_params.zip(rbs_type.args).each do |from, arg|
      convert[from] = arg.name if arg.is_a? RBS::Types::Variable
    end
    return if convert.empty?
    ac = {}
    definition.methods.each do |method_name, method|
      return_type = method_return_type value, method_name
      method.defs.each do |method_def|
        interface_return_type = method_def.type.type.return_type
        _match_free_variable convert, interface_return_type, return_type, ac
      end
    end
    convert.each do |from, to|
      values = ac[from]
      (accumulator[to] ||= []).concat values if values
    end
  else
  end
constants() click to toggle source
# File irb/type_completion/types.rb, line 181
  def constants() = []
  def types() = [self]
  def nillable?() = (@klass == NilClass)
  def nonnillable() = self
  def rbs_methods
    name = Types.class_name_of(@klass)
    return {} unless name && Types.rbs_builder

    type_name = RBS::TypeName(name).absolute!
    Types.rbs_builder.build_instance(type_name).methods rescue {}
  end
  def inspect
    if params.empty?
      inspect_without_params
    else
      params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
      "#{inspect_without_params}#{params_string}"
    end
  end
  def inspect_without_params
    if klass == NilClass
      'nil'
    elsif klass == TrueClass
      'true'
    elsif klass == FalseClass
      'false'
    else
      klass.singleton_class? ? klass.superclass.to_s : klass.to_s
    end
  end
end

NIL = InstanceType.new NilClass
OBJECT = InstanceType.new Object
TRUE = InstanceType.new TrueClass
FALSE = InstanceType.new FalseClass
SYMBOL = InstanceType.new Symbol
STRING = InstanceType.new String
INTEGER = InstanceType.new Integer
RANGE = InstanceType.new Range
REGEXP = InstanceType.new Regexp
FLOAT = InstanceType.new Float
RATIONAL = InstanceType.new Rational
COMPLEX = InstanceType.new Complex
ARRAY = InstanceType.new Array
HASH = InstanceType.new Hash
CLASS = InstanceType.new Class
MODULE = InstanceType.new Module
PROC = InstanceType.new Proc

class UnionType
  attr_reader :types

  def initialize(*types)
    @types = []
    singletons = []
    instances = {}
    collect = -> type do
      case type
      in UnionType
        type.types.each(&collect)
      in InstanceType
        params = (instances[type.klass] ||= {})
        type.params.each do |k, v|
          (params[k] ||= []) << v
        end
      in SingletonType
        singletons << type
      end
    end
    types.each(&collect)
    @types = singletons.uniq + instances.map do |klass, params|
      InstanceType.new(klass, params.transform_values { |v| UnionType[*v] })
    end
  end

  def transform(&block)
    UnionType[*types.map(&block)]
  end

  def nillable?
    types.any?(&:nillable?)
  end

  def nonnillable
    UnionType[*types.reject { _1.is_a?(InstanceType) && _1.klass == NilClass }]
  end

  def self.[](*types)
    type = new(*types)
    if type.types.empty?
      OBJECT
    elsif type.types.size == 1
      type.types.first
    else
      type
    end
  end

  def methods() = @types.flat_map(&:methods).uniq
  def all_methods() = @types.flat_map(&:all_methods).uniq
  def constants() = @types.flat_map(&:constants).uniq
  def inspect() = @types.map(&:inspect).join(' | ')
end

BOOLEAN = UnionType[TRUE, FALSE]

def self.array_of(*types)
  type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
  InstanceType.new Array, Elem: type
end

def self.from_rbs_type(return_type, self_type, extra_vars = {})
  case return_type
  when RBS::Types::Bases::Self
    self_type
  when RBS::Types::Bases::Bottom, RBS::Types::Bases::Nil
    NIL
  when RBS::Types::Bases::Any, RBS::Types::Bases::Void
    OBJECT
  when RBS::Types::Bases::Class
    self_type.transform do |type|
      case type
      in SingletonType
        InstanceType.new(self_type.module_or_class.is_a?(Class) ? Class : Module)
      in InstanceType
        SingletonType.new type.klass
      end
    end
    UnionType[*types]
  when RBS::Types::Bases::Bool
    BOOLEAN
  when RBS::Types::Bases::Instance
    self_type.transform do |type|
      if type.is_a?(SingletonType) && type.module_or_class.is_a?(Class)
        InstanceType.new type.module_or_class
      else
        OBJECT
      end
    end
  when RBS::Types::Union
    UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
  when RBS::Types::Proc
    PROC
  when RBS::Types::Tuple
    elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
    InstanceType.new Array, Elem: elem
  when RBS::Types::Record
    InstanceType.new Hash, K: SYMBOL, V: OBJECT
  when RBS::Types::Literal
    InstanceType.new return_type.literal.class
  when RBS::Types::Variable
    if extra_vars.key? return_type.name
      extra_vars[return_type.name]
    elsif self_type.is_a? InstanceType
      self_type.params[return_type.name] || OBJECT
    elsif self_type.is_a? UnionType
      types = self_type.types.filter_map do |t|
        t.params[return_type.name] if t.is_a? InstanceType
      end
      UnionType[*types]
    else
      OBJECT
    end
  when RBS::Types::Optional
    UnionType[from_rbs_type(return_type.type, self_type, extra_vars), NIL]
  when RBS::Types::Alias
    case return_type.name.name
    when :int
      INTEGER
    when :boolish
      BOOLEAN
    when :string
      STRING
    else
      # TODO: ???
      OBJECT
    end
  when RBS::Types::Interface
    # unimplemented
    OBJECT
  when RBS::Types::ClassInstance
    klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
    if return_type.args
      args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
      names = rbs_builder.build_singleton(return_type.name).type_params
      params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
    end
    InstanceType.new klass, params || {}
  end
end

def self.method_return_bottom?(method)
  method.type.return_type.is_a? RBS::Types::Bases::Bottom
end

def self.match_free_variables(vars, types, values)
  accumulator = {}
  types.zip values do |t, v|
    _match_free_variable(vars, t, v, accumulator) if v
  end
  accumulator.transform_values { UnionType[*_1] }
end

def self._match_free_variable(vars, rbs_type, value, accumulator)
  case [rbs_type, value]
  in [RBS::Types::Variable,]
    (accumulator[rbs_type.name] ||= []) << value if vars.include? rbs_type.name
  in [RBS::Types::ClassInstance, InstanceType]
    names = rbs_builder.build_singleton(rbs_type.name).type_params
    names.zip(rbs_type.args).each do |name, arg|
      v = value.params[name]
      _match_free_variable vars, arg, v, accumulator if v
    end
  in [RBS::Types::Tuple, InstanceType] if value.klass == Array
    v = value.params[:Elem]
    rbs_type.types.each do |t|
      _match_free_variable vars, t, v, accumulator
    end
  in [RBS::Types::Record, InstanceType] if value.klass == Hash
    # TODO
  in [RBS::Types::Interface,]
    definition = rbs_builder.build_interface rbs_type.name
    convert = {}
    definition.type_params.zip(rbs_type.args).each do |from, arg|
      convert[from] = arg.name if arg.is_a? RBS::Types::Variable
    end
    return if convert.empty?
    ac = {}
    definition.methods.each do |method_name, method|
      return_type = method_return_type value, method_name
      method.defs.each do |method_def|
        interface_return_type = method_def.type.type.return_type
        _match_free_variable convert, interface_return_type, return_type, ac
      end
    end
    convert.each do |from, to|
      values = ac[from]
      (accumulator[to] ||= []).concat values if values
    end
  else
  end
end
inspect() click to toggle source
# File irb/type_completion/types.rb, line 192
def inspect
  if params.empty?
    inspect_without_params
  else
    params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
    "#{inspect_without_params}#{params_string}"
  end
end
inspect_without_params() click to toggle source
# File irb/type_completion/types.rb, line 200
def inspect_without_params
  if klass == NilClass
    'nil'
  elsif klass == TrueClass
    'true'
  elsif klass == FalseClass
    'false'
  else
    klass.singleton_class? ? klass.superclass.to_s : klass.to_s
  end
end
methods() click to toggle source
# File irb/type_completion/types.rb, line 179
  def methods() = rbs_methods.select { _2.public? }.keys | @klass.instance_methods
  def all_methods() = rbs_methods.keys | @klass.instance_methods | @klass.private_instance_methods
  def constants() = []
  def types() = [self]
  def nillable?() = (@klass == NilClass)
  def nonnillable() = self
  def rbs_methods
    name = Types.class_name_of(@klass)
    return {} unless name && Types.rbs_builder

    type_name = RBS::TypeName(name).absolute!
    Types.rbs_builder.build_instance(type_name).methods rescue {}
  end
  def inspect
    if params.empty?
      inspect_without_params
    else
      params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
      "#{inspect_without_params}#{params_string}"
    end
  end
  def inspect_without_params
    if klass == NilClass
      'nil'
    elsif klass == TrueClass
      'true'
    elsif klass == FalseClass
      'false'
    else
      klass.singleton_class? ? klass.superclass.to_s : klass.to_s
    end
  end
end

NIL = InstanceType.new NilClass
OBJECT = InstanceType.new Object
TRUE = InstanceType.new TrueClass
FALSE = InstanceType.new FalseClass
SYMBOL = InstanceType.new Symbol
STRING = InstanceType.new String
INTEGER = InstanceType.new Integer
RANGE = InstanceType.new Range
REGEXP = InstanceType.new Regexp
FLOAT = InstanceType.new Float
RATIONAL = InstanceType.new Rational
COMPLEX = InstanceType.new Complex
ARRAY = InstanceType.new Array
HASH = InstanceType.new Hash
CLASS = InstanceType.new Class
MODULE = InstanceType.new Module
PROC = InstanceType.new Proc

class UnionType
  attr_reader :types

  def initialize(*types)
    @types = []
    singletons = []
    instances = {}
    collect = -> type do
      case type
      in UnionType
        type.types.each(&collect)
      in InstanceType
        params = (instances[type.klass] ||= {})
        type.params.each do |k, v|
          (params[k] ||= []) << v
        end
      in SingletonType
        singletons << type
      end
    end
    types.each(&collect)
    @types = singletons.uniq + instances.map do |klass, params|
      InstanceType.new(klass, params.transform_values { |v| UnionType[*v] })
    end
  end

  def transform(&block)
    UnionType[*types.map(&block)]
  end

  def nillable?
    types.any?(&:nillable?)
  end

  def nonnillable
    UnionType[*types.reject { _1.is_a?(InstanceType) && _1.klass == NilClass }]
  end

  def self.[](*types)
    type = new(*types)
    if type.types.empty?
      OBJECT
    elsif type.types.size == 1
      type.types.first
    else
      type
    end
  end

  def methods() = @types.flat_map(&:methods).uniq
  def all_methods() = @types.flat_map(&:all_methods).uniq
  def constants() = @types.flat_map(&:constants).uniq
  def inspect() = @types.map(&:inspect).join(' | ')
end

BOOLEAN = UnionType[TRUE, FALSE]

def self.array_of(*types)
  type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
  InstanceType.new Array, Elem: type
end

def self.from_rbs_type(return_type, self_type, extra_vars = {})
  case return_type
  when RBS::Types::Bases::Self
    self_type
  when RBS::Types::Bases::Bottom, RBS::Types::Bases::Nil
    NIL
  when RBS::Types::Bases::Any, RBS::Types::Bases::Void
    OBJECT
  when RBS::Types::Bases::Class
    self_type.transform do |type|
      case type
      in SingletonType
        InstanceType.new(self_type.module_or_class.is_a?(Class) ? Class : Module)
      in InstanceType
        SingletonType.new type.klass
      end
    end
    UnionType[*types]
  when RBS::Types::Bases::Bool
    BOOLEAN
  when RBS::Types::Bases::Instance
    self_type.transform do |type|
      if type.is_a?(SingletonType) && type.module_or_class.is_a?(Class)
        InstanceType.new type.module_or_class
      else
        OBJECT
      end
    end
  when RBS::Types::Union
    UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
  when RBS::Types::Proc
    PROC
  when RBS::Types::Tuple
    elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
    InstanceType.new Array, Elem: elem
  when RBS::Types::Record
    InstanceType.new Hash, K: SYMBOL, V: OBJECT
  when RBS::Types::Literal
    InstanceType.new return_type.literal.class
  when RBS::Types::Variable
    if extra_vars.key? return_type.name
      extra_vars[return_type.name]
    elsif self_type.is_a? InstanceType
      self_type.params[return_type.name] || OBJECT
    elsif self_type.is_a? UnionType
      types = self_type.types.filter_map do |t|
        t.params[return_type.name] if t.is_a? InstanceType
      end
      UnionType[*types]
    else
      OBJECT
    end
  when RBS::Types::Optional
    UnionType[from_rbs_type(return_type.type, self_type, extra_vars), NIL]
  when RBS::Types::Alias
    case return_type.name.name
    when :int
      INTEGER
    when :boolish
      BOOLEAN
    when :string
      STRING
    else
      # TODO: ???
      OBJECT
    end
  when RBS::Types::Interface
    # unimplemented
    OBJECT
  when RBS::Types::ClassInstance
    klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
    if return_type.args
      args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
      names = rbs_builder.build_singleton(return_type.name).type_params
      params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
    end
    InstanceType.new klass, params || {}
  end
end

def self.method_return_bottom?(method)
  method.type.return_type.is_a? RBS::Types::Bases::Bottom
end

def self.match_free_variables(vars, types, values)
  accumulator = {}
  types.zip values do |t, v|
    _match_free_variable(vars, t, v, accumulator) if v
  end
  accumulator.transform_values { UnionType[*_1] }
end

def self._match_free_variable(vars, rbs_type, value, accumulator)
  case [rbs_type, value]
  in [RBS::Types::Variable,]
    (accumulator[rbs_type.name] ||= []) << value if vars.include? rbs_type.name
  in [RBS::Types::ClassInstance, InstanceType]
    names = rbs_builder.build_singleton(rbs_type.name).type_params
    names.zip(rbs_type.args).each do |name, arg|
      v = value.params[name]
      _match_free_variable vars, arg, v, accumulator if v
    end
  in [RBS::Types::Tuple, InstanceType] if value.klass == Array
    v = value.params[:Elem]
    rbs_type.types.each do |t|
      _match_free_variable vars, t, v, accumulator
    end
  in [RBS::Types::Record, InstanceType] if value.klass == Hash
    # TODO
  in [RBS::Types::Interface,]
    definition = rbs_builder.build_interface rbs_type.name
    convert = {}
    definition.type_params.zip(rbs_type.args).each do |from, arg|
      convert[from] = arg.name if arg.is_a? RBS::Types::Variable
    end
    return if convert.empty?
    ac = {}
    definition.methods.each do |method_name, method|
      return_type = method_return_type value, method_name
      method.defs.each do |method_def|
        interface_return_type = method_def.type.type.return_type
        _match_free_variable convert, interface_return_type, return_type, ac
      end
    end
    convert.each do |from, to|
      values = ac[from]
      (accumulator[to] ||= []).concat values if values
    end
  else
  
nillable?() click to toggle source
# File irb/type_completion/types.rb, line 183
    def nillable?() = (@klass == NilClass)
    def nonnillable() = self
    def rbs_methods
      name = Types.class_name_of(@klass)
      return {} unless name && Types.rbs_builder

      type_name = RBS::TypeName(name).absolute!
      Types.rbs_builder.build_instance(type_name).methods rescue {}
    end
    def inspect
      if params.empty?
        inspect_without_params
      else
        params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
        "#{inspect_without_params}#{params_string}"
      end
    end
    def inspect_without_params
      if klass == NilClass
        'nil'
      elsif klass == TrueClass
        'true'
      elsif klass == FalseClass
        'false'
      else
        klass.singleton_class? ? klass.superclass.to_s : klass.to_s
      end
    end
  end

  NIL = InstanceType.new NilClass
  OBJECT = InstanceType.new Object
  TRUE = InstanceType.new TrueClass
  FALSE = InstanceType.new FalseClass
  SYMBOL = InstanceType.new Symbol
  STRING = InstanceType.new String
  INTEGER = InstanceType.new Integer
  RANGE = InstanceType.new Range
  REGEXP = InstanceType.new Regexp
  FLOAT = InstanceType.new Float
  RATIONAL = InstanceType.new Rational
  COMPLEX = InstanceType.new Complex
  ARRAY = InstanceType.new Array
  HASH = InstanceType.new Hash
  CLASS = InstanceType.new Class
  MODULE = InstanceType.new Module
  PROC = InstanceType.new Proc

  class UnionType
    attr_reader :types

    def initialize(*types)
      @types = []
      singletons = []
      instances = {}
      collect = -> type do
        case type
        in UnionType
          type.types.each(&collect)
        in InstanceType
          params = (instances[type.klass] ||= {})
          type.params.each do |k, v|
            (params[k] ||= []) << v
          end
        in SingletonType
          singletons << type
        end
      end
      types.each(&collect)
      @types = singletons.uniq + instances.map do |klass, params|
        InstanceType.new(klass, params.transform_values { |v| UnionType[*v] })
      end
    end

    def transform(&block)
      UnionType[*types.map(&block)]
    end

    def nillable?
      types.any?(&:nillable?)
    end

    def nonnillable
      UnionType[*types.reject { _1.is_a?(InstanceType) && _1.klass == NilClass }]
    end

    def self.[](*types)
      type = new(*types)
      if type.types.empty?
        OBJECT
      elsif type.types.size == 1
        type.types.first
      else
        type
      end
    end

    def methods() = @types.flat_map(&:methods).uniq
    def all_methods() = @types.flat_map(&:all_methods).uniq
    def constants() = @types.flat_map(&:constants).uniq
    def inspect() = @types.map(&:inspect).join(' | ')
  end

  BOOLEAN = UnionType[TRUE, FALSE]

  def self.array_of(*types)
    type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
    InstanceType.new Array, Elem: type
  end

  def self.from_rbs_type(return_type, self_type, extra_vars = {})
    case return_type
    when RBS::Types::Bases::Self
      self_type
    when RBS::Types::Bases::Bottom, RBS::Types::Bases::Nil
      NIL
    when RBS::Types::Bases::Any, RBS::Types::Bases::Void
      OBJECT
    when RBS::Types::Bases::Class
      self_type.transform do |type|
        case type
        in SingletonType
          InstanceType.new(self_type.module_or_class.is_a?(Class) ? Class : Module)
        in InstanceType
          SingletonType.new type.klass
        end
      end
      UnionType[*types]
    when RBS::Types::Bases::Bool
      BOOLEAN
    when RBS::Types::Bases::Instance
      self_type.transform do |type|
        if type.is_a?(SingletonType) && type.module_or_class.is_a?(Class)
          InstanceType.new type.module_or_class
        else
          OBJECT
        end
      end
    when RBS::Types::Union
      UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
    when RBS::Types::Proc
      PROC
    when RBS::Types::Tuple
      elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
      InstanceType.new Array, Elem: elem
    when RBS::Types::Record
      InstanceType.new Hash, K: SYMBOL, V: OBJECT
    when RBS::Types::Literal
      InstanceType.new return_type.literal.class
    when RBS::Types::Variable
      if extra_vars.key? return_type.name
        extra_vars[return_type.name]
      elsif self_type.is_a? InstanceType
        self_type.params[return_type.name] || OBJECT
      elsif self_type.is_a? UnionType
        types = self_type.types.filter_map do |t|
          t.params[return_type.name] if t.is_a? InstanceType
        end
        UnionType[*types]
      else
        OBJECT
      end
    when RBS::Types::Optional
      UnionType[from_rbs_type(return_type.type, self_type, extra_vars), NIL]
    when RBS::Types::Alias
      case return_type.name.name
      when :int
        INTEGER
      when :boolish
        BOOLEAN
      when :string
        STRING
      else
        # TODO: ???
        OBJECT
      end
    when RBS::Types::Interface
      # unimplemented
      OBJECT
    when RBS::Types::ClassInstance
      klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
      if return_type.args
        args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
        names = rbs_builder.build_singleton(return_type.name).type_params
        params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
      end
      InstanceType.new klass, params || {}
    end
  end

  def self.method_return_bottom?(method)
    method.type.return_type.is_a? RBS::Types::Bases::Bottom
  end

  def self.match_free_variables(vars, types, values)
    accumulator = {}
    types.zip values do |t, v|
      _match_free_variable(vars, t, v, accumulator) if v
    end
    accumulator.transform_values { UnionType[*_1] }
  end

  def self._match_free_variable(vars, rbs_type, value, accumulator)
    case [rbs_type, value]
    in [RBS::Types::Variable,]
      (accumulator[rbs_type.name] ||= []) << value if vars.include? rbs_type.name
    in [RBS::Types::ClassInstance, InstanceType]
      names = rbs_builder.build_singleton(rbs_type.name).type_params
      names.zip(rbs_type.args).each do |name, arg|
        v = value.params[name]
        _match_free_variable vars, arg, v, accumulator if v
      end
    in [RBS::Types::Tuple, InstanceType] if value.klass == Array
      v = value.params[:Elem]
      rbs_type.types.each do |t|
        _match_free_variable vars, t, v, accumulator
      end
    in [RBS::Types::Record, InstanceType] if value.klass == Hash
      # TODO
    in [RBS::Types::Interface,]
      definition = rbs_builder.build_interface rbs_type.name
      convert = {}
      definition.type_params.zip(rbs_type.args).each do |from, arg|
        convert[from] = arg.name if arg.is_a? RBS::Types::Variable
      end
      return if convert.empty?
      ac = {}
      definition.methods.each do |method_name, method|
        return_type = method_return_type value, method_name
        method.defs.each do |method_def|
          interface_return_type = method_def.type.type.return_type
          _match_free_variable convert, interface_return_type, return_type, ac
        end
      end
      convert.each do |from, to|
        values = ac[from]
        (accumulator[to] ||= []).concat values if values
      end
    else
    end
  end
end
nonnillable() click to toggle source
# File irb/type_completion/types.rb, line 184
  def nonnillable() = self
  def rbs_methods
    name = Types.class_name_of(@klass)
    return {} unless name && Types.rbs_builder

    type_name = RBS::TypeName(name).absolute!
    Types.rbs_builder.build_instance(type_name).methods rescue {}
  end
  def inspect
    if params.empty?
      inspect_without_params
    else
      params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
      "#{inspect_without_params}#{params_string}"
    end
  end
  def inspect_without_params
    if klass == NilClass
      'nil'
    elsif klass == TrueClass
      'true'
    elsif klass == FalseClass
      'false'
    else
      klass.singleton_class? ? klass.superclass.to_s : klass.to_s
    end
  end
end
rbs_methods() click to toggle source
# File irb/type_completion/types.rb, line 185
def rbs_methods
  name = Types.class_name_of(@klass)
  return {} unless name && Types.rbs_builder

  type_name = RBS::TypeName(name).absolute!
  Types.rbs_builder.build_instance(type_name).methods rescue {}
end
transform() { |self| ... } click to toggle source
# File irb/type_completion/types.rb, line 178
  def transform() = yield(self)
  def methods() = rbs_methods.select { _2.public? }.keys | @klass.instance_methods
  def all_methods() = rbs_methods.keys | @klass.instance_methods | @klass.private_instance_methods
  def constants() = []
  def types() = [self]
  def nillable?() = (@klass == NilClass)
  def nonnillable() = self
  def rbs_methods
    name = Types.class_name_of(@klass)
    return {} unless name && Types.rbs_builder

    type_name = RBS::TypeName(name).absolute!
    Types.rbs_builder.build_instance(type_name).methods rescue {}
  end
  def inspect
    if params.empty?
      inspect_without_params
    else
      params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
      "#{inspect_without_params}#{params_string}"
    end
  end
  def inspect_without_params
    if klass == NilClass
      'nil'
    elsif klass == TrueClass
      'true'
    elsif klass == FalseClass
      'false'
    else
      klass.singleton_class? ? klass.superclass.to_s : klass.to_s
    end
  end
end

NIL = InstanceType.new NilClass
OBJECT = InstanceType.new Object
TRUE = InstanceType.new TrueClass
FALSE = InstanceType.new FalseClass
SYMBOL = InstanceType.new Symbol
STRING = InstanceType.new String
INTEGER = InstanceType.new Integer
RANGE = InstanceType.new Range
REGEXP = InstanceType.new Regexp
FLOAT = InstanceType.new Float
RATIONAL = InstanceType.new Rational
COMPLEX = InstanceType.new Complex
ARRAY = InstanceType.new Array
HASH = InstanceType.new Hash
CLASS = InstanceType.new Class
MODULE = InstanceType.new Module
PROC = InstanceType.new Proc

class UnionType
  attr_reader :types

  def initialize(*types)
    @types = []
    singletons = []
    instances = {}
    collect = -> type do
      case type
      in UnionType
        type.types.each(&collect)
      in InstanceType
        params = (instances[type.klass] ||= {})
        type.params.each do |k, v|
          (params[k] ||= []) << v
        end
      in SingletonType
        singletons << type
      end
    end
    types.each(&collect)
    @types = singletons.uniq + instances.map do |klass, params|
      InstanceType.new(klass, params.transform_values { |v| UnionType[*v] })
    end
  end

  def transform(&block)
    UnionType[*types.map(&block)]
  end

  def nillable?
    types.any?(&:nillable?)
  end

  def nonnillable
    UnionType[*types.reject { _1.is_a?(InstanceType) && _1.klass == NilClass }]
  end

  def self.[](*types)
    type = new(*types)
    if type.types.empty?
      OBJECT
    elsif type.types.size == 1
      type.types.first
    else
      type
    end
  end

  def methods() = @types.flat_map(&:methods).uniq
  def all_methods() = @types.flat_map(&:all_methods).uniq
  def constants() = @types.flat_map(&:constants).uniq
  def inspect() = @types.map(&:inspect).join(' | ')
end

BOOLEAN = UnionType[TRUE, FALSE]

def self.array_of(*types)
  type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
  InstanceType.new Array, Elem: type
end

def self.from_rbs_type(return_type, self_type, extra_vars = {})
  case return_type
  when RBS::Types::Bases::Self
    self_type
  when RBS::Types::Bases::Bottom, RBS::Types::Bases::Nil
    NIL
  when RBS::Types::Bases::Any, RBS::Types::Bases::Void
    OBJECT
  when RBS::Types::Bases::Class
    self_type.transform do |type|
      case type
      in SingletonType
        InstanceType.new(self_type.module_or_class.is_a?(Class) ? Class : Module)
      in InstanceType
        SingletonType.new type.klass
      end
    end
    UnionType[*types]
  when RBS::Types::Bases::Bool
    BOOLEAN
  when RBS::Types::Bases::Instance
    self_type.transform do |type|
      if type.is_a?(SingletonType) && type.module_or_class.is_a?(Class)
        InstanceType.new type.module_or_class
      else
        OBJECT
      end
    end
  when RBS::Types::Union
    UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
  when RBS::Types::Proc
    PROC
  when RBS::Types::Tuple
    elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
    InstanceType.new Array, Elem: elem
  when RBS::Types::Record
    InstanceType.new Hash, K: SYMBOL, V: OBJECT
  when RBS::Types::Literal
    InstanceType.new return_type.literal.class
  when RBS::Types::Variable
    if extra_vars.key? return_type.name
      extra_vars[return_type.name]
    elsif self_type.is_a? InstanceType
      self_type.params[return_type.name] || OBJECT
    elsif self_type.is_a? UnionType
      types = self_type.types.filter_map do |t|
        t.params[return_type.name] if t.is_a? InstanceType
      end
      UnionType[*types]
    else
      OBJECT
    end
  when RBS::Types::Optional
    UnionType[from_rbs_type(return_type.type, self_type, extra_vars), NIL]
  when RBS::Types::Alias
    case return_type.name.name
    when :int
      INTEGER
    when :boolish
      BOOLEAN
    when :string
      STRING
    else
      # TODO: ???
      OBJECT
    end
  when RBS::Types::Interface
    # unimplemented
    OBJECT
  when RBS::Types::ClassInstance
    klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
    if return_type.args
      args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
      names = rbs_builder.build_singleton(return_type.name).type_params
      params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
    end
    InstanceType.new klass, params || {}
  end
end

def self.method_return_bottom?(method)
  method.type.return_type.is_a? RBS::Types::Bases::Bottom
end

def self.match_free_variables(vars, types, values)
  accumulator = {}
  types.zip values do |t, v|
    _match_free_variable(vars, t, v, accumulator) if v
  end
  accumulator.transform_values { UnionType[*_1] }
end

def self._match_free_variable(vars, rbs_type, value, accumulator)
  case [rbs_type, value]
  in [RBS::Types::Variable,]
    (accumulator[rbs_type.name] ||= []) << value if vars.include? rbs_type.name
  in [RBS::Types::ClassInstance, InstanceType]
    names = rbs_builder.build_singleton(rbs_type.name).type_params
    names.zip(rbs_type.args).each do |name, arg|
      v = value.params[name]
      _match_free_variable vars, arg, v, accumulator if v
    end
  in [RBS::Types::Tuple, InstanceType] if value.klass == Array
    v = value.params[:Elem]
    rbs_type.types.each do |t|
      _match_free_variable vars, t, v, accumulator
    end
  in [RBS::Types::Record, InstanceType] if value.klass == Hash
    # TODO
  in [RBS::Types::Interface,]
    definition = rbs_builder.build_interface rbs_type.name
    convert = {}
    definition.type_params.zip(rbs_type.args).each do |from, arg|
      convert[from] = arg.name if arg.is_a? RBS::Types::Variable
    end
    return if convert.empty?
    ac = {}
    definition.methods.each do |method_name, method|
      return_type = method_return_type value, method_name
      method.defs.each do |method_def|
        interface_return_type = method_def.type.type.return_type
        _match_free_variable convert, interface_return_type, return_type, ac
      end
    end
    convert.each do |from, to|
      values = ac[from]
      (accumulator[to] ||= []).concat values if values
    end
  else
types() click to toggle source
# File irb/type_completion/types.rb, line 182
  def types() = [self]
  def nillable?() = (@klass == NilClass)
  def nonnillable() = self
  def rbs_methods
    name = Types.class_name_of(@klass)
    return {} unless name && Types.rbs_builder

    type_name = RBS::TypeName(name).absolute!
    Types.rbs_builder.build_instance(type_name).methods rescue {}
  end
  def inspect
    if params.empty?
      inspect_without_params
    else
      params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
      "#{inspect_without_params}#{params_string}"
    end
  end
  def inspect_without_params
    if klass == NilClass
      'nil'
    elsif klass == TrueClass
      'true'
    elsif klass == FalseClass
      'false'
    else
      klass.singleton_class? ? klass.superclass.to_s : klass.to_s
    end
  end
end

NIL = InstanceType.new NilClass
OBJECT = InstanceType.new Object
TRUE = InstanceType.new TrueClass
FALSE = InstanceType.new FalseClass
SYMBOL = InstanceType.new Symbol
STRING = InstanceType.new String
INTEGER = InstanceType.new Integer
RANGE = InstanceType.new Range
REGEXP = InstanceType.new Regexp
FLOAT = InstanceType.new Float
RATIONAL = InstanceType.new Rational
COMPLEX = InstanceType.new Complex
ARRAY = InstanceType.new Array
HASH = InstanceType.new Hash
CLASS = InstanceType.new Class
MODULE = InstanceType.new Module
PROC = InstanceType.new Proc

class UnionType
  attr_reader :types

  def initialize(*types)
    @types = []
    singletons = []
    instances = {}
    collect = -> type do
      case type
      in UnionType
        type.types.each(&collect)
      in InstanceType
        params = (instances[type.klass] ||= {})
        type.params.each do |k, v|
          (params[k] ||= []) << v
        end
      in SingletonType
        singletons << type
      end
    end
    types.each(&collect)
    @types = singletons.uniq + instances.map do |klass, params|
      InstanceType.new(klass, params.transform_values { |v| UnionType[*v] })
    end
  end

  def transform(&block)
    UnionType[*types.map(&block)]
  end

  def nillable?
    types.any?(&:nillable?)
  end

  def nonnillable
    UnionType[*types.reject { _1.is_a?(InstanceType) && _1.klass == NilClass }]
  end

  def self.[](*types)
    type = new(*types)
    if type.types.empty?
      OBJECT
    elsif type.types.size == 1
      type.types.first
    else
      type
    end
  end

  def methods() = @types.flat_map(&:methods).uniq
  def all_methods() = @types.flat_map(&:all_methods).uniq
  def constants() = @types.flat_map(&:constants).uniq
  def inspect() = @types.map(&:inspect).join(' | ')
end

BOOLEAN = UnionType[TRUE, FALSE]

def self.array_of(*types)
  type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
  InstanceType.new Array, Elem: type
end

def self.from_rbs_type(return_type, self_type, extra_vars = {})
  case return_type
  when RBS::Types::Bases::Self
    self_type
  when RBS::Types::Bases::Bottom, RBS::Types::Bases::Nil
    NIL
  when RBS::Types::Bases::Any, RBS::Types::Bases::Void
    OBJECT
  when RBS::Types::Bases::Class
    self_type.transform do |type|
      case type
      in SingletonType
        InstanceType.new(self_type.module_or_class.is_a?(Class) ? Class : Module)
      in InstanceType
        SingletonType.new type.klass
      end
    end
    UnionType[*types]
  when RBS::Types::Bases::Bool
    BOOLEAN
  when RBS::Types::Bases::Instance
    self_type.transform do |type|
      if type.is_a?(SingletonType) && type.module_or_class.is_a?(Class)
        InstanceType.new type.module_or_class
      else
        OBJECT
      end
    end
  when RBS::Types::Union
    UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
  when RBS::Types::Proc
    PROC
  when RBS::Types::Tuple
    elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
    InstanceType.new Array, Elem: elem
  when RBS::Types::Record
    InstanceType.new Hash, K: SYMBOL, V: OBJECT
  when RBS::Types::Literal
    InstanceType.new return_type.literal.class
  when RBS::Types::Variable
    if extra_vars.key? return_type.name
      extra_vars[return_type.name]
    elsif self_type.is_a? InstanceType
      self_type.params[return_type.name] || OBJECT
    elsif self_type.is_a? UnionType
      types = self_type.types.filter_map do |t|
        t.params[return_type.name] if t.is_a? InstanceType
      end
      UnionType[*types]
    else
      OBJECT
    end
  when RBS::Types::Optional
    UnionType[from_rbs_type(return_type.type, self_type, extra_vars), NIL]
  when RBS::Types::Alias
    case return_type.name.name
    when :int
      INTEGER
    when :boolish
      BOOLEAN
    when :string
      STRING
    else
      # TODO: ???
      OBJECT
    end
  when RBS::Types::Interface
    # unimplemented
    OBJECT
  when RBS::Types::ClassInstance
    klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
    if return_type.args
      args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
      names = rbs_builder.build_singleton(return_type.name).type_params
      params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
    end
    InstanceType.new klass, params || {}
  end
end

def self.method_return_bottom?(method)
  method.type.return_type.is_a? RBS::Types::Bases::Bottom
end

def self.match_free_variables(vars, types, values)
  accumulator = {}
  types.zip values do |t, v|
    _match_free_variable(vars, t, v, accumulator) if v
  end
  accumulator.transform_values { UnionType[*_1] }
end

def self._match_free_variable(vars, rbs_type, value, accumulator)
  case [rbs_type, value]
  in [RBS::Types::Variable,]
    (accumulator[rbs_type.name] ||= []) << value if vars.include? rbs_type.name
  in [RBS::Types::ClassInstance, InstanceType]
    names = rbs_builder.build_singleton(rbs_type.name).type_params
    names.zip(rbs_type.args).each do |name, arg|
      v = value.params[name]
      _match_free_variable vars, arg, v, accumulator if v
    end
  in [RBS::Types::Tuple, InstanceType] if value.klass == Array
    v = value.params[:Elem]
    rbs_type.types.each do |t|
      _match_free_variable vars, t, v, accumulator
    end
  in [RBS::Types::Record, InstanceType] if value.klass == Hash
    # TODO
  in [RBS::Types::Interface,]
    definition = rbs_builder.build_interface rbs_type.name
    convert = {}
    definition.type_params.zip(rbs_type.args).each do |from, arg|
      convert[from] = arg.name if arg.is_a? RBS::Types::Variable
    end
    return if convert.empty?
    ac = {}
    definition.methods.each do |method_name, method|
      return_type = method_return_type value, method_name
      method.defs.each do |method_def|
        interface_return_type = method_def.type.type.return_type
        _match_free_variable convert, interface_return_type, return_type, ac
      end
    end
    convert.each do |from, to|
      values = ac[from]
      (accumulator[to] ||= []).concat values if values
    end
  else
  end
end