class Solargraph::ComplexType::UniqueType


unique types.
An individual type signature. A complex type can consist of multiple

def self.can_root_name?(name)

Parameters:
  • name (String) --
def self.can_root_name?(name)
  # name is not lowercase

  !name.empty? && name != name.downcase
end

def self.parse name, substring = '', make_rooted: nil

Returns:
  • (UniqueType) -

Parameters:
  • make_rooted (Boolean, nil) --
  • substring (String) -- The substring of the type
  • name (String) -- The name of the type
def self.parse name, substring = '', make_rooted: nil
  if name.start_with?(':::')
    raise "Illegal prefix: #{name}"
  end
  if name.start_with?('::')
    name = name[2..-1]
    rooted = true
  elsif !can_root_name?(name)
    rooted = true
  else
    rooted = false
  end
  rooted = make_rooted unless make_rooted.nil?
  # @type [Array<ComplexType>]

  key_types = []
  # @type [Array<ComplexType>]

  subtypes = []
  parameters_type = nil
  unless substring.empty?
    subs = ComplexType.parse(substring[1..-2], partial: true)
    parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
    if parameters_type == :hash
      raise ComplexTypeError, "Bad hash type" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
      # @todo should be able to resolve map; both types have it

      #   with same return type

      # @sg-ignore

      key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
      # @sg-ignore

      subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
    else
      subtypes.concat subs
    end
  end
  new(name, key_types, subtypes, rooted: rooted, parameters_type: parameters_type)
end

def ==(other)

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

def all_rooted?

def all_rooted?
  return true if name == GENERIC_TAG_NAME
  rooted? && all_params.all?(&:rooted?)
end

def can_root_name?(name_to_check = name)

def can_root_name?(name_to_check = name)
  self.class.can_root_name?(name_to_check)
end

def eql?(other)

def eql?(other)
  self.class == other.class &&
    @name == other.name &&
    @key_types == other.key_types &&
    @subtypes == other.subtypes &&
    @rooted == other.rooted? &&
    @all_params == other.all_params &&
    @parameters_type == other.parameters_type
end

def force_rooted

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

def generic?

def generic?
  name == GENERIC_TAG_NAME || all_params.any?(&:generic?)
end

def hash

def hash
  [self.class, @name, @key_types, @sub_types, @rooted, @all_params, @parameters_type].hash
end

def initialize(name, key_types = [], subtypes = [], rooted:, parameters_type: nil)

Parameters:
  • parameters_type (Symbol, nil) --
  • rooted (Boolean) --
  • subtypes (Array) --
  • key_types (Array) --
  • name (String) --
def initialize(name, key_types = [], subtypes = [], rooted:, parameters_type: nil)
  if parameters_type.nil?
    raise "You must supply parameters_type if you provide parameters" unless key_types.empty? && subtypes.empty?
  end
  raise "Please remove leading :: and set rooted instead - #{name.inspect}" if name.start_with?('::')
  @name = name
  @key_types = key_types
  @subtypes = subtypes
  @rooted = rooted
  @all_params = []
  @all_params.concat key_types
  @all_params.concat subtypes
  @parameters_type = parameters_type
end

def items

Returns:
  • (Array) -
def items
  [self]
end

def map &block

Returns:
  • (Array) -

Other tags:
    Yieldreturn: -

Other tags:
    Yieldparam: t -
def map &block
  [block.yield(self)]
end

def parameters?

Returns:
  • (Boolean) -
def parameters?
  !all_params.empty?
end

def parameters_as_rbs

Returns:
  • (String) -
def parameters_as_rbs
  return '' unless parameters?
  return "[#{all_params.map(&:to_rbs).join(', ')}]" if key_types.empty?
  # handle, e.g., Hash[K, V] case

  key_types_str = rbs_union(key_types)
  subtypes_str = rbs_union(subtypes)
  "[#{key_types_str}, #{subtypes_str}]"
end

def qualify api_map, context = ''

Returns:
  • (self, ComplexType, UniqueType) - The generated ComplexType

Parameters:
  • context (String) -- The namespace from which to resolve names
  • api_map (ApiMap) -- The ApiMap that performs qualification
def qualify api_map, context = ''
  transform do |t|
    next t if t.name == GENERIC_TAG_NAME
    next t if t.duck_type? || t.void? || t.undefined?
    recon = (t.rooted? ? '' : context)
    fqns = api_map.qualify(t.name, recon)
    if fqns.nil?
      next UniqueType::BOOLEAN if t.tag == 'Boolean'
      next UniqueType::UNDEFINED
    end
    t.recreate(new_name: fqns, make_rooted: true)
  end
end

def rbs_name

Returns:
  • (String) -
def rbs_name
  if name == 'undefined'
    'untyped'
  else
    rooted_name
  end
end

def rbs_union(types)

Returns:
  • (String) -

Parameters:
  • types (Array) --
