class IRB::TypeCompletion::RootScope::Scope

Constants

BREAK_RESULT
NEXT_RESULT
PATTERNMATCH_BREAK
RETURN_RESULT

Attributes

level[R]
mergeable_changes[R]
module_nesting[R]
parent[R]

Public Class Methods

from_binding(binding, locals) click to toggle source
# File irb/type_completion/scope.rb, line 113
    def self.from_binding(binding, locals) = new(RootScope.new(binding, binding.receiver, locals))

    def initialize(parent, table = {}, trace_ivar: true, trace_lvar: true, self_type: nil, nesting: nil)
      @parent = parent
      @level = parent.level + 1
      @trace_ivar = trace_ivar
      @trace_lvar = trace_lvar
      @module_nesting = nesting ? [nesting, *parent.module_nesting] : parent.module_nesting
      @self_type = self_type
      @terminated = false
      @jump_branches = []
      @mergeable_changes = @table = table.transform_values { [level, _1] }
    end

    def mutable? = true

    def terminated?
      @terminated
    end

    def terminate_with(type, value)
      return if terminated?
      store_jump type, value, @mergeable_changes
      terminate
    end

    def store_jump(type, value, changes)
      return if terminated?
      if has_own?(type)
        changes[type] = [level, value]
        @jump_branches << changes
      elsif @parent.mutable?
        @parent.store_jump(type, value, changes)
      end
    end

    def terminate
      return if terminated?
      @terminated = true
      @table = @mergeable_changes.dup
    end

    def trace?(name)
      return false unless @parent
      type = RootScope.type_by_name(name)
      type == :ivar ? @trace_ivar : type == :lvar ? @trace_lvar : true
    end

    def level_of(name, var_type)
      case var_type
      when :ivar
        return level unless @trace_ivar
      when :gvar
        return 0
      end
      variable_level, = @table[name]
      variable_level || parent.level_of(name, var_type)
    end

    def get_const(nesting, path, key = nil)
      key ||= [nesting.__id__, path].join('::')
      _l, value = @table[key]
      value || @parent.get_const(nesting, path, key)
    end

    def get_cvar(nesting, path, name, key = nil)
      key ||= [name, nesting.__id__, path].join('::')
      _l, value = @table[key]
      value || @parent.get_cvar(nesting, path, name, key)
    end

    def [](name)
      type = RootScope.type_by_name(name)
      if type == :const
        return get_const(nil, nil, name) || Types::NIL if name.include?('::')

        module_nesting.each do |(nesting, path)|
          value = get_const nesting, [*path, name]
          return value if value
        end
        return Types::NIL
      elsif type == :cvar
        return get_cvar(nil, nil, nil, name) if name.include?('::')

        nesting, path = module_nesting.first
        return get_cvar(nesting, path, name)
      end
      level, value = @table[name]
      if level
        value
      elsif trace? name
        @parent[name]
      elsif type == :ivar
        self_instance_variable_get name
      end
    end

    def set_const(nesting, path, value)
      key = [nesting.__id__, path].join('::')
      @table[key] = [0, value]
    end

    def set_cvar(nesting, path, name, value)
      key = [name, nesting.__id__, path].join('::')
      @table[key] = [0, value]
    end

    def []=(name, value)
      type = RootScope.type_by_name(name)
      if type == :const
        if name.include?('::')
          @table[name] = [0, value]
        else
          parent_module, parent_path = module_nesting.first
          set_const parent_module, [*parent_path, name], value
        end
        return
      elsif type == :cvar
        if name.include?('::')
          @table[name] = [0, value]
        else
          parent_module, parent_path = module_nesting.first
          set_cvar parent_module, parent_path, name, value
        end
        return
      end
      variable_level = level_of name, type
      @table[name] = [variable_level, value] if variable_level
    end

    def self_type
      @self_type || @parent.self_type
    end

    def global_variables
      gvar_keys = @table.keys.select do |name|
        RootScope.type_by_name(name) == :gvar
      end
      gvar_keys | @parent.global_variables
    end

    def local_variables
      lvar_keys = @table.keys.select do |name|
        RootScope.type_by_name(name) == :lvar
      end
      lvar_keys |= @parent.local_variables if @trace_lvar
      lvar_keys
    end

    def table_constants
      constants = module_nesting.flat_map do |mod, path|
        prefix = [mod.__id__, *path].join('::') + '::'
        @table.keys.select { _1.start_with? prefix }.map { _1.delete_prefix(prefix).split('::').first }
      end.uniq
      constants |= @parent.table_constants if @parent.mutable?
      constants
    end

    def table_module_constants(mod)
      prefix = "#{mod.__id__}::"
      constants = @table.keys.select { _1.start_with? prefix }.map { _1.delete_prefix(prefix).split('::').first }
      constants |= @parent.table_constants if @parent.mutable?
      constants
    end

    def base_scope
      @parent.mutable? ? @parent.base_scope : @parent
    end

    def table_instance_variables
      ivars = @table.keys.select { RootScope.type_by_name(_1) == :ivar }
      ivars |= @parent.table_instance_variables if @parent.mutable? && @trace_ivar
      ivars
    end

    def instance_variables
      self_singleton_types = self_type.types.grep(Types::SingletonType)
      singleton_classes = self_type.types.grep(Types::InstanceType).map(&:klass).select(&:singleton_class?)
      base_self = base_scope.self_object
      self_instance_variables = singleton_classes.flat_map do |singleton_class|
        if singleton_class.respond_to? :attached_object
          Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(singleton_class.attached_object).map(&:to_s)
        elsif singleton_class == Methods::OBJECT_SINGLETON_CLASS_METHOD.bind_call(base_self)
          Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(base_self).map(&:to_s)
        else
          []
        end
      end
      [
        self_singleton_types.flat_map { _1.module_or_class.instance_variables.map(&:to_s) },
        self_instance_variables || [],
        table_instance_variables
      ].inject(:|)
    end

    def self_instance_variable_get(name)
      self_objects = self_type.types.grep(Types::SingletonType).map(&:module_or_class)
      singleton_classes = self_type.types.grep(Types::InstanceType).map(&:klass).select(&:singleton_class?)
      base_self = base_scope.self_object
      singleton_classes.each do |singleton_class|
        if singleton_class.respond_to? :attached_object
          self_objects << singleton_class.attached_object
        elsif singleton_class == base_self.singleton_class
          self_objects << base_self
        end
      end
      types = self_objects.map do |object|
        value = begin
          Methods::OBJECT_INSTANCE_VARIABLE_GET_METHOD.bind_call(object, name)
        rescue NameError
        end
        Types.type_from_object value
      end
      Types::UnionType[*types]
    end

    def table_class_variables
      cvars = @table.keys.filter_map { _1.split('::', 2).first if RootScope.type_by_name(_1) == :cvar }
      cvars |= @parent.table_class_variables if @parent.mutable?
      cvars
    end

    def class_variables
      cvars = table_class_variables
      m, = module_nesting.first
      cvars |= m.class_variables.map(&:to_s) if m.is_a? Module
      cvars
    end

    def constants
      module_nesting.flat_map do |nest,|
        nest.constants
      end.map(&:to_s) | table_constants
    end

    def merge_jumps
      if terminated?
        @terminated = false
        @table = @mergeable_changes
        merge @jump_branches
        @terminated = true
      else
        merge [*@jump_branches, {}]
      end
    end

    def conditional(&block)
      run_branches(block, ->(_s) {}).first || Types::NIL
    end

    def never(&block)
      block.call Scope.new(self, { BREAK_RESULT => nil, NEXT_RESULT => nil, PATTERNMATCH_BREAK => nil, RETURN_RESULT => nil })
    end

    def run_branches(*blocks)
      results = []
      branches = []
      blocks.each do |block|
        scope = Scope.new self
        result = block.call scope
        next if scope.terminated?
        results << result
        branches << scope.mergeable_changes
      end
      terminate if branches.empty?
      merge branches
      results
    end

    def has_own?(name)
      @table.key? name
    end

    def update(child_scope)
      current_level = level
      child_scope.mergeable_changes.each do |name, (level, value)|
        self[name] = value if level <= current_level
      end
    end

    protected

    def merge(branches)
      current_level = level
      merge = {}
      branches.each do |changes|
        changes.each do |name, (level, value)|
          next if current_level < level
          (merge[name] ||= []) << value
        end
      end
      merge.each do |name, values|
        values << self[name] unless values.size == branches.size
        values.compact!
        self[name] = Types::UnionType[*values.compact] unless values.empty?
      end
    end
  end
