typeprof 0.4.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -2
- data/Gemfile.lock +3 -3
- data/README.md +6 -0
- data/lib/typeprof/analyzer.rb +97 -84
- data/lib/typeprof/arguments.rb +27 -19
- data/lib/typeprof/block.rb +5 -2
- data/lib/typeprof/builtin.rb +14 -4
- data/lib/typeprof/config.rb +10 -6
- data/lib/typeprof/container-type.rb +117 -101
- data/lib/typeprof/export.rb +1 -1
- data/lib/typeprof/import.rb +44 -22
- data/lib/typeprof/method.rb +70 -12
- data/lib/typeprof/type.rb +108 -89
- data/lib/typeprof/version.rb +1 -1
- data/smoke/arguments2.rb +1 -1
- data/smoke/array11.rb +1 -1
- data/smoke/array6.rb +2 -2
- data/smoke/array8.rb +1 -1
- data/smoke/block-args2.rb +3 -3
- data/smoke/block-args3.rb +4 -4
- data/smoke/block-blockarg.rb +1 -1
- data/smoke/block-kwarg.rb +1 -1
- data/smoke/block10.rb +1 -1
- data/smoke/block5.rb +1 -1
- data/smoke/constant2.rb +1 -2
- data/smoke/demo5.rb +1 -1
- data/smoke/demo9.rb +1 -1
- data/smoke/hash-fetch.rb +3 -3
- data/smoke/hash-merge-bang.rb +11 -0
- data/smoke/hash1.rb +3 -2
- data/smoke/hash3.rb +1 -1
- data/smoke/inheritance2.rb +2 -2
- data/smoke/ivar2.rb +2 -2
- data/smoke/kernel-class.rb +1 -1
- data/smoke/keyword4.rb +1 -1
- data/smoke/kwsplat1.rb +2 -2
- data/smoke/kwsplat2.rb +1 -1
- data/smoke/multiple-superclass.rb +1 -1
- data/smoke/parameterizedd-self.rb +2 -2
- data/smoke/pattern-match1.rb +23 -0
- data/smoke/pattern-match2.rb +15 -0
- data/smoke/rbs-tyvar3.rb +11 -19
- data/smoke/rbs-tyvar3.rbs +4 -3
- data/smoke/rbs-tyvar4.rb +36 -0
- data/smoke/rbs-tyvar5.rb +12 -0
- data/smoke/rbs-tyvar5.rbs +8 -0
- data/smoke/struct.rb +2 -2
- data/smoke/uninitialize-var.rb +12 -0
- data/smoke/union-recv.rb +2 -2
- data/typeprof.gemspec +1 -1
- metadata +11 -4
    
        data/lib/typeprof/export.rb
    CHANGED
    
    | @@ -174,7 +174,7 @@ module TypeProf | |
| 174 174 | 
             
                  cvars = cvars.map do |var, entry|
         | 
| 175 175 | 
             
                    next if entry.absolute_paths.all? {|path| Config.check_dir_filter(path) == :exclude }
         | 
| 176 176 | 
             
                    [var, entry.type.screen_name(@scratch), entry.rbs_declared]
         | 
| 177 | 
            -
                  end
         | 
| 177 | 
            +
                  end.compact
         | 
| 178 178 |  | 
| 179 179 | 
             
                  if !class_def.absolute_path || Config.check_dir_filter(class_def.absolute_path) == :exclude
         | 
| 180 180 | 
             
                    return nil if consts.empty? && included_mods.empty? && extended_mods.empty? && ivars.empty? && cvars.empty? && iseq_methods.empty? && attr_methods.empty? && inner_classes.empty?
         | 
    
        data/lib/typeprof/import.rb
    CHANGED
    
    | @@ -10,7 +10,10 @@ module TypeProf | |
| 10 10 | 
             
                def self.get_builtin_env
         | 
| 11 11 | 
             
                  unless @builtin_env
         | 
| 12 12 | 
             
                    @builtin_env = RBS::Environment.new
         | 
| 13 | 
            -
             | 
| 13 | 
            +
             | 
| 14 | 
            +
                    loader = RBS::EnvironmentLoader.new
         | 
| 15 | 
            +
                    new_decls = loader.load(env: @builtin_env).map {|decl,| decl }
         | 
| 16 | 
            +
                    @builtin_env_json = load_rbs(@builtin_env, new_decls)
         | 
| 14 17 | 
             
                  end
         | 
| 15 18 |  | 
| 16 19 | 
             
                  return @builtin_env.dup, @builtin_env_json
         | 
| @@ -21,27 +24,34 @@ module TypeProf | |
| 21 24 | 
             
                end
         | 
| 22 25 |  | 
| 23 26 | 
             
                def load_library(lib)
         | 
| 24 | 
            -
                   | 
| 27 | 
            +
                  loader = RBS::EnvironmentLoader.new(core_root: nil)
         | 
| 28 | 
            +
                  loader.add(library: lib)
         | 
| 29 | 
            +
                  new_decls = loader.load(env: @env).map {|decl,| decl }
         | 
| 30 | 
            +
                  RBSReader.load_rbs(@env, new_decls)
         | 
| 25 31 | 
             
                end
         | 
| 26 32 |  | 
| 27 33 | 
             
                def load_path(path)
         | 
| 28 | 
            -
                   | 
| 34 | 
            +
                  loader = RBS::EnvironmentLoader.new(core_root: nil)
         | 
| 35 | 
            +
                  loader.add(path: path)
         | 
| 36 | 
            +
                  new_decls = loader.load(env: @env).map {|decl,| decl }
         | 
| 37 | 
            +
                  RBSReader.load_rbs(@env, new_decls)
         | 
| 29 38 | 
             
                end
         | 
| 30 39 |  | 
| 31 | 
            -
                def  | 
| 32 | 
            -
                   | 
| 33 | 
            -
             | 
| 34 | 
            -
                   | 
| 35 | 
            -
                     | 
| 36 | 
            -
                     | 
| 40 | 
            +
                def load_rbs_string(name, content)
         | 
