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/block.rb
    CHANGED
    
    | @@ -85,10 +85,13 @@ module TypeProf | |
| 85 85 | 
             
                end
         | 
| 86 86 |  | 
| 87 87 | 
             
                def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, &ctn)
         | 
| 88 | 
            -
                   | 
| 89 | 
            -
                   | 
| 88 | 
            +
                  aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
         | 
| 89 | 
            +
                  subst = aargs.consistent_with_method_signature?(@msig)
         | 
| 90 | 
            +
                  unless subst
         | 
| 90 91 | 
             
                    scratch.warn(caller_ep, "The arguments is not compatibile to RBS block")
         | 
| 91 92 | 
             
                  end
         | 
| 93 | 
            +
                  # check?
         | 
| 94 | 
            +
                  #subst = { Type::Var.new(:self) => caller_env.static_env.recv_ty }
         | 
| 92 95 | 
             
                  # XXX: Update type vars
         | 
| 93 96 | 
             
                  ctn[@ret_ty, caller_ep, caller_env]
         | 
| 94 97 | 
             
                end
         | 
    
        data/lib/typeprof/builtin.rb
    CHANGED
    
    | @@ -54,6 +54,10 @@ module TypeProf | |
| 54 54 | 
             
                  ctn[ret_ty, ep, env]
         | 
| 55 55 | 
             
                end
         | 
| 56 56 |  | 
| 57 | 
            +
                def vmcore_raise(recv, mid, aargs, ep, env, scratch, &ctn)
         | 
| 58 | 
            +
                  # no-op
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 57 61 | 
             
                def lambda(recv, mid, aargs, ep, env, scratch, &ctn)
         | 
| 58 62 | 
             
                  ctn[aargs.blk_ty, ep, env]
         | 
| 59 63 | 
             
                end
         | 
| @@ -63,10 +67,11 @@ module TypeProf | |
| 63 67 | 
             
                end
         | 
| 64 68 |  | 
| 65 69 | 
             
                def object_s_new(recv, mid, aargs, ep, env, scratch, &ctn)
         | 
| 66 | 
            -
                  ty = Type::Instance.new(recv)
         | 
| 67 70 | 
             
                  if recv.type_params.size >= 1
         | 
| 68 | 
            -
                    ty = Type:: | 
| 71 | 
            +
                    ty = Type::ContainerType.create_empty_instance(recv)
         | 
| 69 72 | 
             
                    env, ty = scratch.localize_type(ty, env, ep, AllocationSite.new(ep).add_id(:object_s_new))
         | 
| 73 | 
            +
                  else
         | 
| 74 | 
            +
                    ty = Type::Instance.new(recv)
         | 
| 70 75 | 
             
                  end
         | 
| 71 76 | 
             
                  meths = scratch.get_method(recv, false, :initialize)
         | 
| 72 77 | 
             
                  meths.flat_map do |meth|
         | 
| @@ -149,7 +154,11 @@ module TypeProf | |
| 149 154 |  | 
| 150 155 | 
             
                def module_include(recv, mid, aargs, ep, env, scratch, &ctn)
         | 
| 151 156 | 
             
                  arg = aargs.lead_tys[0]
         | 
| 152 | 
            -
                   | 
| 157 | 
            +
                  arg.each_child do |arg|
         | 
| 158 | 
            +
                    if arg.is_a?(Type::Class)
         | 
| 159 | 
            +
                      scratch.include_module(recv, arg, false, ep.ctx.iseq.absolute_path)
         | 
| 160 | 
            +
                    end
         | 
| 161 | 
            +
                  end
         | 
| 153 162 | 
             
                  ctn[recv, ep, env]
         | 
| 154 163 | 
             
                end
         | 
| 155 164 |  | 
| @@ -157,7 +166,7 @@ module TypeProf | |
| 157 166 | 
             
                  arg = aargs.lead_tys[0]
         | 
| 158 167 | 
             
                  arg.each_child do |arg|
         | 
| 159 168 | 
             
                    if arg.is_a?(Type::Class)
         | 
| 160 | 
            -
                      scratch. | 
| 169 | 
            +
                      scratch.include_module(recv, arg, true, ep.ctx.iseq.absolute_path)
         | 
| 161 170 | 
             
                    end
         | 