end
new(parent, table = {}, trace_ivar: true, trace_lvar: true, self_type: nil, nesting: nil) click to toggle source
# File irb/type_completion/scope.rb, line 115
def initialize(parent, table = {}, trace_ivar: true, trace_lvar: true, self_type: nil, nesting: nil)
  @parent = parent
  @level = parent.level + 1
  @trace_ivar = trace_ivar
  @trace_lvar = trace_lvar
  @module_nesting = nesting ? [nesting, *parent.module_nesting] : parent.module_nesting
  @self_type = self_type
  @terminated = false
  @jump_branches = []
  @mergeable_changes = @table = table.transform_values { [level, _1] }
end

Public Instance Methods

[](name) click to toggle source
# File irb/type_completion/scope.rb, line 184
def [](name)
  type = RootScope.type_by_name(name)
  if type == :const
    return get_const(nil, nil, name) || Types::NIL if name.include?('::')

    module_nesting.each do |(nesting, path)|
      value = get_const nesting, [*path, name]
      return value if value
    end
    return Types::NIL
  elsif type == :cvar
    return get_cvar(nil, nil, nil, name) if name.include?('::')

    nesting, path = module_nesting.first
    return get_cvar(nesting, path, name)
  end
  level, value = @table[name]
  if level
    value
  elsif trace? name
    @parent[name]
  elsif type == :ivar
    self_instance_variable_get name
  end