| 41 | 
            +
                  buffer = RBS::Buffer.new(name: name, content: content)
         | 
| 42 | 
            +
                  new_decls = []
         | 
| 43 | 
            +
                  RBS::Parser.parse_signature(buffer).each do |decl|
         | 
| 44 | 
            +
                    @env << decl
         | 
| 45 | 
            +
                    new_decls << decl
         | 
| 37 46 | 
             
                  end
         | 
| 38 | 
            -
                   | 
| 47 | 
            +
                  RBSReader.load_rbs(@env, new_decls)
         | 
| 48 | 
            +
                end
         | 
| 39 49 |  | 
| 50 | 
            +
                def self.load_rbs(env, new_decls)
         | 
| 40 51 | 
             
                  all_env = env.resolve_type_names
         | 
| 41 | 
            -
             | 
| 42 52 | 
             
                  resolver = RBS::TypeNameResolver.from_env(all_env)
         | 
| 43 53 | 
             
                  cur_env = RBS::Environment.new
         | 
| 44 | 
            -
                  new_decls.each do |decl | 
| 54 | 
            +
                  new_decls.each do |decl|
         | 
| 45 55 | 
             
                    cur_env << env.resolve_declaration(resolver, decl, outer: [], prefix: RBS::Namespace.root)
         | 
| 46 56 | 
             
                  end
         | 
| 47 57 |  | 
| @@ -210,7 +220,7 @@ module TypeProf | |
| 210 220 | 
             
                  #   * superclasses and modules appear earlier than their subclasses (Object is earlier than String)
         | 
| 211 221 | 
             
                  #   * namespace module appers earlier than its children (Process is earlier than Process::Status)
         | 
| 212 222 | 
             
                  visited = {}
         | 
| 213 | 
            -
                  queue = @cur_env.class_decls.keys.map {|name| [:visit, name] }
         | 
| 223 | 
            +
                  queue = @cur_env.class_decls.keys.map {|name| [:visit, name] }.reverse
         | 
| 214 224 | 
             
                  until queue.empty?
         | 
| 215 225 | 
             
                    event, name = queue.pop
         | 
| 216 226 | 
             
                    case event
         | 
| @@ -365,10 +375,15 @@ module TypeProf | |
| 365 375 | 
             
                      raise if ty.args.size != 2
         | 
| 366 376 | 
             
                      [:array, [:Enumerator], [], conv_type(ty.args.first)]
         | 
| 367 377 | 
             
                    else
         | 
| 368 | 
            -
                       | 
| 378 | 
            +
                      if ty.args.empty?
         | 
| 379 | 
            +
                        [:instance, klass]
         | 
| 380 | 
            +
                      else
         | 
| 381 | 
            +
                        [:cell, [:instance, klass], ty.args.map {|ty| conv_type(ty) }]
         | 
| 382 | 
            +
                      end
         | 
| 369 383 | 
             
                    end
         | 
| 370 384 | 
             
                  when RBS::Types::Bases::Bool   then [:bool]
         | 
| 371 385 | 
             
                  when RBS::Types::Bases::Any    then [:any]
         | 
| 386 | 
            +
                  when RBS::Types::Bases::Top    then [:any]
         | 
| 372 387 | 
             
                  when RBS::Types::Bases::Void   then [:void]
         | 
| 373 388 | 
             
                  when RBS::Types::Bases::Self   then [:self]
         | 
| 374 389 | 
             
                  when RBS::Types::Bases::Nil    then [:nil]
         | 
| @@ -440,6 +455,10 @@ module TypeProf | |
| 440 455 | 
             
                  Import.new(scratch, scratch.rbs_reader.load_path(rbs_path)).import(true)
         | 
| 441 456 | 
             
                end
         | 
| 442 457 |  | 
| 458 | 
            +
                def self.import_rbs_code(scratch, rbs_name, rbs_code)
         | 
| 459 | 
            +
                  Import.new(scratch, scratch.rbs_reader.load_rbs_string(rbs_name, rbs_code)).import(true)
         | 
| 460 | 
            +
                end
         | 
| 461 | 
            +
             | 
| 443 462 | 
             
                def initialize(scratch, json)
         | 
| 444 463 | 
             
                  @scratch = scratch
         | 
| 445 464 | 
             
                  @json = json
         | 
| @@ -485,11 +504,11 @@ module TypeProf | |
| 485 504 | 
             
                    rbs_sources = members[:rbs_sources]
         | 
| 486 505 |  | 
| 487 506 | 
             
                    included_modules.each do |mod|
         | 
| 488 | 
            -
                      @scratch.include_module(klass, path_to_klass(mod), nil)
         | 
| 507 | 
            +
                      @scratch.include_module(klass, path_to_klass(mod), false, nil)
         | 
| 489 508 | 
             
                    end
         | 
| 490 509 |  | 
| 491 510 | 
             
                    extended_modules.each do |mod|
         | 
| 492 | 
            -
                      @scratch. | 
| 511 | 
            +
                      @scratch.include_module(klass, path_to_klass(mod), true, nil)
         | 
| 493 512 | 
             
                    end
         | 
| 494 513 |  | 
| 495 514 | 
             
                    methods.each do |(singleton, method_name), mdef|
         | 
| @@ -499,24 +518,25 @@ module TypeProf | |
| 499 518 | 
             
                    end
         | 
| 500 519 |  | 
| 501 520 | 
             
                    ivars.each do |ivar_name, ty|
         | 
| 502 | 
            -
                      ty = conv_type(ty)
         | 
| 521 | 
            +
                      ty = conv_type(ty).remove_type_vars
         | 
| 503 522 | 
             
                      @scratch.add_ivar_write!(Type::Instance.new(klass), ivar_name, ty, nil)
         | 
| 504 523 | 
             
                    end
         | 
| 505 524 |  | 
| 506 525 | 
             
                    cvars.each do |ivar_name, ty|
         | 
| 507 | 
            -
                      ty = conv_type(ty)
         | 
| 526 | 
            +
                      ty = conv_type(ty).remove_type_vars
         | 