| 162 171 | 
             
                  end
         | 
| 163 172 | 
             
                  ctn[recv, ep, env]
         | 
| @@ -520,6 +529,7 @@ module TypeProf | |
| 520 529 | 
             
                  scratch.set_custom_method(klass_vmcore, :"core#set_method_alias", Builtin.method(:vmcore_set_method_alias))
         | 
| 521 530 | 
             
                  scratch.set_custom_method(klass_vmcore, :"core#undef_method", Builtin.method(:vmcore_undef_method))
         | 
| 522 531 | 
             
                  scratch.set_custom_method(klass_vmcore, :"core#hash_merge_kwd", Builtin.method(:vmcore_hash_merge_kwd))
         | 
| 532 | 
            +
                  scratch.set_custom_method(klass_vmcore, :"core#raise", Builtin.method(:vmcore_raise))
         | 
| 523 533 | 
             
                  scratch.set_custom_method(klass_vmcore, :lambda, Builtin.method(:lambda))
         | 
| 524 534 | 
             
                  scratch.set_singleton_custom_method(klass_obj, :"new", Builtin.method(:object_s_new))
         | 
| 525 535 | 
             
                  scratch.set_singleton_custom_method(klass_obj, :"attr_accessor", Builtin.method(:module_attr_accessor))
         | 
    
        data/lib/typeprof/config.rb
    CHANGED
    
    | @@ -69,19 +69,23 @@ module TypeProf | |
| 69 69 | 
             
                prologue_ep = ExecutionPoint.new(prologue_ctx, -1, nil)
         | 
| 70 70 | 
             
                prologue_env = Env.new(StaticEnv.new(:top, Type.nil, false), [], [], Utils::HashWrapper.new({}))
         | 
| 71 71 |  | 
| 72 | 
            -
                Config.rb_files.each do | | 
| 73 | 
            -
                  if  | 