end
[]=(name, value) click to toggle source
# File irb/type_completion/scope.rb, line 220
def []=(name, value)
  type = RootScope.type_by_name(name)
  if type == :const
    if name.include?('::')
      @table[name] = [0, value]
    else
      parent_module, parent_path = module_nesting.first
      set_const parent_module, [*parent_path, name], value
    end
    return
  elsif type == :cvar
    if name.include?('::')
      @table[name] = [0, value]
    else
      parent_module, parent_path = module_nesting.first
      set_cvar parent_module, parent_path, name, value
    end
    return
  end
  variable_level = level_of name, type
  @table[name] = [variable_level, value] if variable_level
end
base_scope() click to toggle source
# File irb/type_completion/scope.rb, line 278
def base_scope
  @parent.mutable? ? @parent.base_scope : @parent
end
class_variables() click to toggle source
# File irb/type_completion/scope.rb, line 335
def class_variables
  cvars = table_class_variables
  m, = module_nesting.first
  cvars |= m.class_variables.map(&:to_s) if m.is_a? Module
  cvars
end
conditional(&block) click to toggle source
# File irb/type_completion/scope.rb, line 359
def conditional(&block)
  run_branches(block, ->(_s) {}).first || Types::NIL
end
constants() click to toggle source
# File irb/type_completion/scope.rb, line 342
def constants
  module_nesting.flat_map do |nest,|
    nest.constants
  end.map(&:to_s) | table_constants
end
get_const(nesting, path, key = nil) click to toggle source
# File irb/type_completion/scope.rb, line 172
def get_const(nesting, path, key = nil)
  key ||= [nesting.__id__, path].join('::')
  _l, value = @table[key]
  value || @parent.get_const(nesting, path, key)
