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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +1 -2
  3. data/Gemfile.lock +3 -3
  4. data/README.md +6 -0
  5. data/lib/typeprof/analyzer.rb +97 -84
  6. data/lib/typeprof/arguments.rb +27 -19
  7. data/lib/typeprof/block.rb +5 -2
  8. data/lib/typeprof/builtin.rb +14 -4
  9. data/lib/typeprof/config.rb +10 -6
  10. data/lib/typeprof/container-type.rb +117 -101
  11. data/lib/typeprof/export.rb +1 -1
  12. data/lib/typeprof/import.rb +44 -22
  13. data/lib/typeprof/method.rb +70 -12
  14. data/lib/typeprof/type.rb +108 -89
  15. data/lib/typeprof/version.rb +1 -1
  16. data/smoke/arguments2.rb +1 -1
  17. data/smoke/array11.rb +1 -1
  18. data/smoke/array6.rb +2 -2
  19. data/smoke/array8.rb +1 -1
  20. data/smoke/block-args2.rb +3 -3
  21. data/smoke/block-args3.rb +4 -4
  22. data/smoke/block-blockarg.rb +1 -1
  23. data/smoke/block-kwarg.rb +1 -1
  24. data/smoke/block10.rb +1 -1
  25. data/smoke/block5.rb +1 -1
  26. data/smoke/constant2.rb +1 -2
  27. data/smoke/demo5.rb +1 -1
  28. data/smoke/demo9.rb +1 -1
  29. data/smoke/hash-fetch.rb +3 -3
  30. data/smoke/hash-merge-bang.rb +11 -0
  31. data/smoke/hash1.rb +3 -2
  32. data/smoke/hash3.rb +1 -1
  33. data/smoke/inheritance2.rb +2 -2
  34. data/smoke/ivar2.rb +2 -2
  35. data/smoke/kernel-class.rb +1 -1
  36. data/smoke/keyword4.rb +1 -1
  37. data/smoke/kwsplat1.rb +2 -2
  38. data/smoke/kwsplat2.rb +1 -1
  39. data/smoke/multiple-superclass.rb +1 -1
  40. data/smoke/parameterizedd-self.rb +2 -2
  41. data/smoke/pattern-match1.rb +23 -0
  42. data/smoke/pattern-match2.rb +15 -0
  43. data/smoke/rbs-tyvar3.rb +11 -19
  44. data/smoke/rbs-tyvar3.rbs +4 -3
  45. data/smoke/rbs-tyvar4.rb +36 -0
  46. data/smoke/rbs-tyvar5.rb +12 -0
  47. data/smoke/rbs-tyvar5.rbs +8 -0
  48. data/smoke/struct.rb +2 -2
  49. data/smoke/uninitialize-var.rb +12 -0
  50. data/smoke/union-recv.rb +2 -2
  51. data/typeprof.gemspec +1 -1
  52. metadata +11 -4
@@ -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?
@@ -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
- @builtin_env_json = load_rbs(@builtin_env, builtin: true)
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
- RBSReader.load_rbs(@env, library: lib)
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
- RBSReader.load_rbs(@env, path: path)
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 self.load_rbs(env, builtin: false, **opt)
32
- if builtin
33
- loader = RBS::EnvironmentLoader.new
34
- else
35
- loader = RBS::EnvironmentLoader.new(core_root: nil)
36
- loader.add(**opt)
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
- new_decls = loader.load(env: env)
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
- [:instance, klass]
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.extend_module(klass, path_to_klass(mod), nil)
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, value|
519
- @scratch.add_gvar_write!(name, conv_type(value), nil)
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
@@ -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 = { Type::Var.new(:self) => recv }
179
- next unless aargs.consistent_with_method_signature?(msig, subst)
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.squash_or_any })
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
- # XXX: need to support destructive operation
213
- k_ty, v_ty = recv.elems.squash
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 => k_ty, tyvar_v => v_ty })
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
- dummy_env = Env.new(StaticEnv.new(recv, msig.blk_ty, false), [], [], Utils::HashWrapper.new({}))
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 blk_ret_ty.consistent?(msig.blk_ty.block_body.ret_ty, subst2)
245
- if recv.is_a?(Type::Array) && recv_orig.is_a?(Type::LocalArray)
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(nil, subst2[tyvar_elem])
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
@@ -20,16 +20,69 @@ module TypeProf
20
20
  self
21
21
  end
22
22
 
23
- def consistent?(other, subst)
24
- case other
25
- when Type::Any then true
26
- when Type::Var then other.add_subst!(self, subst)
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
- other.types.each do |ty2|
29
- return true if consistent?(ty2, subst)
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
- self == other
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?(other, subst)
122
- # need to create a type assignment if other is Var
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
- alloc_site2 = alloc_site.add_id(ty)
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
- alloc_site2 = alloc_site.add_id(container_kind.name.to_sym).add_id(base_type)
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?(other, subst)
289
- case other
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?(other, subst)
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) }.class"
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, subst)
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, subst)
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, subst)
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, type)
524
- @block_body, @type = block_body, type
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, :type
550
+ attr_reader :block_body, :base_type
528
551
 
529
- def consistent?(other, subst)
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
- @type.get_method(mid, scratch)
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), @type)
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, subst)
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, subst)
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 info
612
+ # A local type
598
613
  class Literal < Type
599
- def initialize(lit, type)
614
+ def initialize(lit, base_type)
600
615
  @lit = lit
601
- @type = type
616
+ @base_type = base_type
602
617
  end
603
618
 
604
- attr_reader :lit, :type
619
+ attr_reader :lit, :base_type
605
620
 
606
621
  def inspect
607
- "Type::Literal[#{ @lit.inspect }, #{ @type.inspect }]"
622
+ "Type::Literal[#{ @lit.inspect }, #{ @base_type.inspect }]"
608
623
  end
609
624
 
610
625
  def screen_name(scratch)
611
- @type.screen_name(scratch) + "<#{ @lit.inspect }>"
626
+ @base_type.screen_name(scratch) + "<#{ @lit.inspect }>"
612
627
  end
613
628
 
614
629
  def globalize(_env, _visited, _depth)
615
- @type
630
+ @base_type
616
631
  end
617
632
 
618
633
  def get_method(mid, scratch)
619
- @type.get_method(mid, scratch)
634
+ @base_type.get_method(mid, scratch)
620
635
  end
621
636
 
622
- def consistent?(other, subst)
623
- @type.consistent?(other, subst)
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|