| 74 | 
            -
                    iseq = ISeq.compile_str( | 
| 72 | 
            +
                Config.rb_files.each do |rb|
         | 
| 73 | 
            +
                  if rb.is_a?(Array) # [String name, String content]
         | 
| 74 | 
            +
                    iseq = ISeq.compile_str(*rb.reverse)
         | 
| 75 75 | 
             
                  else
         | 
| 76 | 
            -
                    iseq = ISeq.compile( | 
| 76 | 
            +
                    iseq = ISeq.compile(rb)
         | 
| 77 77 | 
             
                  end
         | 
| 78 78 | 
             
                  ep, env = TypeProf.starting_state(iseq)
         | 
| 79 79 | 
             
                  scratch.merge_env(ep, env)
         | 
| 80 80 | 
             
                  scratch.add_callsite!(ep.ctx, prologue_ep, prologue_env) {|ty, ep| }
         | 
| 81 81 | 
             
                end
         | 
| 82 82 |  | 
| 83 | 
            -
                Config.rbs_files.each do | | 
| 84 | 
            -
                   | 
| 83 | 
            +
                Config.rbs_files.each do |rbs|
         | 
| 84 | 
            +
                  if rbs.is_a?(Array) # [String name, String content]
         | 
| 85 | 
            +
                    Import.import_rbs_code(scratch, *rbs)
         | 
| 86 | 
            +
                  else
         | 
| 87 | 
            +
                    Import.import_rbs_file(scratch, rbs)
         | 
| 88 | 
            +
                  end
         | 
| 85 89 | 
             
                end
         | 
| 86 90 |  | 
| 87 91 | 
             
                result = scratch.type_profile
         | 
| @@ -19,13 +19,44 @@ module TypeProf | |
| 19 19 | 
             
                # Cell, Array, and Hash are types for global interface, e.g., TypedISeq.
         | 
| 20 20 | 
             
                # Do not push such types to local environment, stack, etc.
         | 
| 21 21 |  | 
| 22 | 
            +
                class ContainerType < Type
         | 
| 23 | 
            +
                  def match?(other)
         | 
| 24 | 
            +
                    return nil if self.class != other.class
         | 
| 25 | 
            +
                    return nil unless @base_type.consistent?(other.base_type)
         | 
| 26 | 
            +
                    @elems.match?(other.elems)
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def each_free_type_variable(&blk)
         | 
| 30 | 
            +
                    @elems.each_free_type_variable(&blk)
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def consistent?(other)
         | 
| 34 | 
            +
                    raise "must not be used"
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def self.create_empty_instance(klass)
         | 
| 38 | 
            +
                    base_type = Type::Instance.new(klass)
         | 
| 39 | 
            +
                    case klass
         | 
| 40 | 
            +
                    when Type::Builtin[:ary] # XXX: check inheritance...
         | 
| 41 | 
            +
                      Type::Array.new(Type::Array::Elements.new([], Type.bot), base_type)
         | 
| 42 | 
            +
                    when Type::Builtin[:hash]
         | 
| 43 | 
            +
                      Type.gen_hash(base_type) {|h| }
         | 
| 44 | 
            +
                    else
         | 
| 45 | 
            +
                      Type::Cell.new(Type::Cell::Elements.new([Type.bot] * klass.type_params.size), base_type)
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 22 50 | 
             
                # The most basic container type for default type parameter class
         | 
| 23 | 
            -
                class Cell <  | 
| 51 | 
            +
                class Cell < ContainerType
         | 
| 24 52 | 
             
                  def initialize(elems, base_type)
         | 
| 25 53 | 
             
                    raise if !elems.is_a?(Cell::Elements)
         | 
| 26 54 | 
             
                    @elems = elems # Cell::Elements
         | 
| 27 55 | 
             
                    raise unless base_type
         | 
| 28 56 | 
             
                    @base_type = base_type
         | 
| 57 | 
            +
                    if base_type.klass.type_params.size != elems.elems.size
         | 
| 58 | 
            +
                      raise
         | 
| 59 | 
            +
                    end
         | 
| 29 60 | 
             
                  end
         | 
| 30 61 |  | 
| 31 62 | 
             
                  attr_reader :elems, :base_type
         | 
| @@ -44,7 +75,7 @@ module TypeProf | |
| 44 75 |  | 
| 45 76 | 
             
                  def localize(env, alloc_site, depth)
         | 
| 46 77 | 
             
                    return env, Type.any if depth <= 0
         | 
| 47 | 
            -
                    alloc_site = alloc_site.add_id(:cell)
         | 
| 78 | 
            +
                    alloc_site = alloc_site.add_id(:cell).add_id(@base_type)
         | 
| 48 79 | 
             
                    env, elems = @elems.localize(env, alloc_site, depth)
         | 
| 49 80 | 
             
                    env.deploy_type(LocalCell, alloc_site, elems, @base_type)
         | 
| 50 81 | 
             
                  end
         | 
| @@ -58,31 +89,13 @@ module TypeProf | |
| 58 89 | 
             
                    raise
         | 
| 59 90 | 
             
                  end
         | 
| 60 91 |  | 
| 61 | 
            -
                  def consistent?(other, subst)
         | 
| 62 | 
            -
                    case other
         | 
| 63 | 
            -
                    when Type::Any then true
         | 
| 64 | 
            -
                    when Type::Var then other.add_subst!(self, subst)
         | 
| 65 | 
            -
                    when Type::Union
         | 
| 66 | 
            -
                      other.types.each do |ty2|
         | 
| 67 | 
            -
                        return true if consistent?(ty2, subst)
         | 
| 68 | 
            -
                      end
         | 
| 69 | 
            -
                      return false
         | 
| 70 | 
            -
                    when Type::Cell
         | 
| 71 | 
            -
                      @elems.size == other.elems.size &&
         | 
| 72 | 
            -
                        @base_type.consistent?(other.base_type, subst) &&
         | 
| 73 | 
            -
                        @elems.zip(other.elems).all? {|elem1, elem2| elem1..consistent?(elem2, subst) }
         | 
| 74 | 
            -
                    else
         | 
| 75 | 
            -
                      self == other
         | 
| 76 | 
            -
                    end
         | 
| 77 | 
            -
                  end
         | 
| 78 | 
            -
             | 
| 79 92 | 
             
                  def substitute(subst, depth)
         | 
| 80 93 | 
             
                    return Type.any if depth <= 0
         | 
| 81 94 | 
             
                    elems = @elems.substitute(subst, depth)
         | 
| 82 95 | 
             
                    Cell.new(elems, @base_type)
         | 
| 83 96 | 
             
                  end
         | 
| 84 97 |  | 
| 85 | 
            -
                  class Elements
         | 
| 98 | 
            +
                  class Elements # Cell
         | 
| 86 99 | 
             
                    include Utils::StructuralEquality
         | 
| 87 100 |  | 
| 88 101 | 
             
                    def initialize(elems)
         | 
| @@ -124,12 +137,21 @@ module TypeProf | |
| 124 137 | 
             
                      end
         | 
| 125 138 | 
             
                    end
         | 
| 126 139 |  | 
| 127 | 
            -
                    def  | 
| 128 | 
            -
                       | 
| 140 | 
            +
                    def match?(other)
         | 
| 141 | 
            +
                      return nil if @elems.size != other.elems.size
         | 
| 142 | 
            +
                      subst = nil
         | 
| 129 143 | 
             
                      @elems.zip(other.elems) do |ty0, ty1|
         | 
| 130 | 
            -
                         | 
| 144 | 
            +
                        subst2 = Type.match?(ty0, ty1)
         | 
| 145 | 
            +
                        return nil unless subst2
         | 
| 146 | 
            +
                        subst = Type.merge_substitution(subst, subst2)
         | 
| 147 | 
            +
                      end
         | 
| 148 | 
            +
                      subst
         | 
| 149 | 
            +
                    end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                    def each_free_type_variable(&blk)
         | 
| 152 | 
            +
                      @elems.each do |ty|
         | 
| 153 | 
            +
                        ty.each_free_type_variable(&blk)
         | 
| 131 154 | 
             
                      end
         | 
| 132 | 
            -
                      return true
         | 
| 133 155 | 
             
                    end
         | 
| 134 156 |  | 
| 135 157 | 
             
                    def substitute(subst, depth)
         | 
| @@ -146,6 +168,9 @@ module TypeProf | |
| 146 168 |  | 
| 147 169 | 
             
                    def union(other)
         | 
| 148 170 | 
             
                      return self if self == other
         | 
| 171 | 
            +
                      if @elems.size != other.elems.size
         | 
| 172 | 
            +
                        raise "#{ @elems.size } != #{ other.elems.size }"
         | 
| 173 | 
            +
                      end
         | 
| 149 174 | 
             
                      elems = []
         | 
| 150 175 | 
             
                      @elems.zip(other.elems) do |ty0, ty1|
         | 
| 151 176 | 
             
                        elems << ty0.union(ty1)
         | 
| @@ -155,7 +180,7 @@ module TypeProf | |
| 155 180 | 
             
                  end
         | 
| 156 181 | 
             
                end
         | 
| 157 182 |  | 
| 158 | 
            -
                class LocalCell <  | 
| 183 | 
            +
                class LocalCell < ContainerType
         | 
| 159 184 | 
             
                  def initialize(id, base_type)
         | 
| 160 185 | 
             
                    @id = id
         | 
| 161 186 | 
             
                    raise unless base_type
         | 
| @@ -184,6 +209,7 @@ module TypeProf | |
| 184 209 | 
             
                      else
         | 
| 185 210 | 
             
                        elems = Cell::Elements.new([]) # XXX
         | 
| 186 211 | 
             
                      end
         | 
| 212 | 
            +
                      visited.delete(self)
         | 
| 187 213 | 
             
                      Cell.new(elems, @base_type)
         | 
| 188 214 | 
             
                    end
         | 
| 189 215 | 
             
                  end
         | 
| @@ -191,14 +217,10 @@ module TypeProf | |
| 191 217 | 
             
                  def get_method(mid, scratch)
         | 
| 192 218 | 
             
                    @base_type.get_method(mid, scratch)
         | 
| 193 219 | 
             
                  end
         | 
| 194 | 
            -
             | 
| 195 | 
            -
                  def consistent?(other, subst)
         | 
| 196 | 
            -
                    raise "must not be used"
         | 
| 197 | 
            -
                  end
         | 
| 198 220 | 
             
                end
         | 
| 199 221 |  | 
| 200 222 | 
             
                # Do not insert Array type to local environment, stack, etc.
         | 
| 201 | 
            -
                class Array <  | 
| 223 | 
            +
                class Array < ContainerType
         | 
| 202 224 | 
             
                  def initialize(elems, base_type)
         | 
| 203 225 | 
             
                    raise unless elems.is_a?(Array::Elements)
         | 
| 204 226 | 
             
                    @elems = elems # Array::Elements
         | 
| @@ -223,7 +245,7 @@ module TypeProf | |
| 223 245 |  | 
| 224 246 | 
             
                  def localize(env, alloc_site, depth)
         | 
| 225 247 | 
             
                    return env, Type.any if depth <= 0
         | 
| 226 | 
            -
                    alloc_site = alloc_site.add_id(:ary)
         | 
| 248 | 
            +
                    alloc_site = alloc_site.add_id(:ary).add_id(@base_type)
         | 
| 227 249 | 
             
                    env, elems = @elems.localize(env, alloc_site, depth - 1)
         | 
| 228 250 | 
             
                    env.deploy_type(LocalArray, alloc_site, elems, @base_type)
         | 
| 229 251 | 
             
                  end
         | 
| @@ -237,29 +259,13 @@ module TypeProf | |
| 237 259 | 
             
                    raise
         | 
| 238 260 | 
             
                  end
         | 
| 239 261 |  | 
| 240 | 
            -
                  def consistent?(other, subst)
         | 
| 241 | 
            -
                    case other
         | 
| 242 | 
            -
                    when Type::Any then true
         | 
| 243 | 
            -
                    when Type::Var then other.add_subst!(self, subst)
         | 
| 244 | 
            -
                    when Type::Union
         | 
| 245 | 
            -
                      other.types.each do |ty2|
         | 
| 246 | 
            -
                        return true if consistent?(ty2, subst)
         | 
| 247 | 
            -
                      end
         | 
| 248 | 
            -
                      return false
         | 
| 249 | 
            -
                    when Type::Array
         | 
| 250 | 
            -
                      @base_type.consistent?(other.base_type, subst) && @elems.consistent?(other.elems, subst)
         | 
| 251 | 
            -
                    else
         | 
| 252 | 
            -
                      self == other
         | 
| 253 | 
            -
                    end
         | 
| 254 | 
            -
                  end
         | 
| 255 | 
            -
             | 
| 256 262 | 
             
                  def substitute(subst, depth)
         | 
| 257 263 | 
             
                    return Type.any if depth <= 0
         | 
| 258 264 | 
             
                    elems = @elems.substitute(subst, depth - 1)
         | 
| 259 265 | 
             
                    Array.new(elems, @base_type)
         | 
| 260 266 | 
             
                  end
         | 
| 261 267 |  | 
| 262 | 
            -
                  class Elements
         | 
| 268 | 
            +
                  class Elements # Array
         | 
| 263 269 | 
             
                    include Utils::StructuralEquality
         | 
| 264 270 |  | 
| 265 271 | 
             
                    def initialize(lead_tys, rest_ty = Type.bot)
         | 
| @@ -300,6 +306,9 @@ module TypeProf | |
| 300 306 |  | 
| 301 307 | 
             
                    def screen_name(scratch)
         | 
| 302 308 | 
             
                      if Config.options[:show_container_raw_elements] || @rest_ty == Type.bot
         | 
| 309 | 
            +
                        if @lead_tys.empty?
         | 
| 310 | 
            +
                          return "Array[bot]" # RBS does not allow an empty tuple "[]"
         | 
| 311 | 
            +
                        end
         | 
| 303 312 | 
             
                        s = @lead_tys.map do |ty|
         | 
| 304 313 | 
             
                          ty.screen_name(scratch)
         | 
| 305 314 | 
             
                        end
         | 
| @@ -318,14 +327,24 @@ module TypeProf | |
| 318 327 | 
             
                      end
         | 
| 319 328 | 
             
                    end
         | 
| 320 329 |  | 
| 321 | 
            -
                    def  | 
| 330 | 
            +
                    def match?(other)
         | 
| 322 331 | 
             
                      n = [@lead_tys.size, other.lead_tys.size].min
         | 
| 323 | 
            -
                      n.times do |i|
         | 
| 324 | 
            -
                        return false unless @lead_tys[i].consistent?(other.lead_tys[i], subst)
         | 
| 325 | 
            -
                      end
         | 
| 326 332 | 
             
                      rest_ty1 = @lead_tys[n..].inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) }
         | 