end
get_cvar(nesting, path, name, key = nil) click to toggle source
# File irb/type_completion/scope.rb, line 178
def get_cvar(nesting, path, name, key = nil)
  key ||= [name, nesting.__id__, path].join('::')
  _l, value = @table[key]
  value || @parent.get_cvar(nesting, path, name, key)
end
global_variables() click to toggle source
# File irb/type_completion/scope.rb, line 247
def global_variables
  gvar_keys = @table.keys.select do |name|
    RootScope.type_by_name(name) == :gvar
  end
  gvar_keys | @parent.global_variables
end
has_own?(name) click to toggle source
# File irb/type_completion/scope.rb, line 382
def has_own?(name)
  @table.key? name
end
instance_variables() click to toggle source
# File irb/type_completion/scope.rb, line 288
def instance_variables
  self_singleton_types = self_type.types.grep(Types::SingletonType)
  singleton_classes = self_type.types.grep(Types::InstanceType).map(&:klass).select(&:singleton_class?)
  base_self = base_scope.self_object
  self_instance_variables = singleton_classes.flat_map do |singleton_class|
    if singleton_class.respond_to? :attached_object
      Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(singleton_class.attached_object).map(&:to_s)
    elsif singleton_class == Methods::OBJECT_SINGLETON_CLASS_METHOD.bind_call(base_self)
      Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(base_self).map(&:to_s)
    else
      []
    end
  end
  [
    self_singleton_types.flat_map { _1.module_or_class.instance_variables.map(&:to_s) },
    self_instance_variables || [],
    table_instance_variables
  ].inject(:|)
end
level_of(name, var_type) click to toggle source
# File irb/type_completion/scope.rb, line 161
def level_of(name, var_type)
  case var_type
  when :ivar
    return level unless @trace_ivar
  when :gvar
    return 0
  end
  variable_level, = @table[name]
  variable_level || parent.level_of(name, var_type)
end
local_variables() click to toggle source
# File irb/type_completion/scope.rb, line 254
def local_variables
  lvar_keys = @table.keys.select do |name|
    RootScope.type_by_name(name) == :lvar
  end
  lvar_keys |= @parent.local_variables if @trace_lvar
  lvar_keys
end
merge(branches) click to toggle source
# File irb/type_completion/scope.rb, line 395
def merge(branches)
  current_level = level
  merge = {}
  branches.each do |changes|
    changes.each do |name, (level, value)|
      next if current_level < level
      (merge[name] ||= []) << value
    end
  end
  merge.each do |name, values|
    values << self[name] unless values.size == branches.size
    values.compact!
    self[name] = Types::UnionType[*values.compact] unless values.empty?
  end
end
merge_jumps() click to toggle source
# File irb/type_completion/scope.rb, line 348
def merge_jumps
  if terminated?
    @terminated = false
    @table = @mergeable_changes
    merge @jump_branches
    @terminated = true
  else
    merge [*@jump_branches, {}]
  end
