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

# class TypeProf::Core::EscapeBox::HashSplatBox::MethodDefBox

### Attributes

cpath[R]
f_args[R]
mid[R]
node[RW]
ret[R]
singleton[R]

### Public Class Methods

new(node, genv, cpath, singleton, mid, f_args, ret_boxes) click to toggle source
Calls superclass method `TypeProf::Core::Box::new`

    # File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 336
    def initialize(node, genv, cpath, singleton, mid, f_args, ret_boxes)
      super(node)
      @cpath = cpath
      @singleton = singleton
      @mid = mid
      raise unless f_args
      @f_args = f_args
      raise unless f_args.is_a?(FormalArguments)

      @record_block = RecordBlock.new(@node)
      if @f_args.block
        record_blk_ty = Source.new(Type::Proc.new(genv, @record_block))
        record_blk_ty.add_edge(genv, @f_args.block)
      end

      @ret_boxes = ret_boxes
      @ret = Vertex.new(node)
      ret_boxes.each do |box|
        @changes.add_edge(genv, box.ret, @ret)
      end
      me = genv.resolve_method(@cpath, @singleton, @mid)
      me.add_def(self)
      if me.decls.empty?
        me.add_run_all_method_call_boxes(genv)
      else
        genv.add_run(self)
      end
    end

### Public Instance Methods

call(changes, genv, a_args, ret) click to toggle source

    # File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 556
    def call(changes, genv, a_args, ret)
      if pass_arguments(changes, genv, a_args)
        changes.add_edge(genv, a_args.block, @f_args.block) if @f_args.block && a_args.block

        changes.add_edge(genv, @ret, ret)
      end
    end

destroy(genv) click to toggle source
Calls superclass method `TypeProf::Core::Box#destroy`

    # File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 369
    def destroy(genv)
      me = genv.resolve_method(@cpath, @singleton, @mid)
      me.remove_def(self)
      if me.decls.empty?
        me.add_run_all_method_call_boxes(genv)
      else
        genv.add_run(self)
      end
      super(genv)
    end

pass_arguments(changes, genv, a_args) click to toggle source

    # File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 439
    def pass_arguments(changes, genv, a_args)
      if a_args.splat_flags.any?
        # there is at least one splat actual argument

        lower = @f_args.req_positionals.size + @f_args.post_positionals.size
        upper = @f_args.rest_positionals ? nil : lower + @f_args.opt_positionals.size
        if upper && upper < a_args.positionals.size
          meth = changes.node.mid_code_range ? :mid_code_range : :code_range
          err = "#{ a_args.positionals.size } for #{ lower }#{ upper ? lower < upper ? "...#{ upper }" : "" : "+" }"
          changes.add_diagnostic(meth, "wrong number of arguments (#{ err })")
          return false
        end

        start_rest = [a_args.splat_flags.index(true), @f_args.req_positionals.size + @f_args.opt_positionals.size].min
        end_rest = [a_args.splat_flags.rindex(true) + 1, a_args.positionals.size - @f_args.post_positionals.size].max
        rest_vtxs = a_args.get_rest_args(genv, start_rest, end_rest)

        @f_args.req_positionals.each_with_index do |f_vtx, i|
          if i < start_rest
            changes.add_edge(genv, a_args.positionals[i], f_vtx)
          else
            rest_vtxs.each do |vtx|
              changes.add_edge(genv, vtx, f_vtx)
            end
          end
        end
        @f_args.opt_positionals.each_with_index do |f_vtx, i|
          i += @f_args.opt_positionals.size
          if i < start_rest
            changes.add_edge(genv, a_args.positionals[i], f_vtx)
          else
            rest_vtxs.each do |vtx|
              changes.add_edge(genv, vtx, f_vtx)
            end
          end
        end
        @f_args.post_positionals.each_with_index do |f_vtx, i|
          i += a_args.positionals.size - @f_args.post_positionals.size
          if end_rest <= i
            changes.add_edge(genv, a_args.positionals[i], f_vtx)
          else
            rest_vtxs.each do |vtx|
              changes.add_edge(genv, vtx, f_vtx)
            end
          end
        end

        if @f_args.rest_positionals
          rest_vtxs.each do |vtx|
            @f_args.rest_positionals.each_type do |ty|
              if ty.is_a?(Type::Instance) && ty.mod == genv.mod_ary && ty.args[0]
                changes.add_edge(genv, vtx, ty.args[0])
              end
            end
          end
        end
      else
        # there is no splat actual argument

        lower = @f_args.req_positionals.size + @f_args.post_positionals.size
        upper = @f_args.rest_positionals ? nil : lower + @f_args.opt_positionals.size
        if a_args.positionals.size < lower || (upper && upper < a_args.positionals.size)
          meth = changes.node.mid_code_range ? :mid_code_range : :code_range
          err = "#{ a_args.positionals.size } for #{ lower }#{ upper ? lower < upper ? "...#{ upper }" : "" : "+" }"
          changes.add_diagnostic(meth, "wrong number of arguments (#{ err })")
          return false
        end

        @f_args.req_positionals.each_with_index do |f_vtx, i|
          changes.add_edge(genv, a_args.positionals[i], f_vtx)
        end
        @f_args.post_positionals.each_with_index do |f_vtx, i|
          i -= @f_args.post_positionals.size
          changes.add_edge(genv, a_args.positionals[i], f_vtx)
        end
        start_rest = @f_args.req_positionals.size
        end_rest = a_args.positionals.size - @f_args.post_positionals.size
        i = 0
        while i < @f_args.opt_positionals.size && start_rest < end_rest
          f_arg = @f_args.opt_positionals[i]
          changes.add_edge(genv, a_args.positionals[start_rest], f_arg)
          i += 1
          start_rest += 1
        end

        if start_rest < end_rest
          if @f_args.rest_positionals
            (start_rest..end_rest-1).each do |i|
              @f_args.rest_positionals.each_type do |ty|
                if ty.is_a?(Type::Instance) && ty.mod == genv.mod_ary && ty.args[0]
                  changes.add_edge(genv, a_args.positionals[i], ty.args[0])
                end
              end
            end
          end
        end
      end

      if a_args.keywords
        # TODO: support diagnostics
        @node.req_keywords.zip(@f_args.req_keywords) do |name, f_vtx|
          changes.add_edge(genv, a_args.get_keyword_arg(genv, changes, name), f_vtx)
        end

        @node.opt_keywords.zip(@f_args.opt_keywords).each do |name, f_vtx|
          changes.add_edge(genv, a_args.get_keyword_arg(genv, changes, name), f_vtx)
        end

        if @node.rest_keywords
          # FIXME: Extract the rest keywords excluding req_keywords and opt_keywords.
          changes.add_edge(genv, a_args.keywords, @f_args.rest_keywords)
        end
      end

      return true
    end