| 327 333 | 
             
                      rest_ty2 = other.lead_tys[n..].inject(other.rest_ty) {|ty1, ty2| ty1.union(ty2) }
         | 
| 328 | 
            -
                       | 
| 334 | 
            +
                      subst = nil
         | 
| 335 | 
            +
                      (@lead_tys[0, n] + [rest_ty1]).zip(other.lead_tys[0, n] + [rest_ty2]) do |ty0, ty1|
         | 
| 336 | 
            +
                        subst2 = Type.match?(ty0, ty1)
         | 
| 337 | 
            +
                        return nil unless subst2
         | 
| 338 | 
            +
                        subst = Type.merge_substitution(subst, subst2)
         | 
| 339 | 
            +
                      end
         | 
| 340 | 
            +
                      subst
         | 
| 341 | 
            +
                    end
         | 
| 342 | 
            +
             | 
| 343 | 
            +
                    def each_free_type_variable(&blk)
         | 
| 344 | 
            +
                      @lead_tys.each do |ty|
         | 
| 345 | 
            +
                        ty.each_free_type_variable(&blk)
         | 
| 346 | 
            +
                      end
         | 
| 347 | 
            +
                      @rest_ty&.each_free_type_variable(&blk)
         | 
| 329 348 | 
             
                    end
         | 
