class TypeProf::Core::EscapeBox::HashSplatBox::MethodCallBox

Attributes

mid[R]
recv[R]
ret[R]

Public Class Methods

new(node, genv, recv, mid, a_args, subclasses) click to toggle source
Calls superclass method TypeProf::Core::Box::new
# File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 657
def initialize(node, genv, recv, mid, a_args, subclasses)
  raise mid.to_s unless mid
  super(node)
  @recv = recv.new_vertex(genv, node)
  @recv.add_edge(genv, self)
  @mid = mid
  @a_args = a_args.new_vertexes(genv, node)
  @a_args.positionals.each {|arg| arg.add_edge(genv, self) }
  @a_args.keywords.add_edge(genv, self) if @a_args.keywords
  @a_args.block.add_edge(genv, self) if @a_args.block
  @ret = Vertex.new(node)
  @subclasses = subclasses
  @generics = {}
end

Public Instance Methods

resolve(genv, changes) { |me, ty, mid, orig_ty| ... } click to toggle source
# File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 734
def resolve(genv, changes, &blk)
  @recv.each_type do |orig_ty|
    next if orig_ty == Type::Bot.new(genv)
    if @mid == :"*super"
      mid = @node.lenv.cref.mid
      skip = true
    else
      mid = @mid
      skip = false
    end

    ty = orig_ty.base_type(genv)

    base_ty_env = Type.default_param_map(genv, ty)

    alias_limit = 0
    while ty
      unless skip
        me = ty.mod.get_method(ty.is_a?(Type::Singleton), mid)
        changes.add_depended_method_entity(me) if changes
        if !me.aliases.empty?
          mid = me.aliases.values.first
          alias_limit += 1
          redo if alias_limit < 5
        end
        if me.exist?
          yield me, ty, mid, orig_ty
          break
        end
      end

      skip = false

      if ty.is_a?(Type::Singleton)
        # TODO: extended modules
      else
        break if resolve_included_modules(genv, changes, base_ty_env, ty, mid) do |me, ty, mid|
          yield me, ty, mid, orig_ty
        end
      end

      ty = genv.get_superclass_type(ty, changes, base_ty_env)
    end

    yield nil, nil, mid, orig_ty unless ty
  end
end
resolve_included_modules(genv, changes, base_ty_env, ty, mid) { |me, self_ty, mid| ... } click to toggle source
# File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 782
def resolve_included_modules(genv, changes, base_ty_env, ty, mid, &blk)
  found = false

  alias_limit = 0
  ty.mod.self_types.each do |(mdecl, idx), self_ty_mod|
    raise unless mdecl.is_a?(AST::SigModuleNode)
    if self_ty_mod.type_params
      self_ty = genv.get_instance_type(self_ty_mod, mdecl.self_type_args[idx], changes, base_ty_env, ty)
    else
      self_ty = Type::Instance.new(genv, self_ty_mod, [])
    end

    me = self_ty.mod.get_method(false, mid)
    changes.add_depended_method_entity(me) if changes
    if !me.aliases.empty?
      mid = me.aliases.values.first
      alias_limit += 1
      redo if alias_limit < 5
    end
    if me.exist?
      found = true
      yield me, self_ty, mid
    else
      found ||= resolve_included_modules(genv, changes, base_ty_env, self_ty, mid, &blk)
    end
  end

  alias_limit = 0
  ty.mod.included_modules.each do |inc_decl, inc_mod|
    if inc_decl.is_a?(AST::SigIncludeNode) && inc_mod.type_params
      inc_ty = genv.get_instance_type(inc_mod, inc_decl.args, changes, base_ty_env, ty)
    else
      type_params = inc_mod.type_params.map {|ty_param| Source.new() } # TODO: better support
      inc_ty = Type::Instance.new(genv, inc_mod, type_params)
    end

    me = inc_ty.mod.get_method(false, mid)
    changes.add_depended_method_entity(me) if changes
    if !me.aliases.empty?
      mid = me.aliases.values.first
      alias_limit += 1
      redo if alias_limit < 5
    end
    if me.exist?
      found = true
      yield me, inc_ty, mid
    else
      found ||= resolve_included_modules(genv, changes, base_ty_env, inc_ty, mid, &blk)
    end
  end
  found
end
resolve_subclasses(genv, changes) { |ty, me| ... } click to toggle source
# File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 835
def resolve_subclasses(genv, changes)
  # TODO: This does not follow new subclasses
  @recv.each_type do |ty|
    next if ty == Type::Bot.new(genv)
    base_ty = ty.base_type(genv)
    singleton = base_ty.is_a?(Type::Singleton)
    mod = base_ty.mod
    mod.each_descendant do |desc_mod|
      next if mod == desc_mod
      me = desc_mod.get_method(singleton, @mid)
      changes.add_depended_method_entity(me)
      if me && me.exist?
        yield ty, me
      end
    end
  end
end
run0(genv, changes) click to toggle source
# File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 674
def run0(genv, changes)
  edges = Set[]
  called_mdefs = Set[]
  error_count = 0
  resolve(genv, changes) do |me, ty, mid, orig_ty|
    if !me
      # TODO: undefined method error
      if error_count < 3
        meth = @node.mid_code_range ? :mid_code_range : :code_range
        changes.add_diagnostic(meth, "undefined method: #{ orig_ty.show }##{ mid }")
      end
      error_count += 1
    elsif me.builtin && me.builtin[changes, @node, orig_ty, @a_args, @ret]
      # do nothing
    elsif !me.decls.empty?
      # TODO: support "| ..."
      me.decls.each do |mdecl|
        # TODO: union type is ok?
        # TODO: add_depended_method_entity for types used to resolve overloads
        ty_env = Type.default_param_map(genv, orig_ty)
        if ty.is_a?(Type::Instance)
          ty.mod.type_params.zip(ty.args) do |param, arg|
            ty_env[param] = arg
          end
        end
        mdecl.resolve_overloads(changes, genv, @node, ty_env, @a_args, @ret) do |method_type|
          @generics[method_type] ||= method_type.type_params.map {|var| Vertex.new(@node) }
        end
      end
    elsif !me.defs.empty?
      me.defs.each do |mdef|
        next if called_mdefs.include?(mdef)
        called_mdefs << mdef
        mdef.call(changes, genv, @a_args, @ret)
      end
    else
      pp me
      raise
    end
  end
  if @subclasses
    resolve_subclasses(genv, changes) do |recv_ty, me|
      if !me.defs.empty?
        me.defs.each do |mdef|
          next if called_mdefs.include?(mdef)
          called_mdefs << mdef
          mdef.call(changes, genv, @a_args, @ret)
        end
      end
    end
  end
  edges.each do |src, dst|
    changes.add_edge(genv, src, dst)
  end
  if error_count > 3
    meth = @node.mid_code_range ? :mid_code_range : :code_range
    changes.add_diagnostic(meth, "... and other #{ error_count - 3 } errors")
  end
end