class TypeProf::ISeqMethodDef
Attributes
iseq[R]
Public Class Methods
new(iseq, cref, outer_ep, pub_meth)
click to toggle source
# File typeprof-0.21.3/lib/typeprof/method.rb, line 9 def initialize(iseq, cref, outer_ep, pub_meth) @iseq = iseq raise if iseq.nil? @cref = cref @outer_ep = outer_ep @pub_meth = pub_meth end
Public Instance Methods
do_check_send(msig, recv, mid, ep, scratch)
click to toggle source
# File typeprof-0.21.3/lib/typeprof/method.rb, line 52 def do_check_send(msig, recv, mid, ep, scratch) klass, singleton = recv.method_dispatch_info cur_subst = {} direct_method = true scratch.adjust_substitution(klass, singleton, mid, self, recv.generate_substitution) do |subst, direct| direct_method &&= direct cur_subst = Type.merge_substitution(cur_subst, subst) end lead_num = @iseq.fargs_format[:lead_num] || 0 post_num = @iseq.fargs_format[:post_num] || 0 rest_start = @iseq.fargs_format[:rest_start] opt = @iseq.fargs_format[:opt] || [0] # TODO: check keywords if rest_start # almost ok else if msig.rest_ty scratch.error(ep, "RBS says that a rest argument is accepted, but the method definition does not accept one") return end if msig.lead_tys.size + msig.post_tys.size < lead_num + post_num scratch.error(ep, "RBS says that the arity may be %d, but the method definition requires at least %d arguments" % [msig.lead_tys.size + msig.post_tys.size, lead_num + post_num]) return end if msig.lead_tys.size + msig.opt_tys.size + msig.post_tys.size > lead_num + opt.size - 1 + post_num scratch.error(ep, "RBS says that the arity may be %d, but the method definition requires at most %d arguments" % [msig.lead_tys.size + msig.opt_tys.size + msig.post_tys.size, lead_num + opt.size - 1 + post_num]) return end end lead_num = @iseq.fargs_format[:lead_num] || 0 post_start = @iseq.fargs_format[:post_start] kw_start = @iseq.fargs_format[:kwbits] keyword = @iseq.fargs_format[:keyword] kw_start -= keyword.size if kw_start kw_rest = @iseq.fargs_format[:kwrest] block_start = @iseq.fargs_format[:block_start] # XXX: need to check .rbs msig and .rb fargs ctx = Context.new(@iseq, @cref, mid) callee_ep = ExecutionPoint.new(ctx, 0, @outer_ep) locals = [Type.nil] * @iseq.locals.size nenv = Env.new(StaticEnv.new(recv, msig.blk_ty, false, true), locals, [], Utils::HashWrapper.new({})) alloc_site = AllocationSite.new(callee_ep) idx = 0 msig.lead_tys.each_with_index do |ty, i| alloc_site2 = alloc_site.add_id(idx += 1) ty = ty.substitute(cur_subst, Config.current.options[:type_depth_limit]).remove_type_vars nenv, ty = scratch.localize_type(ty, nenv, callee_ep, alloc_site2) nenv = nenv.local_update(i, ty) end if msig.opt_tys msig.opt_tys.each_with_index do |ty, i| alloc_site2 = alloc_site.add_id(idx += 1) ty = ty.substitute(cur_subst, Config.current.options[:type_depth_limit]).remove_type_vars nenv, ty = scratch.localize_type(ty, nenv, callee_ep, alloc_site2) nenv = nenv.local_update(lead_num + i, ty) end end if msig.rest_ty alloc_site2 = alloc_site.add_id(idx += 1) ty = Type::Array.new(Type::Array::Elements.new([], msig.rest_ty), Type::Instance.new(Type::Builtin[:ary])) ty = ty.substitute(cur_subst, Config.current.options[:type_depth_limit]).remove_type_vars nenv, rest_ty = scratch.localize_type(ty, nenv, callee_ep, alloc_site2) nenv = nenv.local_update(rest_start, rest_ty) end if msig.post_tys msig.post_tys.each_with_index do |ty, i| alloc_site2 = alloc_site.add_id(idx += 1) ty = ty.substitute(cur_subst, Config.current.options[:type_depth_limit]).remove_type_vars nenv, ty = scratch.localize_type(ty, nenv, callee_ep, alloc_site2) nenv = nenv.local_update(post_start + i, ty) end end if msig.kw_tys && keyword # TODO: support the case where RBS writes kw_tys and RB method accepts **kwrest msig.kw_tys.each do |_, key, ty| i = keyword.index {|callee_key,| callee_key == key } unless i # warn next end alloc_site2 = alloc_site.add_id(key) ty = ty.substitute(cur_subst, Config.current.options[:type_depth_limit]).remove_type_vars nenv, ty = scratch.localize_type(ty, nenv, callee_ep, alloc_site2) nenv = nenv.local_update(kw_start + i, ty) end end if msig.kw_rest_ty ty = msig.kw_rest_ty alloc_site2 = alloc_site.add_id(:**) ty = ty.substitute(cur_subst, Config.current.options[:type_depth_limit]).remove_type_vars nenv, ty = scratch.localize_type(ty, nenv, callee_ep, alloc_site2) nenv = nenv.local_update(kw_rest, ty) end nenv = nenv.local_update(block_start, msig.blk_ty) if block_start opt.each do |start_pc| scratch.merge_env(callee_ep.jump(start_pc), nenv) end scratch.add_executed_iseq(@iseq) ctx end
do_send(recv, mid, aargs, caller_ep, caller_env, scratch, &ctn)
click to toggle source
# File typeprof-0.21.3/lib/typeprof/method.rb, line 19 def do_send(recv, mid, aargs, caller_ep, caller_env, scratch, &ctn) recv = recv.base_type while recv.respond_to?(:base_type) recv = scratch.globalize_type(recv, caller_env, caller_ep) aargs = scratch.globalize_type(aargs, caller_env, caller_ep) locals = [Type.nil] * @iseq.locals.size blk_ty, start_pcs = aargs.setup_formal_arguments(:method, locals, @iseq.fargs_format) if blk_ty.is_a?(String) scratch.error(caller_ep, blk_ty) ctn[Type.any, caller_ep, caller_env] return end nctx = Context.new(@iseq, @cref, mid) callee_ep = ExecutionPoint.new(nctx, 0, @outer_ep) nenv = Env.new(StaticEnv.new(recv, blk_ty, false, true), locals, [], Utils::HashWrapper.new({})) alloc_site = AllocationSite.new(callee_ep) locals.each_with_index do |ty, i| alloc_site2 = alloc_site.add_id(i) # nenv is top-level, so it is okay to call Type#localize directly nenv, ty = ty.localize(nenv, alloc_site2, Config.current.options[:type_depth_limit]) nenv = nenv.local_update(i, ty) end start_pcs.each do |start_pc| scratch.merge_env(ExecutionPoint.new(nctx, start_pc, @outer_ep), nenv) end scratch.add_iseq_method_call!(self, nctx) scratch.add_callsite!(nctx, caller_ep, caller_env, &ctn) end