class Solargraph::Source::Chain

A chain of constants, variables, and method calls for inferring types of values.

Constants

UNDEFINED_CALL
UNDEFINED_CONSTANT

Attributes

node[R]

Public Class Methods

new(links, node = nil, splat = false) click to toggle source

@param links [Array<Chain::Link>]

# File lib/solargraph/source/chain.rb, line 38
def initialize links, node = nil, splat = false
  @links = links.clone
  @links.push UNDEFINED_CALL if @links.empty?
  head = true
  @links.map! do |link|
    result = (head ? link.clone_head : link.clone_body)
    head = false
    result
  end
  @node = node
  @splat = splat
end

Public Instance Methods

base() click to toggle source

@return [Chain]

# File lib/solargraph/source/chain.rb, line 52
def base
  @base ||= Chain.new(links[0..-2])
end
constant?() click to toggle source

@return [Boolean]

# File lib/solargraph/source/chain.rb, line 97
def constant?
  links.last.is_a?(Chain::Constant)
end
define(api_map, name_pin, locals) click to toggle source

@param api_map [ApiMap] @param name_pin [Pin::Base] @param locals [Array<Pin::Base>] @return [Array<Pin::Base>]

# File lib/solargraph/source/chain.rb, line 60
def define api_map, name_pin, locals
  return [] if undefined?
  working_pin = name_pin
  links[0..-2].each do |link|
    pins = link.resolve(api_map, working_pin, locals)
    type = infer_first_defined(pins, working_pin, api_map)
    return [] if type.undefined?
    working_pin = Pin::ProxyType.anonymous(type)
  end
  links.last.last_context = working_pin
  links.last.resolve(api_map, working_pin, locals)
end
defined?() click to toggle source
# File lib/solargraph/source/chain.rb, line 92
def defined?
  !undefined?
end
infer(api_map, name_pin, locals) click to toggle source

@param api_map [ApiMap] @param name_pin [Pin::Base] @param locals [Array<Pin::Base>] @return [ComplexType]

# File lib/solargraph/source/chain.rb, line 77
def infer api_map, name_pin, locals
  pins = define(api_map, name_pin, locals)
  type = infer_first_defined(pins, links.last.last_context, api_map)
  maybe_nil(type)
end
literal?() click to toggle source

@return [Boolean]

# File lib/solargraph/source/chain.rb, line 84
def literal?
  links.last.is_a?(Chain::Literal)
end
nullable?() click to toggle source
# File lib/solargraph/source/chain.rb, line 105
def nullable?
  links.any?(&:nullable?)
end
splat?() click to toggle source
# File lib/solargraph/source/chain.rb, line 101
def splat?
  @splat
end
undefined?() click to toggle source
# File lib/solargraph/source/chain.rb, line 88
def undefined?
  links.any?(&:undefined?)
end

Private Instance Methods

infer_first_defined(pins, context, api_map) click to toggle source

@param pins [Array<Pin::Base>] @param api_map [ApiMap] @return [ComplexType]

# File lib/solargraph/source/chain.rb, line 114
def infer_first_defined pins, context, api_map
  possibles = []
  pins.each do |pin|
    # Avoid infinite recursion
    next if @@inference_stack.include?(pin.identity)
    @@inference_stack.push pin.identity
    type = pin.typify(api_map)
    @@inference_stack.pop
    if type.defined?
      possibles.push type
      break if pin.is_a?(Pin::Method)
    end
  end
  if possibles.empty?
    # Limit method inference recursion
    return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
    @@inference_depth += 1
    pins.each do |pin|
      # Avoid infinite recursion
      next if @@inference_stack.include?(pin.identity)
      @@inference_stack.push pin.identity
      type = pin.probe(api_map)
      @@inference_stack.pop
      if type.defined?
        possibles.push type
        break if pin.is_a?(Pin::Method)
      end
    end
    @@inference_depth -= 1
  end
  return ComplexType::UNDEFINED if possibles.empty?
  type = if possibles.length > 1
    sorted = possibles.map { |t| t.rooted? ? "::#{t}" : t.to_s }.sort { |a, _| a == 'nil' ? 1 : 0 }
    ComplexType.parse(*sorted)
  else
    possibles.first
  end
  return type if context.nil? || context.return_type.undefined?
  type.self_to(context.return_type.namespace)
end
maybe_nil(type) click to toggle source

@param type [ComplexType]

# File lib/solargraph/source/chain.rb, line 156
def maybe_nil type
  return type if type.undefined? || type.void? || type.nullable?
  return type unless nullable?
  ComplexType.try_parse("#{type}, nil")
end