end
mutable?(= true) click to toggle source
# File irb/type_completion/scope.rb, line 127
  def mutable? = true

  def terminated?
    @terminated
  end

  def terminate_with(type, value)
    return if terminated?
    store_jump type, value, @mergeable_changes
    terminate
  end

  def store_jump(type, value, changes)
    return if terminated?
    if has_own?(type)
      changes[type] = [level, value]
      @jump_branches << changes
    elsif @parent.mutable?
      @parent.store_jump(type, value, changes)
    end
  end

  def terminate
    return if terminated?
    @terminated = true
    @table = @mergeable_changes.dup
  end

  def trace?(name)
    return false unless @parent
    type = RootScope.type_by_name(name)
    type == :ivar ? @trace_ivar : type == :lvar ? @trace_lvar : true
  end

  def level_of(name, var_type)
    case var_type
    when :ivar
      return level unless @trace_ivar
    when :gvar
      return 0
    end
    variable_level, = @table[name]
    variable_level || parent.level_of(name, var_type)
  end

  def get_const(nesting, path, key = nil)
    key ||= [nesting.__id__, path].join('::')
    _l, value = @table[key]
    value || @parent.get_const(nesting, path, key)
  end

  def get_cvar(nesting, path, name, key = nil)
    key ||= [name, nesting.__id__, path].join('::')
    _l, value = @table[key]
    value || @parent.get_cvar(nesting, path, name, key)
  end

  def [](name)
    type = RootScope.type_by_name(name)
    if type == :const
      return get_const(nil, nil, name) || Types::NIL if name.include?('::')

      module_nesting.each do |(nesting, path)|
        value = get_const nesting, [*path, name]
        return value if value
      end
      return Types::NIL
    elsif type == :cvar
      return get_cvar(nil, nil, nil, name) if name.include?('::')

      nesting, path = module_nesting.first
      return get_cvar(nesting, path, name)
    end
    level, value = @table[name]
    if level
      value
    elsif trace? name
      @parent[name]
    elsif type == :ivar
      self_instance_variable_get name
    end
  end

  def set_const(nesting, path, value)
    key = [nesting.__id__, path].join('::')
    @table[key] = [0, value]
  end

  def set_cvar(nesting, path, name, value)
    key = [name, nesting.__id__, path].join('::')
    @table[key] = [0, value]
  end

  def []=(name, value)
    type = RootScope.type_by_name(name)
    if type == :const
      if name.include?('::')
        @table[name] = [0, value]
      else
        parent_module, parent_path = module_nesting.first
        set_const parent_module, [*parent_path, name], value
      end
      return
    elsif type == :cvar
      if name.include?('::')
        @table[name] = [0, value]
      else
        parent_module, parent_path = module_nesting.first
        set_cvar parent_module, parent_path, name, value
      end
      return
    end
    variable_level = level_of name, type
    @table[name] = [variable_level, value] if variable_level
  end

  def self_type
    @self_type || @parent.self_type
  end

  def global_variables
    gvar_keys = @table.keys.select do |name|
      RootScope.type_by_name(name) == :gvar
    end
    gvar_keys | @parent.global_variables
  end

  def local_variables
    lvar_keys = @table.keys.select do |name|
      RootScope.type_by_name(name) == :lvar
    end
    lvar_keys |= @parent.local_variables if @trace_lvar
    lvar_keys
  end

  def table_constants
    constants = module_nesting.flat_map do |mod, path|
      prefix = [mod.__id__, *path].join('::') + '::'
      @table.keys.select { _1.start_with? prefix }.map { _1.delete_prefix(prefix).split('::').first }
    end.uniq
    constants |= @parent.table_constants if @parent.mutable?
    constants
  end

  def table_module_constants(mod)
    prefix = "#{mod.__id__}::"
    constants = @table.keys.select { _1.start_with? prefix }.map { _1.delete_prefix(prefix).split('::').first }
    constants |= @parent.table_constants if @parent.mutable?
    constants
  end

  def base_scope
    @parent.mutable? ? @parent.base_scope : @parent
  end

  def table_instance_variables
    ivars = @table.keys.select { RootScope.type_by_name(_1) == :ivar }
    ivars |= @parent.table_instance_variables if @parent.mutable? && @trace_ivar
    ivars
  end

  def instance_variables
    self_singleton_types = self_type.types.grep(Types::SingletonType)
    singleton_classes = self_type.types.grep(Types::InstanceType).map(&:klass).select(&:singleton_class?)
    base_self = base_scope.self_object
    self_instance_variables = singleton_classes.flat_map do |singleton_class|
      if singleton_class.respond_to? :attached_object
        Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(singleton_class.attached_object).map(&:to_s)
      elsif singleton_class == Methods::OBJECT_SINGLETON_CLASS_METHOD.bind_call(base_self)
        Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(base_self).map(&:to_s)
      else
        []
      end
    end
    [
      self_singleton_types.flat_map { _1.module_or_class.instance_variables.map(&:to_s) },
      self_instance_variables || [],
      table_instance_variables
    ].inject(:|)
  end

  def self_instance_variable_get(name)
    self_objects = self_type.types.grep(Types::SingletonType).map(&:module_or_class)
    singleton_classes = self_type.types.grep(Types::InstanceType).map(&:klass).select(&:singleton_class?)
    base_self = base_scope.self_object
    singleton_classes.each do |singleton_class|
      if singleton_class.respond_to? :attached_object
        self_objects << singleton_class.attached_object
      elsif singleton_class == base_self.singleton_class
        self_objects << base_self
      end
    end
    types = self_objects.map do |object|
      value = begin
        Methods::OBJECT_INSTANCE_VARIABLE_GET_METHOD.bind_call(object, name)
      rescue NameError
      end
      Types.type_from_object value
    end
    Types::UnionType[*types]
  end

  def table_class_variables
    cvars = @table.keys.filter_map { _1.split('::', 2).first if RootScope.type_by_name(_1) == :cvar }
    cvars |= @parent.table_class_variables if @parent.mutable?
    cvars
  end

  def class_variables
    cvars = table_class_variables
    m, = module_nesting.first
    cvars |= m.class_variables.map(&:to_s) if m.is_a? Module
    cvars
  end

  def constants
    module_nesting.flat_map do |nest,|
      nest.constants
    end.map(&:to_s) | table_constants
  end

  def merge_jumps
    if terminated?
      @terminated = false
      @table = @mergeable_changes
      merge @jump_branches
      @terminated = true
    else
      merge [*@jump_branches, {}]
    end
  end

  def conditional(&block)
    run_branches(block, ->(_s) {}).first || Types::NIL
  end

  def never(&block)
    block.call Scope.new(self, { BREAK_RESULT => nil, NEXT_RESULT => nil, PATTERNMATCH_BREAK => nil, RETURN_RESULT => nil })
  end

  def run_branches(*blocks)
    results = []
    branches = []
    blocks.each do |block|
      scope = Scope.new self
      result = block.call scope
      next if scope.terminated?
      results << result
      branches << scope.mergeable_changes
    end
    terminate if branches.empty?
    merge branches
    results
  end

  def has_own?(name)
    @table.key? name
  end

  def update(child_scope)
    current_level = level
    child_scope.mergeable_changes.each do |name, (level, value)|
      self[name] = value if level <= current_level
    end
  end

  protected

  def merge(branches)
    current_level = level
    merge = {}
    branches.each do |changes|
      changes.each do |name, (level, value)|
        next if current_level < level
        (merge[name] ||= []) << value
      end
    end
    merge.each do |name, values|
      values << self[name] unless values.size == branches.size
      values.compact!
      self[name] = Types::UnionType[*values.compact] unless values.empty?
    end
  end