| 330 349 |  | 
| 331 350 | 
             
                    def substitute(subst, depth)
         | 
| @@ -476,7 +495,7 @@ module TypeProf | |
| 476 495 | 
             
                end
         | 
| 477 496 |  | 
| 478 497 | 
             
                # Do not insert Array type to local environment, stack, etc.
         | 
| 479 | 
            -
                class LocalArray <  | 
| 498 | 
            +
                class LocalArray < ContainerType
         | 
| 480 499 | 
             
                  def initialize(id, base_type)
         | 
| 481 500 | 
             
                    @id = id
         | 
| 482 501 | 
             
                    raise unless base_type
         | 
| @@ -506,6 +525,7 @@ module TypeProf | |
| 506 525 | 
             
                        # TODO: currently out-of-scope array cannot be accessed
         | 
| 507 526 | 
             
                        elems = Array::Elements.new([], Type.any)
         | 
| 508 527 | 
             
                      end
         | 
| 528 | 
            +
                      visited.delete(self)
         | 
| 509 529 | 
             
                      Array.new(elems, @base_type)
         | 
| 510 530 | 
             
                    end
         | 
| 511 531 | 
             
                  end
         | 
| @@ -513,14 +533,10 @@ module TypeProf | |
| 513 533 | 
             
                  def get_method(mid, scratch)
         | 
