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