| 508 527 | 
             
                      @scratch.add_cvar_write!(klass, ivar_name, ty, nil)
         | 
| 509 528 | 
             
                    end
         | 
| 510 529 | 
             
                  end
         | 
| 511 530 |  | 
| 512 531 | 
             
                  @json[:constants].each do |classpath, value|
         | 
| 513 532 | 
             
                    base_klass = path_to_klass(classpath[0..-2])
         | 
| 514 | 
            -
                    value = conv_type(value)
         | 
| 533 | 
            +
                    value = conv_type(value).remove_type_vars
         | 
| 515 534 | 
             
                    @scratch.add_constant(base_klass, classpath[-1], value, nil)
         | 
| 516 535 | 
             
                  end
         | 
| 517 536 |  | 
| 518 | 
            -
                  @json[:globals].each do |name,  | 
| 519 | 
            -
                     | 
| 537 | 
            +
                  @json[:globals].each do |name, ty|
         | 
| 538 | 
            +
                    ty = conv_type(ty).remove_type_vars
         | 
| 539 | 
            +
                    @scratch.add_gvar_write!(name, ty, nil)
         | 
| 520 540 | 
             
                  end
         | 
| 521 541 |  | 
| 522 542 | 
             
                  true
         | 
| @@ -574,6 +594,8 @@ module TypeProf | |
| 574 594 | 
             
                  case ty.first
         | 
| 575 595 | 
             
                  when :class then path_to_klass(ty[1])
         | 
| 576 596 | 
             
                  when :instance then Type::Instance.new(path_to_klass(ty[1]))
         | 
| 597 | 
            +
                  when :cell
         | 
| 598 | 
            +
                    Type::Cell.new(Type::Cell::Elements.new(ty[2].map {|ty| conv_type(ty) }), conv_type(ty[1]))
         | 
| 577 599 | 
             
                  when :any then Type.any
         | 
| 578 600 | 
             
                  when :void then Type::Void.new
         | 
| 579 601 | 
             
                  when :nil then Type.nil
         | 
| @@ -609,7 +631,7 @@ module TypeProf | |
| 609 631 | 
             
                    end
         | 
| 610 632 | 
             
                  when :union
         | 
| 611 633 | 
             
                    tys = ty[1]
         | 
| 612 | 
            -
                    Type::Union.new(Utils::Set[*tys.map {|ty2| conv_type(ty2) }], nil) # XXX: Array and Hash support
         | 
| 634 | 
            +
                    Type::Union.new(Utils::Set[*tys.map {|ty2| conv_type(ty2) }], nil).normalize # XXX: Array and Hash support
         | 
| 613 635 | 
             
                  when :var
         | 
| 614 636 | 
             
                    Type::Var.new(ty[1])
         | 
| 615 637 | 
             
                  when :proc
         | 
    
        data/lib/typeprof/method.rb
    CHANGED
    
    | @@ -11,6 +11,7 @@ module TypeProf | |
| 11 11 | 
             
                end
         | 
| 12 12 |  | 
| 13 13 | 
             
                def do_send(recv, mid, aargs, caller_ep, caller_env, scratch, &ctn)
         | 
| 14 | 
            +
                  recv = recv.base_type while recv.respond_to?(:base_type)
         | 
| 14 15 | 
             
                  recv = scratch.globalize_type(recv, caller_env, caller_ep)
         | 
| 15 16 | 
             
                  aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
         | 
| 16 17 |  | 
| @@ -175,8 +176,10 @@ module TypeProf | |
| 175 176 | 
             
                    ncaller_env = caller_env
         | 
| 176 177 | 
             
                    #pp [mid, aargs, msig]
         | 
| 177 178 | 
             
                    # XXX: support self type in msig
         | 
| 178 | 
            -
                    subst =  | 
| 179 | 
            -
                    next unless  | 
| 179 | 
            +
                    subst = aargs.consistent_with_method_signature?(msig)
         | 
| 180 | 
            +
                    next unless subst
         | 
| 181 | 
            +
                    # need to check self tyvar?
         | 
| 182 | 
            +
                    subst[Type::Var.new(:self)] = recv
         | 
| 180 183 | 
             
                    case
         | 
| 181 184 | 
             
                    when recv.is_a?(Type::Cell) && recv_orig.is_a?(Type::LocalCell)
         | 
| 182 185 | 
             
                      tyvars = recv.base_type.klass.type_params.map {|name,| Type::Var.new(name) }
         | 
| @@ -205,22 +208,34 @@ module TypeProf | |
| 205 208 | 
             
                          elems.update(nil, ty)
         | 
| 206 209 | 
             
                        end
         | 
| 207 210 | 
             
                      end
         | 