| 514 534 | 
             
                    @base_type.get_method(mid, scratch)
         | 
| 515 535 | 
             
                  end
         | 
| 516 | 
            -
             | 
| 517 | 
            -
                  def consistent?(other, subst)
         | 
| 518 | 
            -
                    raise "must not be used"
         | 
| 519 | 
            -
                  end
         | 
| 520 536 | 
             
                end
         | 
| 521 537 |  | 
| 522 538 |  | 
| 523 | 
            -
                class Hash <  | 
| 539 | 
            +
                class Hash < ContainerType
         | 
| 524 540 | 
             
                  def initialize(elems, base_type)
         | 
| 525 541 | 
             
                    @elems = elems
         | 
| 526 542 | 
             
                    raise unless elems
         | 
| @@ -539,7 +555,7 @@ module TypeProf | |
| 539 555 |  | 
| 540 556 | 
             
                  def localize(env, alloc_site, depth)
         | 
| 541 557 | 
             
                    return env, Type.any if depth <= 0
         | 
| 542 | 
            -
                    alloc_site = alloc_site.add_id(:hash)
         | 
| 558 | 
            +
                    alloc_site = alloc_site.add_id(:hash).add_id(@base_type)
         | 
| 543 559 | 
             
                    env, elems = @elems.localize(env, alloc_site, depth - 1)
         | 
| 544 560 | 
             
                    env.deploy_type(LocalHash, alloc_site, elems, @base_type)
         | 
| 545 561 | 
             
                  end
         | 
