class TypeProf::Core::EscapeBox::HashSplatBox::MethodCallBox - typeprof: Ruby Standard Library Documentation

# 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