end
never(&block) click to toggle source
# File irb/type_completion/scope.rb, line 363
def never(&block)
  block.call Scope.new(self, { BREAK_RESULT => nil, NEXT_RESULT => nil, PATTERNMATCH_BREAK => nil, RETURN_RESULT => nil })
end
run_branches(*blocks) click to toggle source
# File irb/type_completion/scope.rb, line 367
def run_branches(*blocks)
  results = []
  branches = []
  blocks.each do |block|
    scope = Scope.new self
    result = block.call scope
    next if scope.terminated?
    results << result
    branches << scope.mergeable_changes
  end
  terminate if branches.empty?
  merge branches
  results
end
self_instance_variable_get(name) click to toggle source
# File irb/type_completion/scope.rb, line 308
def self_instance_variable_get(name)
  self_objects = self_type.types.grep(Types::SingletonType).map(&:module_or_class)
  singleton_classes = self_type.types.grep(Types::InstanceType).map(&:klass).select(&:singleton_class?)
  base_self = base_scope.self_object
  singleton_classes.each do |singleton_class|
    if singleton_class.respond_to? :attached_object
      self_objects << singleton_class.attached_object
    elsif singleton_class == base_self.singleton_class
      self_objects << base_self
    end
  end
  types = self_objects.map do |object|
    value = begin
      Methods::OBJECT_INSTANCE_VARIABLE_GET_METHOD.bind_call(object, name)
    rescue NameError
    end
    Types.type_from_object value
  end
  Types::UnionType[*types]