| 208 | 
            -
                      subst.merge!({ tyvar_elem => recv.elems. | 
| 211 | 
            +
                      subst.merge!({ tyvar_elem => recv.elems.squash })
         | 
| 209 212 | 
             
                    when recv.is_a?(Type::Hash) && recv_orig.is_a?(Type::LocalHash)
         | 
| 210 213 | 
             
                      tyvar_k = Type::Var.new(:K)
         | 
| 211 214 | 
             
                      tyvar_v = Type::Var.new(:V)
         | 
| 212 | 
            -
                       | 
| 213 | 
            -
                       | 
| 215 | 
            +
                      k_ty0, v_ty0 = recv.elems.squash
         | 
| 216 | 
            +
                      if subst[tyvar_k] && subst[tyvar_v]
         | 
| 217 | 
            +
                        k_ty = subst[tyvar_k]
         | 
| 218 | 
            +
                        v_ty = subst[tyvar_v]
         | 
| 219 | 
            +
                        k_ty0 = k_ty0.union(k_ty)
         | 
| 220 | 
            +
                        v_ty0 = v_ty0.union(v_ty)
         | 
| 221 | 
            +
                        alloc_site = AllocationSite.new(caller_ep)
         | 
| 222 | 
            +
                        ncaller_env, k_ty = scratch.localize_type(k_ty, ncaller_env, caller_ep, alloc_site.add_id(:k))
         | 
| 223 | 
            +
                        ncaller_env, v_ty = scratch.localize_type(v_ty, ncaller_env, caller_ep, alloc_site.add_id(:v))
         | 
| 224 | 
            +
                        ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id, recv_orig.base_type) do |elems|
         | 
| 225 | 
            +
                          elems.update(k_ty, v_ty)
         | 
| 226 | 
            +
                        end
         | 
| 227 | 
            +
                      end
         | 
| 214 228 | 
             
                      # XXX: need to heuristically replace ret type Hash[K, V] with self, instead of conversative type?
         | 
| 215 | 
            -
                      subst.merge!({ tyvar_k =>  | 
| 229 | 
            +
                      subst.merge!({ tyvar_k => k_ty0, tyvar_v => v_ty0 })
         | 
| 216 230 | 
             
                    end
         | 
| 217 | 
            -
                    ret_ty = ret_ty.substitute(subst, Config.options[:type_depth_limit])
         | 
| 218 231 | 
             
                    found = true
         | 
| 219 232 | 
             
                    if aargs.blk_ty.is_a?(Type::Proc)
         | 
| 220 233 | 
             
                      #raise NotImplementedError unless aargs.blk_ty.block_body.is_a?(ISeqBlock) # XXX
         | 
| 221 234 | 
             
                      dummy_ctx = TypedContext.new(caller_ep, mid)
         | 
| 222 235 | 
             
                      dummy_ep = ExecutionPoint.new(dummy_ctx, -1, caller_ep)
         | 
| 223 | 
            -
                       | 
| 236 | 
            +
                      s_recv = recv
         | 
| 237 | 
            +
                      s_recv = s_recv.base_type while s_recv.respond_to?(:base_type)
         | 
| 238 | 
            +
                      dummy_env = Env.new(StaticEnv.new(s_recv, msig.blk_ty, false), [], [], Utils::HashWrapper.new({}))
         | 
| 224 239 | 
             
                      if msig.blk_ty.is_a?(Type::Proc)
         | 
| 225 240 | 
             
                        scratch.add_callsite!(dummy_ctx, caller_ep, ncaller_env, &ctn)
         | 
| 226 241 | 
             
                        nfargs = msig.blk_ty.block_body.msig
         | 
| @@ -240,13 +255,55 @@ module TypeProf | |
| 240 255 | 
             
                        0.upto(nfargs.opt_tys.size) do |n|
         | 
| 241 256 | 
             
                          naargs = ActualArguments.new(nlead_tys[0, nfargs.lead_tys.size + n], nil, {}, Type.nil) # XXX: support block to block?
         | 
| 242 257 | 
             
                          scratch.do_invoke_block(aargs.blk_ty, naargs, dummy_ep, dummy_env) do |blk_ret_ty, _ep, _env|
         | 
| 243 | 
            -
                            subst2 =  | 
| 244 | 
            -
                            if  | 
| 245 | 
            -
                               | 
| 258 | 
            +
                            subst2 = Type.match?(blk_ret_ty, msig.blk_ty.block_body.ret_ty)
         | 
| 259 | 
            +
                            if subst2
         | 
| 260 | 
            +
                              subst2 = Type.merge_substitution(subst, subst2)
         | 
| 261 | 
            +
                              case
         | 
| 262 | 
            +
                              when recv.is_a?(Type::Cell) && recv_orig.is_a?(Type::LocalCell)
         | 
| 263 | 
            +
                                tyvars = recv.base_type.klass.type_params.map {|name,| Type::Var.new(name) }
         | 
| 264 | 
            +
                                tyvars.each_with_index do |tyvar, idx|
         | 
| 265 | 
            +
                                  ty = subst2[tyvar]
         | 
| 266 | 
            +
                                  if ty
         | 
| 267 | 
            +
                                    ncaller_env, ty = scratch.localize_type(ty, ncaller_env, caller_ep)
         | 
| 268 | 
            +
                                    ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id, recv_orig.base_type) do |elems|
         | 
| 269 | 
            +
                                      elems.update(idx, ty)
         | 
| 270 | 
            +
                                    end
         | 
| 271 | 
            +
                                    scratch.merge_return_env(caller_ep) {|env| env ? env.merge(ncaller_env) : ncaller_env }
         | 
| 272 | 
            +
                                  end
         | 
| 273 | 
            +
                                end
         | 
| 274 | 
            +
                                tyvars.zip(recv.elems.elems) do |tyvar, elem|
         | 
| 275 | 
            +
                                  if subst2[tyvar]
         | 
| 276 | 
            +
                                    subst2[tyvar] = subst2[tyvar].union(elem)
         | 
| 277 | 
            +
                                  else
         | 
| 278 | 
            +
                                    subst2[tyvar] = elem
         | 
| 279 | 
            +
                                  end
         | 
| 280 | 
            +
                                end
         | 
| 281 | 
            +
                                ret_ty = ret_ty.substitute(subst2, Config.options[:type_depth_limit])
         | 
| 282 | 
            +
                              when recv.is_a?(Type::Array) && recv_orig.is_a?(Type::LocalArray)
         | 
| 246 283 | 
             
                                tyvar_elem = Type::Var.new(:Elem)
         | 
| 247 284 | 
             
                                if subst2[tyvar_elem]
         | 
| 285 | 
            +
                                  ty = subst2[tyvar_elem]
         | 
| 286 | 
            +
                                  ncaller_env, ty = scratch.localize_type(ty, ncaller_env, caller_ep)
         | 
| 287 | 
            +
                                  ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id, recv_orig.base_type) do |elems|
         | 
| 288 | 
            +
                                    elems.update(nil, ty)
         | 
| 289 | 
            +
                                  end
         | 
| 290 | 
            +
                                  scratch.merge_return_env(caller_ep) {|env| env ? env.merge(ncaller_env) : ncaller_env }
         | 
| 291 | 
            +
                                end
         | 
| 292 | 
            +
                                ret_ty = ret_ty.substitute(subst2, Config.options[:type_depth_limit])
         | 
| 293 | 
            +
                              when recv.is_a?(Type::Hash) && recv_orig.is_a?(Type::LocalHash)
         | 
| 294 | 
            +
                                tyvar_k = Type::Var.new(:K)
         | 
| 295 | 
            +
                                tyvar_v = Type::Var.new(:V)
         | 
| 296 | 
            +
                                k_ty0, v_ty0 = recv.elems.squash
         | 
| 297 | 
            +
                                if subst2[tyvar_k] && subst2[tyvar_v]
         | 
| 298 | 
            +
                                  k_ty = subst2[tyvar_k]
         | 
| 299 | 
            +
                                  v_ty = subst2[tyvar_v]
         | 
| 300 | 
            +
                                  k_ty0 = k_ty0.union(k_ty)
         | 
| 301 | 
            +
                                  v_ty0 = v_ty0.union(v_ty)
         | 
| 302 | 
            +
                                  alloc_site = AllocationSite.new(caller_ep)
         | 
| 303 | 
            +
                                  ncaller_env, k_ty = scratch.localize_type(k_ty, ncaller_env, caller_ep, alloc_site.add_id(:k))
         | 
| 304 | 
            +
                                  ncaller_env, v_ty = scratch.localize_type(v_ty, ncaller_env, caller_ep, alloc_site.add_id(:v))
         | 
| 248 305 | 
             
                                  ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id, recv_orig.base_type) do |elems|
         | 