| @@ -553,29 +569,13 @@ module TypeProf | |
| 553 569 | 
             
                    raise
         | 
| 554 570 | 
             
                  end
         | 
| 555 571 |  | 
| 556 | 
            -
                  def consistent?(other, subst)
         | 
| 557 | 
            -
                    case other
         | 
| 558 | 
            -
                    when Type::Any then true
         | 
| 559 | 
            -
                    when Type::Var then other.add_subst!(self, subst)
         | 
| 560 | 
            -
                    when Type::Union
         | 
| 561 | 
            -
                      other.types.each do |ty2|
         | 
| 562 | 
            -
                        return true if consistent?(ty2, subst)
         | 
| 563 | 
            -
                      end
         | 
| 564 | 
            -
                      return false
         | 
| 565 | 
            -
                    when Type::Hash
         | 
| 566 | 
            -
                      @base_type.consistent?(other.base_type, subst) && @elems.consistent?(other.elems, subst)
         | 
| 567 | 
            -
                    else
         | 
| 568 | 
            -
                      self == other
         | 
| 569 | 
            -
                    end
         | 
| 570 | 
            -
                  end
         | 
| 571 | 
            -
             | 
| 572 572 | 
             
                  def substitute(subst, depth)
         | 
| 573 573 | 
             
                    return Type.any if depth <= 0
         | 
| 574 574 | 
             
                    elems = @elems.substitute(subst, depth - 1)
         | 
| 575 575 | 
             
                    Hash.new(elems, @base_type)
         | 
| 576 576 | 
             
                  end
         | 
| 577 577 |  | 
| 578 | 
            -
                  class Elements
         | 
| 578 | 
            +
                  class Elements # Hash
         | 
| 579 579 | 
             
                    include Utils::StructuralEquality
         | 
| 580 580 |  | 
| 581 581 | 
             
                    def initialize(map_tys)
         | 
| @@ -634,12 +634,22 @@ module TypeProf | |
| 634 634 | 
             
                    end
         | 
| 635 635 |  | 
| 636 636 | 
             
                    def screen_name(scratch)
         | 
| 637 | 
            -
                       | 
| 638 | 
            -
                         | 
| 639 | 
            -
             | 
| 640 | 
            -
             | 
| 641 | 
            -
             | 
| 642 | 
            -
             | 
| 637 | 
            +
                      if !@map_tys.empty? && @map_tys.all? {|k_ty,| k_ty.is_a?(Type::Symbol) }
         | 
| 638 | 
            +
                        s = @map_tys.map do |k_ty, v_ty|
         | 
| 639 | 
            +
                          v = v_ty.screen_name(scratch)
         | 
| 640 | 
            +
                          "#{ k_ty.sym }: #{ v }"
         | 
| 641 | 
            +
                        end.join(", ")
         | 
| 642 | 
            +
                        "{#{ s }}"
         | 
| 643 | 
            +
                      else
         | 
| 644 | 
            +
                        k_ty = v_ty = Type.bot
         | 
| 645 | 
            +
                        @map_tys.each do |k, v|
         | 
| 646 | 
            +
                          k_ty = k_ty.union(k)
         | 
| 647 | 
            +
                          v_ty = v_ty.union(v)
         | 
| 648 | 
            +
                        end
         | 
| 649 | 
            +
                        k_ty = k_ty.screen_name(scratch)
         | 
| 650 | 
            +
                        v_ty = v_ty.screen_name(scratch)
         | 
| 651 | 
            +
                        "Hash[#{ k_ty }, #{ v_ty }]"
         | 
| 652 | 
            +
                      end
         | 
| 643 653 | 
             
                    end
         | 
| 644 654 |  | 
| 645 655 | 
             
                    def pretty_print(q)
         | 
| @@ -657,22 +667,31 @@ module TypeProf | |
| 657 667 | 
             
                      end
         | 
| 658 668 | 
             
                    end
         | 
| 659 669 |  | 
| 660 | 
            -
                    def  | 
| 661 | 
            -
                       | 
| 670 | 
            +
                    def match?(other)
         | 
| 671 | 
            +
                      subst = nil
         | 
| 662 672 | 
             
                      other.map_tys.each do |k1, v1|
         | 