run0(genv, changes) click to toggle source

    # File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 380
    def run0(genv, changes)
      me = genv.resolve_method(@cpath, @singleton, @mid)
      return if me.decls.empty?

      # TODO: support "| ..."
      decl = me.decls.to_a.first
      # TODO: support overload?
      method_type = decl.method_types.first
      _block = method_type.block

      mod = genv.resolve_cpath(@cpath)
      if @singleton
        ty = Type::Singleton.new(genv, mod)
        param_map0 = Type.default_param_map(genv, ty)
      else
        type_params = mod.type_params.map {|ty_param| Source.new() } # TODO: better support
        ty = Type::Instance.new(genv, mod, type_params)
        param_map0 = Type.default_param_map(genv, ty)
        if ty.is_a?(Type::Instance)
          ty.mod.type_params.zip(ty.args) do |param, arg|
            param_map0[param] = arg
          end
        end
      end
      method_type.type_params.each do |param|
        param_map0[param] = Source.new()
      end

      positional_args = []
      splat_flags = []

      method_type.req_positionals.each do |a_arg|
        positional_args << a_arg.contravariant_vertex(genv, changes, param_map0)
        splat_flags << false
      end
      method_type.opt_positionals.each do |a_arg|
        positional_args << a_arg.contravariant_vertex(genv, changes, param_map0)
        splat_flags << false
      end
      if method_type.rest_positionals
        elems = method_type.rest_positionals.contravariant_vertex(genv, changes, param_map0)
        positional_args << Source.new(genv.gen_ary_type(elems))
        splat_flags << true
      end
      method_type.post_positionals.each do |a_arg|
        positional_args << a_arg.contravariant_vertex(genv, changes, param_map0)
        splat_flags << false
      end

      a_args = ActualArguments.new(positional_args, splat_flags, nil, nil) # TODO: keywords and block
      if pass_arguments(changes, genv, a_args)
        # TODO: block
        f_ret = method_type.return_type.contravariant_vertex(genv, changes, param_map0)
        @ret_boxes.each do |ret_box|
          changes.add_edge(genv, f_ret, ret_box.f_ret)
        end
      end
    end

show(output_parameter_names) click to toggle source

    # File typeprof-0.30.1/lib/typeprof/core/graph/box.rb, line 564
    def show(output_parameter_names)
      block_show = []
      if @record_block.used
        blk_f_args = @record_block.f_args.map {|arg| arg.show }.join(", ")
        blk_ret = @record_block.ret.show
        block_show << "{ (#{ blk_f_args }) -> #{ blk_ret } }"
      end
      args = []
      @f_args.req_positionals.each do |f_vtx|
        args << Type.strip_parens(f_vtx.show)
      end
      @f_args.opt_positionals.each do |f_vtx|
        args << ("?" + Type.strip_parens(f_vtx.show))
      end
      if @f_args.rest_positionals
        args << ("*" + Type.strip_array(Type.strip_parens(@f_args.rest_positionals.show)))
      end
      @f_args.post_positionals.each do |var|
        args << Type.strip_parens(var.show)
      end
      if @node.is_a?(AST::DefNode)
        @node.req_keywords.zip(@f_args.req_keywords) do |name, f_vtx|
          args << "#{ name }: #{Type.strip_parens(f_vtx.show)}"
        end
        @node.opt_keywords.zip(@f_args.opt_keywords) do |name, f_vtx|
          args << "?#{ name }: #{Type.strip_parens(f_vtx.show)}"
        end
      end
      if @f_args.rest_keywords
        args << "**#{ Type.strip_parens(@f_args.rest_keywords.show) }"
      end

      if output_parameter_names && @node.is_a?(AST::DefNode)
        names = []
        names.concat(@node.req_positionals)
        names.concat(@node.opt_positionals)
        names.concat(@node.rest_positionals) if @node.rest_positionals
        names.concat(@node.post_positionals)
        names.concat(@node.req_keywords)
        names.concat(@node.opt_keywords)
        names.concat(@node.rest_keywords) if @node.rest_keywords
        args = args.zip(names).map do |arg, name|
          name ? "#{ arg } #{ name }" : arg
        end
      end

      args = args.join(", ")
      s = args.empty? ? [] : ["(#{ args })"]
      s << "#{ block_show.sort.join(" | ") }" unless block_show.empty?
      s << "-> #{ @ret.show }"
      s.join(" ")
    end