class Solargraph::ComplexType


A container for type data based on YARD type tags.

def ==(other)

def ==(other)
  self.eql?(other)
end

def [](index)

Returns:
  • (UniqueType) -

Parameters:
  • index (Integer) --
def [](index)
  @items[index]
end

def all? &block

def all? &block
  @items.all? &block
end

def all_params

Returns:
  • (Array) -
def all_params
  @items.first.all_params || []
end

def all_rooted?

fully qualified
every type and subtype in this union have been resolved to be
def all_rooted?
  all?(&:all_rooted?)
end

def any? &block

def any? &block
  @items.compact.any? &block
end

def bottom?

def bottom?
  @items.all?(&:bot?)
end

def each &block

Returns:
  • (Enumerable) -

Other tags:
    Yieldparam: -
def each &block
  @items.each &block
end

def each_unique_type &block

Returns:
  • (Enumerator) -
  • (void) -

Overloads:
  • each_unique_type()

Other tags:
    Yieldparam: -
def each_unique_type &block
  return enum_for(__method__) unless block_given?
  @items.each do |item|
    item.each_unique_type &block
  end
end

def eql?(other)

def eql?(other)
  self.class == other.class &&
    @items == other.items
end

def first

Returns:
  • (UniqueType) -
def first
  @items.first
end

def force_rooted

Returns:
  • (self) -
def force_rooted
  transform do |t|
    t.recreate(make_rooted: true)
  end
end

def generic?

def generic?
  any?(&:generic?)
end

def hash

def hash
  [self.class, @items].hash
end

def initialize types = [UniqueType::UNDEFINED]

Parameters:
  • types (Array) --
def initialize types = [UniqueType::UNDEFINED]
  # @todo @items here should not need an annotation

  # @type [Array<UniqueType>]

  @items = types.flat_map(&:items).uniq(&:to_s)
end

def length

Returns:
  • (Integer) -
def length
  @items.length
end

def map &block

Returns:
  • (Array) -

Other tags:
    Yieldparam: -
def map &block
  @items.map &block
end

def method_missing name, *args, &block

Returns:
  • (Object, nil) -

Parameters:
  • name (Symbol) --
def method_missing name, *args, &block
  return if @items.first.nil?
  return @items.first.send(name, *args, &block) if respond_to_missing?(name)
  super
end

def namespace

Returns:
  • (String) -
def namespace
  # cache this attr for high frequency call

  @namespace ||= method_missing(:namespace).to_s
end

def namespaces

Returns:
  • (Array) -
def namespaces
  @items.map(&:namespace)
end

def nullable?

def nullable?
  @items.any?(&:nil_type?)
end

def parse *strings, partial: false

Other tags:
    Todo: - To be able to select the right signature above,

Returns:
  • (ComplexType) -

Parameters:
  • *strings (Array) -- The type definitions to parse

Other tags:
    Note: -
def parse *strings, partial: false
  # @type [Hash{Array<String> => ComplexType}]

  @cache ||= {}
  unless partial
    cached = @cache[strings]
    return cached unless cached.nil?
  end
  types = []
  key_types = nil
  strings.each do |type_string|
    point_stack = 0
    curly_stack = 0
    paren_stack = 0
    base = String.new
    subtype_string = String.new
    type_string&.each_char do |char|
      if char == '='
        #raise ComplexTypeError, "Invalid = in type #{type_string}" unless curly_stack > 0

      elsif char == '<'
        point_stack += 1
      elsif char == '>'
        if subtype_string.end_with?('=') && curly_stack > 0
          subtype_string += char
        elsif base.end_with?('=')
          raise ComplexTypeError, "Invalid hash thing" unless key_types.nil?
          # types.push ComplexType.new([UniqueType.new(base[0..-2].strip)])

          types.push UniqueType.parse(base[0..-2].strip, subtype_string)
          # @todo this should either expand key_type's type

          #   automatically or complain about not being

          #   compatible with key_type's type in type checking

          key_types = types
          types = []
          base.clear
          subtype_string.clear
          next
        else
          raise ComplexTypeError, "Invalid close in type #{type_string}" if point_stack == 0
          point_stack -= 1
          subtype_string += char
        end
        next
      elsif char == '{'
        curly_stack += 1
      elsif char == '}'
        curly_stack -= 1
        subtype_string += char
        raise ComplexTypeError, "Invalid close in type #{type_string}" if curly_stack < 0
        next
      elsif char == '('
        paren_stack += 1
      elsif char == ')'
        paren_stack -= 1
        subtype_string += char
        raise ComplexTypeError, "Invalid close in type #{type_string}" if paren_stack < 0
        next
      elsif char == ',' && point_stack == 0 && curly_stack == 0 && paren_stack == 0
        # types.push ComplexType.new([UniqueType.new(base.strip, subtype_string.strip)])

        types.push UniqueType.parse(base.strip, subtype_string.strip)
        base.clear
        subtype_string.clear
        next
      end
      if point_stack == 0 && curly_stack == 0 && paren_stack == 0
        base.concat char
      else
        subtype_string.concat char
      end
    end
    raise ComplexTypeError, "Unclosed subtype in #{type_string}" if point_stack != 0 || curly_stack != 0 || paren_stack != 0
    # types.push ComplexType.new([UniqueType.new(base, subtype_string)])

    types.push UniqueType.parse(base.strip, subtype_string.strip)
  end
  unless key_types.nil?
    raise ComplexTypeError, "Invalid use of key/value parameters" unless partial
    return key_types if types.empty?
    return [key_types, types]
  end
  result = partial ? types : ComplexType.new(types)
  @cache[strings] = result unless partial
  result