| 249 | 
            -
                                    elems.update( | 
| 306 | 
            +
                                    elems.update(k_ty, v_ty)
         | 
| 250 307 | 
             
                                  end
         | 
| 251 308 | 
             
                                  scratch.merge_return_env(caller_ep) {|env| env ? env.merge(ncaller_env) : ncaller_env }
         | 
| 252 309 | 
             
                                end
         | 
| @@ -274,6 +331,7 @@ module TypeProf | |
| 274 331 | 
             
                        ctn[ret_ty, caller_ep, ncaller_env]
         | 
| 275 332 | 
             
                      end
         | 
| 276 333 | 
             
                    else
         | 
| 334 | 
            +
                      ret_ty = ret_ty.substitute(subst, Config.options[:type_depth_limit])
         | 
| 277 335 | 
             
                      ret_ty = ret_ty.remove_type_vars
         | 
| 278 336 | 
             
                      ctn[ret_ty, caller_ep, ncaller_env]
         | 
| 279 337 | 
             
                    end
         | 
    
        data/lib/typeprof/type.rb
    CHANGED
    
    | @@ -20,16 +20,69 @@ module TypeProf | |
| 20 20 | 
             
                  self
         | 
| 21 21 | 
             
                end
         | 
| 22 22 |  | 
| 23 | 
            -
                def  | 
| 24 | 
            -
                   | 
| 25 | 
            -
                   | 
| 26 | 
            -
                   | 
| 23 | 
            +
                def self.match?(ty1, ty2)
         | 
| 24 | 
            +
                  # both ty1 and ty2 should be global
         | 
| 25 | 
            +
                  # ty1 is always concrete; it should not have type variables
         | 
| 26 | 
            +
                  # ty2 might be abstract; it may have type variables
         | 
| 27 | 
            +
                  case ty2
         | 
| 28 | 
            +
                  when Type::Var
         | 
| 29 | 
            +
                    { ty2 => ty1 }
         | 
| 30 | 
            +
                  when Type::Any
         | 
| 31 | 
            +
                    {}
         | 
| 27 32 | 
             
                  when Type::Union
         | 
| 28 | 
            -
                     | 
| 29 | 
            -
             | 
| 33 | 
            +
                    subst = nil
         | 
| 34 | 
            +
                    ty2.each_child_global do |ty2|
         | 
| 35 | 
            +
                      # this is very conservative to create subst:
         | 
| 36 | 
            +
                      # Type.match?( int | str, int | X) creates { X => int | str } but should be { X => str }???
         | 
| 37 | 
            +
                      subst2 = Type.match?(ty1, ty2)
         | 
| 38 | 
            +
                      next unless subst2
         | 
| 39 | 
            +
                      subst = Type.merge_substitution(subst, subst2)
         | 
| 30 40 | 
             
                    end
         | 
| 41 | 
            +
                    subst
         | 
| 31 42 | 
             
                  else
         | 
| 32 | 
            -
                     | 
| 43 | 
            +
                    case ty1
         | 
| 44 | 
            +
                    when Type::Var then raise "should not occur"
         | 
| 45 | 
            +
                    when Type::Any
         | 
| 46 | 
            +
                      subst = {}
         | 
| 47 | 
            +
                      ty2.each_free_type_variable do |tyvar|
         | 
| 48 | 
            +
                        subst[tyvar] = Type.any
         | 
| 49 | 
            +
                      end
         | 
| 50 | 
            +
                      subst
         | 
| 51 | 
            +
                    when Type::Union
         | 
| 52 | 
            +
                      subst = nil
         | 
| 53 | 
            +
                      ty1.each_child_global do |ty1|
         | 
| 54 | 
            +
                        subst2 = Type.match?(ty1, ty2)
         | 
| 55 | 
            +
                        next unless subst2
         | 
| 56 | 
            +
                        subst = Type.merge_substitution(subst, subst2)
         | 
| 57 | 
            +
                      end
         | 
| 58 | 
            +
                      subst
         | 
| 59 | 
            +
                    else
         | 
| 60 | 
            +
                      if ty2.is_a?(Type::ContainerType)
         | 
| 61 | 
            +
                        # ty2 may have type variables
         | 
| 62 | 
            +
                        return nil if ty1.class != ty2.class
         | 
| 63 | 
            +
                        ty1.match?(ty2)
         | 
| 64 | 
            +
                      elsif ty1.is_a?(Type::ContainerType)
         | 
| 65 | 
            +
                        nil
         | 
| 66 | 
            +
                      else
         | 
| 67 | 
            +
                        ty1.consistent?(ty2) ? {} : nil
         | 
| 68 | 
            +
                      end
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def self.merge_substitution(subst1, subst2)
         | 
| 74 | 
            +
                  if subst1
         | 
| 75 | 
            +
                    subst1 = subst1.dup
         | 
| 76 | 
            +
                    subst2.each do |tyvar, ty|
         | 
| 77 | 
            +
                      if subst1[tyvar]
         | 
| 78 | 
            +
                        subst1[tyvar] = subst1[tyvar].union(ty)
         | 
| 79 | 
            +
                      else
         | 
| 80 | 
            +
                        subst1[tyvar] = ty
         | 
| 81 | 
            +
                      end
         | 
| 82 | 
            +
                    end
         | 
| 83 | 
            +
                    subst1
         | 
| 84 | 
            +
                  else
         | 
| 85 | 
            +
                    subst2
         | 
| 33 86 | 
             
                  end
         | 
| 34 87 | 
             
                end
         | 
| 35 88 |  | 
| @@ -41,6 +94,9 @@ module TypeProf | |
| 41 94 | 
             
                  yield self
         | 
| 42 95 | 
             
                end
         | 
| 43 96 |  | 
| 97 | 
            +
                def each_free_type_variable
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
             | 
| 44 100 | 
             
                def union(other)
         | 
| 45 101 | 
             
                  return self if self == other # fastpath
         | 
| 46 102 |  | 
| @@ -118,10 +174,8 @@ module TypeProf | |
| 118 174 | 
             
                    nil
         | 
| 119 175 | 
             
                  end
         | 
| 120 176 |  | 
| 121 | 
            -
                  def consistent?( | 
| 122 | 
            -
                     | 
| 123 | 
            -
                    other.add_subst!(self, subst) if other.is_a?(Type::Var)
         | 
| 124 | 
            -
                    true
         | 
| 177 | 
            +
                  def consistent?(_other)
         | 
| 178 | 
            +
                    raise "should not be called"
         | 
| 125 179 | 
             
                  end
         | 
| 126 180 |  | 
| 127 181 | 
             
                  def substitute(_subst, _depth)
         | 
| @@ -156,6 +210,12 @@ module TypeProf | |
| 156 210 | 
             
                    @elems = elems
         | 
| 157 211 | 
             
                  end
         | 
| 158 212 |  | 
| 213 | 
            +
                  def each_free_type_variable(&blk)
         | 
| 214 | 
            +
                    each_child_global do |ty|
         | 
| 215 | 
            +
                      ty.each_free_type_variable(&blk)
         | 
| 216 | 
            +
                    end
         | 
| 217 | 
            +
                  end
         | 
| 218 | 
            +
             | 
| 159 219 | 
             
                  def limit_size(limit)
         | 
| 160 220 | 
             
                    return Type.any if limit <= 0
         | 
| 161 221 | 
             
                    tys = Utils::Set[]
         | 
| @@ -271,48 +331,20 @@ module TypeProf | |
| 271 331 | 
             
                  def localize(env, alloc_site, depth)
         | 
| 272 332 | 
             
                    return env, Type.any if depth <= 0
         | 
| 273 333 | 
             
                    tys = @types.map do |ty|
         | 
| 274 | 
            -
                       | 
| 275 | 
            -
                      env, ty2 = ty.localize(env, alloc_site2, depth - 1)
         | 
| 334 | 
            +
                      env, ty2 = ty.localize(env, alloc_site, depth - 1)
         | 
| 276 335 | 
             
                      ty2
         | 
| 277 336 | 
             
                    end
         | 
| 278 337 | 
             
                    @elems&.each do |(container_kind, base_type), elems|
         | 
| 279 338 | 
             
                      ty = container_kind.new(elems, base_type)
         | 
| 280 | 
            -
                       | 
| 281 | 
            -
                      env, ty = ty.localize(env, alloc_site2, depth - 1)
         | 
| 339 | 
            +
                      env, ty = ty.localize(env, alloc_site, depth - 1)
         | 
| 282 340 | 
             
                      tys = tys.add(ty)
         | 
| 283 341 | 
             
                    end
         | 
| 284 342 | 
             
                    ty = Union.new(tys, nil).normalize
         | 
| 285 343 | 
             
                    return env, ty
         | 
| 286 344 | 
             
                  end
         | 
| 287 345 |  | 
| 288 | 
            -
                  def consistent?( | 
| 289 | 
            -
                     | 
| 290 | 
            -
                    when Type::Any then true
         | 
| 291 | 
            -
                    when Type::Var then other.add_subst!(self, subst)
         | 
| 292 | 
            -
                    when Type::Union
         | 
| 293 | 
            -
                      # this is very conservative to create subst:
         | 
| 294 | 
            -
                      # consistent?( int | str, int | X) creates { X => int | str } but should be { X => str }???
         | 
| 295 | 
            -
                      @types.each do |ty1|
         | 
| 296 | 
            -
                        other.types.each do |ty2|
         | 
| 297 | 
            -
                          subst2 = subst.dup
         | 
| 298 | 
            -
                          if ty1.consistent?(ty2, subst2)
         | 
| 299 | 
            -
                            subst.replace(subst2)
         | 
| 300 | 
            -
                            # XXX: need to check other pairs to create conservative substitution??
         | 
| 301 | 
            -
                            # consistent?( X | :foo, str | int ) may return { X => str } or { X => int } but should be { X => str | int }?
         | 
| 302 | 
            -
                            return true
         | 
| 303 | 
            -
                          end
         | 
| 304 | 
            -
                        end
         | 
| 305 | 
            -
                      end
         | 
| 306 | 
            -
                      return true if @types.size == 0 && other.types.size == 0 # XXX: is this okay?
         | 
| 307 | 
            -
                      # TODO: array argument?
         | 
| 308 | 
            -
                      return false
         | 
| 309 | 
            -
                    else
         | 
| 310 | 
            -
                      @types.each do |ty1|
         | 
| 311 | 
            -
                        return true if ty1.consistent?(other, subst)
         | 
| 312 | 
            -
                      end
         | 
| 313 | 
            -
                      # TODO: array argument?
         | 
| 314 | 
            -
                      return false
         | 
| 315 | 
            -
                    end
         | 
| 346 | 
            +
                  def consistent?(_other)
         | 
| 347 | 
            +
                    raise "should not be called"
         | 
| 316 348 | 
             
                  end
         | 
| 317 349 |  | 
| 318 350 | 
             
                  def substitute(subst, depth)
         | 
| @@ -331,7 +363,7 @@ module TypeProf | |
| 331 363 | 
             
                    elems = @elems&.to_h do |(container_kind, base_type), elems|
         | 
| 332 364 | 
             
                      [[container_kind, base_type], elems.substitute(subst, depth - 1)]
         | 
| 333 365 | 
             
                    end
         | 
| 334 | 
            -
                    ty = Union.new(tys, elems)
         | 
| 366 | 
            +
                    ty = Union.new(tys, elems).normalize
         | 
| 335 367 | 
             
                    unions.each do |ty0|
         | 
| 336 368 | 
             
                      ty = ty.union(ty0)
         | 
| 337 369 | 
             
                    end
         | 
| @@ -371,6 +403,10 @@ module TypeProf | |
| 371 403 | 
             
                    "Var[#{ @name }]"
         | 
| 372 404 | 
             
                  end
         | 
| 373 405 |  | 
| 406 | 
            +
                  def each_free_type_variable
         | 
| 407 | 
            +
                    yield self
         | 
| 408 | 
            +
                  end
         | 
| 409 | 
            +
             | 
| 374 410 | 
             
                  def substitute(subst, depth)
         | 
| 375 411 | 
             
                    if subst[self]
         | 
| 376 412 | 
             
                      subst[self].limit_size(depth)
         | 
| @@ -379,7 +415,7 @@ module TypeProf | |
| 379 415 | 
             
                    end
         | 
| 380 416 | 
             
                  end
         | 
| 381 417 |  | 
| 382 | 
            -
                  def consistent?( | 
| 418 | 
            +
                  def consistent?(_other)
         | 
| 383 419 | 
             
                    raise "should not be called: #{ self }"
         | 
| 384 420 | 
             
                  end
         | 
| 385 421 |  | 
| @@ -413,22 +449,15 @@ module TypeProf | |
| 413 449 | 
             
                  end
         | 
| 414 450 |  | 
| 415 451 | 
             
                  def screen_name(scratch)
         | 
| 416 | 
            -
                    "#{ scratch.get_class_name(self) } | 
| 452 | 
            +
                    "singleton(#{ scratch.get_class_name(self) })"
         | 
| 417 453 | 
             
                  end
         | 
| 418 454 |  | 
| 419 455 | 
             
                  def get_method(mid, scratch)
         | 
| 420 456 | 
             
                    scratch.get_method(self, true, mid)
         | 
| 421 457 | 
             
                  end
         | 
| 422 458 |  | 
| 423 | 
            -
                  def consistent?(other | 
| 459 | 
            +
                  def consistent?(other)
         | 
| 424 460 | 
             
                    case other
         | 
| 425 | 
            -
                    when Type::Any then true
         | 
| 426 | 
            -
                    when Type::Var then other.add_subst!(self, subst)
         | 
| 427 | 
            -
                    when Type::Union
         | 
| 428 | 
            -
                      other.types.each do |ty|
         | 
| 429 | 
            -
                        return true if consistent?(ty, subst)
         | 
| 430 | 
            -
                      end
         | 
| 431 | 
            -
                      return false
         | 
| 432 461 | 
             
                    when Type::Class
         | 
| 433 462 | 
             
                      ty = self
         | 
| 434 463 | 
             
                      loop do
         | 
| @@ -479,17 +508,10 @@ module TypeProf | |
| 479 508 | 
             
                    scratch.get_method(@klass, false, mid)
         | 
| 480 509 | 
             
                  end
         | 
| 481 510 |  | 
| 482 | 
            -
                  def consistent?(other | 
| 511 | 
            +
                  def consistent?(other)
         | 
| 483 512 | 
             
                    case other
         | 
| 484 | 
            -
                    when Type::Any then true
         | 
| 485 | 
            -
                    when Type::Var then other.add_subst!(self, subst)
         | 
| 486 | 
            -
                    when Type::Union
         | 
| 487 | 
            -
                      other.types.each do |ty|
         | 
| 488 | 
            -
                        return true if consistent?(ty, subst)
         | 
| 489 | 
            -
                      end
         | 
| 490 | 
            -
                      return false
         | 
| 491 513 | 
             
                    when Type::Instance
         | 
| 492 | 
            -
                      @klass.consistent?(other.klass | 
| 514 | 
            +
                      @klass.consistent?(other.klass)
         | 
| 493 515 | 
             
                    when Type::Class
         | 
| 494 516 | 
             
                      return true if @klass == Type::Builtin[:obj] || @klass == Type::Builtin[:class] || @klass == Type::Builtin[:module]
         | 
| 495 517 | 
             
                      return false
         | 
| @@ -503,6 +525,7 @@ module TypeProf | |
| 503 525 | 
             
                  end
         | 
| 504 526 | 
             
                end
         | 
| 505 527 |  | 
| 528 | 
            +
                # This is an internal object in MRI, so a user program cannot create this object explicitly
         | 
| 506 529 | 
             
                class ISeq < Type
         | 
| 507 530 | 
             
                  def initialize(iseq)
         | 
| 508 531 | 
             
                    @iseq = iseq
         | 
| @@ -520,20 +543,14 @@ module TypeProf | |
| 520 543 | 
             
                end
         | 
| 521 544 |  | 
| 522 545 | 
             
                class Proc < Type
         | 
| 523 | 
            -
                  def initialize(block_body,  | 
| 524 | 
            -
                    @block_body, @ | 
| 546 | 
            +
                  def initialize(block_body, base_type)
         | 
| 547 | 
            +
                    @block_body, @base_type = block_body, base_type
         | 
| 525 548 | 
             
                  end
         | 
| 526 549 |  | 
| 527 | 
            -
                  attr_reader :block_body, : | 
| 550 | 
            +
                  attr_reader :block_body, :base_type
         | 
| 528 551 |  | 
| 529 | 
            -
                  def consistent?(other | 
| 552 | 
            +
                  def consistent?(other)
         | 
| 530 553 | 
             
                    case other
         | 
| 531 | 
            -
                    when Type::Any then true
         | 
| 532 | 
            -
                    when Type::Var then other.add_subst!(self, subst)
         | 
| 533 | 
            -
                    when Type::Union
         | 
| 534 | 
            -
                      other.types.each do |ty2|
         | 
| 535 | 
            -
                        return true if consistent?(ty2, subst)
         | 
| 536 | 
            -
                      end
         | 
| 537 554 | 
             
                    when Type::Proc
         | 
| 538 555 | 
             
                      @block_body.consistent?(other.block_body)
         | 
| 539 556 | 
             
                    else
         | 
| @@ -542,11 +559,11 @@ module TypeProf | |
| 542 559 | 
             
                  end
         | 
| 543 560 |  | 
| 544 561 | 
             
                  def get_method(mid, scratch)
         | 
| 545 | 
            -
                    @ | 
| 562 | 
            +
                    @base_type.get_method(mid, scratch)
         | 
| 546 563 | 
             
                  end
         | 
| 547 564 |  | 
| 548 565 | 
             
                  def substitute(subst, depth)
         | 
| 549 | 
            -
                    Proc.new(@block_body.substitute(subst, depth), @ | 
| 566 | 
            +
                    Proc.new(@block_body.substitute(subst, depth), @base_type)
         | 
| 550 567 | 
             
                  end
         | 
| 551 568 |  | 
| 552 569 | 
             
                  def screen_name(scratch)
         | 
| @@ -566,14 +583,12 @@ module TypeProf | |
| 566 583 | 
             
                    "Type::Symbol[#{ @sym ? @sym.inspect : "(dynamic symbol)" }, #{ @base_type.inspect }]"
         | 
| 567 584 | 
             
                  end
         | 
| 568 585 |  | 
| 569 | 
            -
                  def consistent?(other | 
| 586 | 
            +
                  def consistent?(other)
         | 
| 570 587 | 
             
                    case other
         | 
| 571 | 
            -
                    when Var
         | 
| 572 | 
            -
                      other.add_subst!(self, subst)
         | 
| 573 588 | 
             
                    when Symbol
         | 
| 574 589 | 
             
                      @sym == other.sym
         | 
| 575 590 | 
             
                    else
         | 
| 576 | 
            -
                      @base_type.consistent?(other | 
| 591 | 
            +
                      @base_type.consistent?(other)
         | 
| 577 592 | 
             
                    end
         | 
| 578 593 | 
             
                  end
         | 
| 579 594 |  | 
| @@ -594,33 +609,33 @@ module TypeProf | |
| 594 609 | 
             
                  end
         | 
| 595 610 | 
             
                end
         | 
| 596 611 |  | 
| 597 | 
            -
                # local  | 
| 612 | 
            +
                # A local type
         | 
| 598 613 | 
             
                class Literal < Type
         | 
| 599 | 
            -
                  def initialize(lit,  | 
| 614 | 
            +
                  def initialize(lit, base_type)
         | 
| 600 615 | 
             
                    @lit = lit
         | 
| 601 | 
            -
                    @ | 
| 616 | 
            +
                    @base_type = base_type
         | 
| 602 617 | 
             
                  end
         | 
| 603 618 |  | 
| 604 | 
            -
                  attr_reader :lit, : | 
| 619 | 
            +
                  attr_reader :lit, :base_type
         | 
| 605 620 |  | 
| 606 621 | 
             
                  def inspect
         | 
| 607 | 
            -
                    "Type::Literal[#{ @lit.inspect }, #{ @ | 
| 622 | 
            +
                    "Type::Literal[#{ @lit.inspect }, #{ @base_type.inspect }]"
         | 
| 608 623 | 
             
                  end
         | 
| 609 624 |  | 
| 610 625 | 
             
                  def screen_name(scratch)
         | 
| 611 | 
            -
                    @ | 
| 626 | 
            +
                    @base_type.screen_name(scratch) + "<#{ @lit.inspect }>"
         | 
| 612 627 | 
             
                  end
         | 
| 613 628 |  | 
| 614 629 | 
             
                  def globalize(_env, _visited, _depth)
         | 
| 615 | 
            -
                    @ | 
| 630 | 
            +
                    @base_type
         | 
| 616 631 | 
             
                  end
         | 
| 617 632 |  | 
| 618 633 | 
             
                  def get_method(mid, scratch)
         | 
| 619 | 
            -
                    @ | 
| 634 | 
            +
                    @base_type.get_method(mid, scratch)
         | 
| 620 635 | 
             
                  end
         | 
| 621 636 |  | 
| 622 | 
            -
                  def consistent?( | 
| 623 | 
            -
                     | 
| 637 | 
            +
                  def consistent?(_other)
         | 
| 638 | 
            +
                    raise "should not called"
         | 
| 624 639 | 
             
                  end
         | 
| 625 640 | 
             
                end
         | 
| 626 641 |  | 
| @@ -770,6 +785,10 @@ module TypeProf | |
| 770 785 | 
             
                  end
         | 
| 771 786 | 
             
                  str = str.empty? ? "" : "(#{ str.join(", ") })"
         | 
| 772 787 |  | 
| 788 | 
            +
                  # Dirty Hack: Stop the iteration at most once!
         | 
| 789 | 
            +
                  # I'll remove this hack if RBS removes the limitation of nesting blocks
         | 
| 790 | 
            +
                  return str if caller_locations.any? {|frame| frame.label == "show_block_signature" }
         | 
| 791 | 
            +
             | 
| 773 792 | 
             
                  optional = false
         | 
| 774 793 | 
             
                  blks = []
         | 
| 775 794 | 
             
                  @blk_ty.each_child_global do |ty|
         |