| 663 | 
            -
                         | 
| 673 | 
            +
                        subst2 = nil
         | 
| 664 674 | 
             
                        @map_tys.each do |k0, v0|
         | 
| 665 | 
            -
                          subst3 =  | 
| 666 | 
            -
                          if  | 
| 667 | 
            -
                             | 
| 668 | 
            -
                             | 
| 669 | 
            -
             | 
| 675 | 
            +
                          subst3 = Type.match?(k0, k1)
         | 
| 676 | 
            +
                          if subst3
         | 
| 677 | 
            +
                            subst4 = Type.match?(v0, v1)
         | 
| 678 | 
            +
                            if subst4
         | 
| 679 | 
            +
                              subst2 = Type.merge_substitution(subst2, subst3)
         | 
| 680 | 
            +
                              subst2 = Type.merge_substitution(subst2, subst4)
         | 
| 681 | 
            +
                            end
         | 
| 670 682 | 
             
                          end
         | 
| 671 683 | 
             
                        end
         | 
| 672 | 
            -
                        return  | 
| 684 | 
            +
                        return nil unless subst2
         | 
| 685 | 
            +
                        subst = Type.merge_substitution(subst, subst2)
         | 
| 686 | 
            +
                      end
         | 
| 687 | 
            +
                      subst
         | 
| 688 | 
            +
                    end
         | 
| 689 | 
            +
             | 
| 690 | 
            +
                    def each_free_type_variable(&blk)
         | 
| 691 | 
            +
                      @map_tys.each do |k, v|
         | 
| 692 | 
            +
                        k.each_free_type_variable(&blk)
         | 
| 693 | 
            +
                        v.each_free_type_variable(&blk)
         | 
| 673 694 | 
             
                      end
         | 
| 674 | 
            -
                      subst.replace(subst2)
         | 
| 675 | 
            -
                      true
         | 
| 676 695 | 
             
                    end
         | 
| 677 696 |  | 
| 678 697 | 
             
                    def substitute(subst, depth)
         | 
| @@ -706,7 +725,7 @@ module TypeProf | |
| 706 725 | 
             
                    def [](key_ty)
         | 
| 707 726 | 
             
                      val_ty = Type.bot
         | 
| 708 727 | 
             
                      @map_tys.each do |k_ty, v_ty|
         | 
| 709 | 
            -
                        if  | 
| 728 | 
            +
                        if Type.match?(k_ty, key_ty)
         | 
| 710 729 | 
             
                          val_ty = val_ty.union(v_ty)
         | 
| 711 730 | 
             
                        end
         | 
| 712 731 | 
             
                      end
         | 
| @@ -763,7 +782,7 @@ module TypeProf | |
| 763 782 | 
             
                  end
         | 
| 764 783 | 
             
                end
         | 
| 765 784 |  | 
| 766 | 
            -
                class LocalHash <  | 
| 785 | 
            +
                class LocalHash < ContainerType
         | 
| 767 786 | 
             
                  def initialize(id, base_type)
         | 
| 768 787 | 
             
                    @id = id
         | 
| 769 788 | 
             
                    @base_type = base_type
         | 
| @@ -791,6 +810,7 @@ module TypeProf | |
| 791 810 | 
             
                      else
         | 
| 792 811 | 
             
                        elems = Hash::Elements.new({Type.any => Type.any})
         | 
| 793 812 | 
             
                      end
         | 
| 813 | 
            +
                      visited.delete(self)
         | 
| 794 814 | 
             
                      Hash.new(elems, @base_type)
         | 
| 795 815 | 
             
                    end
         | 
| 796 816 | 
             
                  end
         | 
| @@ -798,10 +818,6 @@ module TypeProf | |
| 798 818 | 
             
                  def get_method(mid, scratch)
         | 
| 799 819 | 
             
                    @base_type.get_method(mid, scratch)
         | 
| 800 820 | 
             
                  end
         | 
| 801 | 
            -
             | 
| 802 | 
            -
                  def consistent?(other, subst)
         | 
| 803 | 
            -
                    raise "must not be used"
         | 
| 804 | 
            -
                  end
         | 
| 805 821 | 
             
                end
         | 
| 806 822 | 
             
              end
         | 
| 807 823 | 
             
            end
         |