end

def qualify api_map, context = ''

Returns:
  • (ComplexType) -

Parameters:
  • context (String) --
  • api_map (ApiMap) --
def qualify api_map, context = ''
  red = reduce_object
  types = red.items.map do |t|
    next t if ['nil', 'void', 'undefined'].include?(t.name)
    next t if ['::Boolean'].include?(t.rooted_name)
    t.qualify api_map, context
  end
  ComplexType.new(types).reduce_object
end

def reduce_class dst

Returns:
  • (String) -

Parameters:
  • dst (String) --

Other tags:
    Todo: - This is a quick and dirty hack that forces `self` keywords
def reduce_class dst
  while dst =~ /^(Class|Module)\<(.*?)\>$/
    dst = dst.sub(/^(Class|Module)\</, '').sub(/\>$/, '')
  end
  dst
end

def reduce_class_type

Returns:
  • (ComplexType) -
def reduce_class_type
  new_items = items.flat_map do |type|
    next type unless ['Module', 'Class'].include?(type.name)
    type.all_params
  end
  ComplexType.new(new_items)
end

def reduce_object

Returns:
  • (ComplexType) -
def reduce_object
  new_items = items.flat_map do |ut|
    next [ut] if ut.name != 'Object' || ut.subtypes.empty?
    ut.subtypes
  end
  ComplexType.new(new_items)
end

def resolve_generics definitions, context_type

Returns:
  • (ComplexType) -

Parameters:
  • context_type (ComplexType) --
  • definitions (Pin::Namespace, Pin::Method) --
def resolve_generics definitions, context_type
  result = @items.map { |i| i.resolve_generics(definitions, context_type) }
  ComplexType.new(result)
end

def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}

Returns:
  • (self) -

Parameters:
  • resolved_generic_values (Hash{String => ComplexType}) -- Added to as types are encountered or resolved
  • context_type (UniqueType, nil) --
  • generics_to_resolve (Enumerable) -- ]
def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
  return self unless generic?
  ComplexType.new(@items.map { |i| i.resolve_generics_from_context(generics_to_resolve, context_type, resolved_generic_values: resolved_generic_values) })
end

def respond_to_missing?(name, include_private = false)

Parameters:
  • include_private (Boolean) --
  • name (Symbol) --
def respond_to_missing?(name, include_private = false)
  TypeMethods.public_instance_methods.include?(name) || super
end

def rooted?

#all_rooted? to check their subtypes as well
every top-level type has resolved to be fully qualified; see
def rooted?
  all?(&:rooted?)
end

def rooted?

def rooted?
  @items.all?(&:rooted?)
end

def rooted_tags

def rooted_tags
  map(&:rooted_tag).join(', ')
end

def select &block

Returns:
  • (Array) -
def select &block
  @items.select &block
end

def self_to_type dst

Returns:
  • (ComplexType) -

Parameters:
  • dst (ComplexType) --
def self_to_type dst
  object_type_dst = dst.reduce_class_type
  transform do |t|
    next t if t.name != 'self'
    object_type_dst
  end
end

def selfy?

def selfy?
  @items.any?(&:selfy?)
end

def tags

def tags
  @items.map(&:tag).join(', ')
end

def to_a

Returns:
  • (Array) -
def to_a
  @items
end

def to_rbs

Returns:
  • (String) -
def to_rbs
  ((@items.length > 1 ? '(' : '') +
   @items.map(&:to_rbs).join(' | ') +
   (@items.length > 1 ? ')' : ''))
end

def to_s

def to_s
  map(&:tag).join(', ')
end

def transform(new_name = nil, &transform_type)

Returns:
  • (ComplexType) -

Other tags:
    Yieldreturn: -

Other tags:
    Yieldparam: t -

Parameters:
  • new_name (String, nil) --
def transform(new_name = nil, &transform_type)
  raise "Please remove leading :: and set rooted with recreate() instead - #{new_name}" if new_name&.start_with?('::')
  ComplexType.new(map { |ut| ut.transform(new_name, &transform_type) })
end

def try_parse *strings

Returns:
  • (ComplexType) -

Parameters:
  • strings (Array) --
def try_parse *strings
  parse *strings
rescue ComplexTypeError => e
  Solargraph.logger.info "Error parsing complex type `#{strings.join(', ')}`: #{e.message}"
  ComplexType::UNDEFINED
end