end
self_type() click to toggle source
# File irb/type_completion/scope.rb, line 243
def self_type
  @self_type || @parent.self_type
end
set_const(nesting, path, value) click to toggle source
# File irb/type_completion/scope.rb, line 210
def set_const(nesting, path, value)
  key = [nesting.__id__, path].join('::')
  @table[key] = [0, value]
end
set_cvar(nesting, path, name, value) click to toggle source
# File irb/type_completion/scope.rb, line 215
def set_cvar(nesting, path, name, value)
  key = [name, nesting.__id__, path].join('::')
  @table[key] = [0, value]
end
store_jump(type, value, changes) click to toggle source
# File irb/type_completion/scope.rb, line 139
def store_jump(type, value, changes)
  return if terminated?
  if has_own?(type)
    changes[type] = [level, value]
    @jump_branches << changes
  elsif @parent.mutable?
    @parent.store_jump(type, value, changes)
  end
end
table_class_variables() click to toggle source
# File irb/type_completion/scope.rb, line 329
def table_class_variables
  cvars = @table.keys.filter_map { _1.split('::', 2).first if RootScope.type_by_name(_1) == :cvar }
  cvars |= @parent.table_class_variables if @parent.mutable?
  cvars
end
table_constants() click to toggle source
# File irb/type_completion/scope.rb, line 262
def table_constants
  constants = module_nesting.flat_map do |mod, path|
    prefix = [mod.__id__, *path].join('::') + '::'
    @table.keys.select { _1.start_with? prefix }.map { _1.delete_prefix(prefix).split('::').first }
  end.uniq
  constants |= @parent.table_constants if @parent.mutable?
  constants
end
table_instance_variables() click to toggle source
# File irb/type_completion/scope.rb, line 282
def table_instance_variables
  ivars = @table.keys.select { RootScope.type_by_name(_1) == :ivar }
  ivars |= @parent.table_instance_variables if @parent.mutable? && @trace_ivar
  ivars
end
table_module_constants(mod) click to toggle source
# File irb/type_completion/scope.rb, line 271
def table_module_constants(mod)
  prefix = "#{mod.__id__}::"
  constants = @table.keys.select { _1.start_with? prefix }.map { _1.delete_prefix(prefix).split('::').first }
  constants |= @parent.table_constants if @parent.mutable?
  constants
end
terminate() click to toggle source
# File irb/type_completion/scope.rb, line 149
def terminate
  return if terminated?
  @terminated = true
  @table = @mergeable_changes.dup
end
terminate_with(type, value) click to toggle source
# File irb/type_completion/scope.rb, line 133
def terminate_with(type, value)
  return if terminated?
  store_jump type, value, @mergeable_changes
  terminate
end
terminated?() click to toggle source
# File irb/type_completion/scope.rb, line 129
def terminated?
  @terminated
end
trace?(name) click to toggle source
# File irb/type_completion/scope.rb, line 155
def trace?(name)
  return false unless @parent
  type = RootScope.type_by_name(name)
  type == :ivar ? @trace_ivar : type == :lvar ? @trace_lvar : true
end
update(child_scope) click to toggle source
# File irb/type_completion/scope.rb, line 386
def update(child_scope)
  current_level = level
  child_scope.mergeable_changes.each do |name, (level, value)|
    self[name] = value if level <= current_level
  end
end