class IRB::TypeCompletion::Types::SingletonType

Attributes

module_or_class[R]

Public Class Methods

new(module_or_class) click to toggle source
# File irb/type_completion/types.rb, line 157
def initialize(module_or_class)
  @module_or_class = module_or_class
end

Public Instance Methods

all_methods() click to toggle source
# File irb/type_completion/types.rb, line 162
  def all_methods() = methods | Kernel.methods
  def constants() = @module_or_class.constants
  def types() = [self]
  def nillable?() = false
  def nonnillable() = self
  def inspect
    "#{module_or_class}.itself"
  end
end

class InstanceType
  attr_reader :klass, :params
  def initialize(klass, params = {})
    @klass = klass
    @params = params
  end
  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
constants() click to toggle source
# File irb/type_completion/types.rb, line 163
  def constants() = @module_or_class.constants
  def types() = [self]
  def nillable?() = false
  def nonnillable() = self
  def inspect
    "#{module_or_class}.itself"
  end
end

class InstanceType
  attr_reader :klass, :params
  def initialize(klass, params = {})
    @klass = klass
    @params = params
  end
  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
inspect() click to toggle source
# File irb/type_completion/types.rb, line 167
def inspect
  "#{module_or_class}.itself"
end
methods() click to toggle source
# File irb/type_completion/types.rb, line 161
  def methods() = @module_or_class.methods
  def all_methods() = methods | Kernel.methods
  def constants() = @module_or_class.constants
  def types() = [self]
  def nillable?() = false
  def nonnillable() = self
  def inspect
    "#{module_or_class}.itself"
  end
end

class InstanceType
  attr_reader :klass, :params
  def initialize(klass, params = {})
    @klass = klass
    @params = params
  end
  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
nillable?() click to toggle source
# File irb/type_completion/types.rb, line 165
  def nillable?() = false
  def nonnillable() = self
  def inspect
    "#{module_or_class}.itself"
  end
end

class InstanceType
  attr_reader :klass, :params
  def initialize(klass, params = {})
    @klass = klass
    @params = params
  end
  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
    
nonnillable() click to toggle source
# File irb/type_completion/types.rb, line 166
  def nonnillable() = self
  def inspect
    "#{module_or_class}.itself"
  end
end
transform() { |self| ... } click to toggle source
# File irb/type_completion/types.rb, line 160
  def transform() = yield(self)
  def methods() = @module_or_class.methods
  def all_methods() = methods | Kernel.methods
  def constants() = @module_or_class.constants
  def types() = [self]
  def nillable?() = false
  def nonnillable() = self
  def inspect
    "#{module_or_class}.itself"
  end
end

class InstanceType
  attr_reader :klass, :params
  def initialize(klass, params = {})
    @klass = klass
    @params = params
  end
  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] ||= [])
types() click to toggle source
# File irb/type_completion/types.rb, line 164
  def types() = [self]
  def nillable?() = false
  def nonnillable() = self
  def inspect
    "#{module_or_class}.itself"
  end
end

class InstanceType
  attr_reader :klass, :params
  def initialize(klass, params = {})
    @klass = klass
    @params = params
  end
  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