def rbs_union(types)
  if types.length == 1
    types.first.to_rbs
  else
    "(#{types.map(&:to_rbs).join(' | ')})"
  end
end

def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)

Returns:
  • (self) -

Parameters:
  • new_subtypes (Array, nil) --
  • rooted (Boolean, nil) --
  • new_key_types (Array, nil) --
  • make_rooted (Boolean, nil) --
  • new_name (String, nil) --
def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)
  raise "Please remove leading :: and set rooted instead - #{new_name}" if new_name&.start_with?('::')
  new_name ||= name
  new_key_types ||= @key_types
  new_subtypes ||= @subtypes
  make_rooted = @rooted if make_rooted.nil?
  UniqueType.new(new_name, new_key_types, new_subtypes, rooted: make_rooted, parameters_type: parameters_type)
end

def resolve_generics definitions, context_type

Returns:
  • (UniqueType, ComplexType) -

Parameters:
  • context_type (ComplexType) -- The receiver type
  • definitions (Pin::Namespace, Pin::Method) -- The module/class/method which uses generic types
def resolve_generics definitions, context_type
  return self if definitions.nil? || definitions.generics.empty?
  transform(name) do |t|
    if t.name == GENERIC_TAG_NAME
      idx = definitions.generics.index(t.subtypes.first&.name)
      next t if idx.nil?
      context_type.all_params[idx] || ComplexType::UNDEFINED
    else
      t
    end
  end
end

def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}

Returns:
  • (UniqueType, ComplexType) -

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: {}
  if name == ComplexType::GENERIC_TAG_NAME
    type_param = subtypes.first&.name
    return self unless generics_to_resolve.include? type_param
    unless context_type.nil? || !resolved_generic_values[type_param].nil?
      new_binding = true
      resolved_generic_values[type_param] = context_type
    end
    if new_binding
      resolved_generic_values.transform_values! do |complex_type|
        complex_type.resolve_generics_from_context(generics_to_resolve, nil, resolved_generic_values: resolved_generic_values)
      end
    end
    return resolved_generic_values[type_param] || self
  end
  # @todo typechecking should complain when the method being called has no @yieldparam tag

  new_key_types = resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values, &:key_types)
  new_subtypes = resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values, &:subtypes)
  recreate(new_key_types: new_key_types, new_subtypes: new_subtypes)
end

def resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values)

Returns:
  • (Array) -

Other tags:
    Yieldreturn: -

Parameters:
  • resolved_generic_values (Hash{String => ComplexType}) --
  • context_type (UniqueType) --
  • generics_to_resolve (Enumerable) --
def resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values)
  types = yield self
  types.each_with_index.flat_map do |ct, i|
    ct.items.flat_map do |ut|
      context_params = yield context_type if context_type
      if context_params && context_params[i]
        type_arg = context_params[i]
        type_arg.map do |new_unique_context_type|
          ut.resolve_generics_from_context generics_to_resolve, new_unique_context_type, resolved_generic_values: resolved_generic_values
        end
      else
        ut.resolve_generics_from_context generics_to_resolve, nil, resolved_generic_values: resolved_generic_values
      end
    end
  end
end

def rooted?

def rooted?
  !can_root_name? || @rooted
end

def rooted_tags

Returns:
  • (String) -
def rooted_tags
  rooted_tag
end

def self_to_type dst

Returns:
  • (self) -

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?
  @name == 'self' || @key_types.any?(&:selfy?) || @subtypes.any?(&:selfy?)
end

def tags

Returns:
  • (String) -
def tags
  tag
end

def to_a

Returns:
  • (Array) -
def to_a
  [self]
end

def to_rbs

Returns:
  • (String) -
def to_rbs
  if duck_type?
    'untyped'
  elsif name == 'Boolean'
    'bool'
  elsif name.downcase == 'nil'
    'nil'
  elsif name == GENERIC_TAG_NAME
    all_params.first.name
  elsif ['Class', 'Module'].include?(name)
    rbs_name
  elsif ['Tuple', 'Array'].include?(name) && fixed_parameters?
    # tuples don't have a name; they're just [foo, bar, baz].

    if substring == '()'
      # but there are no zero element tuples, so we go with an array

      if rooted?
        '::Array[]'
      else
        'Array[]'
      end
    else
      # already generated surrounded by []

      parameters_as_rbs
    end
  else
    "#{rbs_name}#{parameters_as_rbs}"
  end
end

def to_s

def to_s
  tag
end

def transform(new_name = nil, &transform_type)

Returns:
  • (self) -

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?('::')
  if name == ComplexType::GENERIC_TAG_NAME
    # doesn't make sense to manipulate the name of the generic

    new_key_types = @key_types
    new_subtypes = @subtypes
  else
    new_key_types = @key_types.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
    new_subtypes = @subtypes.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
  end
  new_type = recreate(new_name: new_name || name, new_key_types: new_key_types, new_subtypes: new_subtypes, make_rooted: @rooted)
  yield new_type
end