typeprof 0.5.0 → 0.6.0

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.
@@ -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 |file|
73
- if file.respond_to?(:read)
74
- iseq = ISeq.compile_str(file.read, file.to_s)
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(file)
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 |path|
84
- Import.import_rbs_file(scratch, path)
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
@@ -85,7 +85,7 @@ module TypeProf
85
85
  Cell.new(@elems.limit_size(limit - 1), @base_type)
86
86
  end
87
87
 
88
- def get_method(mid, scratch)
88
+ def method_dispatch_info
89
89
  raise
90
90
  end
91
91
 
@@ -214,8 +214,8 @@ module TypeProf
214
214
  end
215
215
  end
216
216
 
217
- def get_method(mid, scratch)
218
- @base_type.get_method(mid, scratch)
217
+ def method_dispatch_info
218
+ @base_type.method_dispatch_info
219
219
  end
220
220
  end
221
221
 
@@ -255,7 +255,7 @@ module TypeProf
255
255
  Array.new(@elems.limit_size(limit - 1), @base_type)
256
256
  end
257
257
 
258
- def get_method(mid, scratch)
258
+ def method_dispatch_info
259
259
  raise
260
260
  end
261
261
 
@@ -306,6 +306,9 @@ module TypeProf
306
306
 
307
307
  def screen_name(scratch)
308
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
309
312
  s = @lead_tys.map do |ty|
310
313
  ty.screen_name(scratch)
311
314
  end
@@ -527,8 +530,8 @@ module TypeProf
527
530
  end
528
531
  end
529
532
 
530
- def get_method(mid, scratch)
531
- @base_type.get_method(mid, scratch)
533
+ def method_dispatch_info
534
+ @base_type.method_dispatch_info
532
535
  end
533
536
  end
534
537
 
@@ -562,7 +565,7 @@ module TypeProf
562
565
  Hash.new(@elems.limit_size(limit - 1), @base_type)
563
566
  end
564
567
 
565
- def get_method(mid, scratch)
568
+ def method_dispatch_info
566
569
  raise
567
570
  end
568
571
 
@@ -631,16 +634,22 @@ module TypeProf
631
634
  end
632
635
 
633
636
  def screen_name(scratch)
634
- s = @map_tys.map do |k_ty, v_ty|
635
- v = v_ty.screen_name(scratch)
636
- if k_ty.is_a?(Type::Symbol)
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)
637
640
  "#{ k_ty.sym }: #{ v }"
638
- else
639
- k = k_ty.screen_name(scratch)
640
- "#{ k }=>#{ 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)
641
648
  end
642
- end.join(", ")
643
- "{#{ s }}"
649
+ k_ty = k_ty.screen_name(scratch)
650
+ v_ty = v_ty.screen_name(scratch)
651
+ "Hash[#{ k_ty }, #{ v_ty }]"
652
+ end
644
653
  end
645
654
 
646
655
  def pretty_print(q)
@@ -806,8 +815,8 @@ module TypeProf
806
815
  end
807
816
  end
808
817
 
809
- def get_method(mid, scratch)
810
- @base_type.get_method(mid, scratch)
818
+ def method_dispatch_info
819
+ @base_type.method_dispatch_info
811
820
  end
812
821
  end
813
822
  end
@@ -91,9 +91,9 @@ module TypeProf
91
91
  def conv_class(namespace, class_def, inner_classes)
92
92
  @scratch.namespace = namespace
93
93
 
94
- if class_def.superclass
95
- omit = @class_defs[class_def.superclass].klass_obj == Type::Builtin[:obj] || class_def.klass_obj == Type::Builtin[:obj]
96
- superclass = omit ? nil : @scratch.get_class_name(@class_defs[class_def.superclass].klass_obj)
94
+ if class_def.klass_obj.superclass != :__root__ && class_def.klass_obj.superclass
95
+ omit = class_def.klass_obj.superclass == Type::Builtin[:obj] || class_def.klass_obj == Type::Builtin[:obj]
96
+ superclass = omit ? nil : @scratch.get_class_name(class_def.klass_obj.superclass)
97
97
  end
98
98
 
99
99
  @scratch.namespace = class_def.name
@@ -105,12 +105,12 @@ module TypeProf
105
105
  consts[name] = ty.screen_name(@scratch)
106
106
  end
107
107
 
108
- included_mods = class_def.modules[false].filter_map do |mod_def, absolute_paths|
108
+ included_mods = class_def.modules[false].filter_map do |mod_def, _type_args, absolute_paths|
109
109
  next if absolute_paths.all? {|path| !path || Config.check_dir_filter(path) == :exclude }
110
110
  Type::Instance.new(mod_def.klass_obj).screen_name(@scratch)
111
111
  end
112
112
 
113
- extended_mods = class_def.modules[true].filter_map do |mod_def, absolute_paths|
113
+ extended_mods = class_def.modules[true].filter_map do |mod_def, _type_args, absolute_paths|
114
114
  next if absolute_paths.all? {|path| !path || Config.check_dir_filter(path) == :exclude }
115
115
  Type::Instance.new(mod_def.klass_obj).screen_name(@scratch)
116
116
  end
@@ -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
 
@@ -90,9 +100,13 @@ module TypeProf
90
100
  json = {}
91
101
 
92
102
  each_class_decl do |name, decls|
93
- super_class_name = get_super_class_name(name, decls)
94
103
  klass = conv_type_name(name)
95
- superclass = super_class_name ? conv_type_name(super_class_name) : nil
104
+ super_class_name, super_class_args = get_super_class(name, decls)
105
+ if super_class_name
106
+ name = conv_type_name(super_class_name)
107
+ type_args = super_class_args.map {|type| conv_type(type) }
108
+ superclass = [name, type_args]
109
+ end
96
110
 
97
111
  type_params = nil
98
112
  included_modules = []
@@ -155,7 +169,8 @@ module TypeProf
155
169
  name = member.name
156
170
  if name.kind == :class
157
171
  mod = conv_type_name(name)
158
- included_modules << mod
172
+ type_args = member.args.map {|type| conv_type(type) }
173
+ included_modules << [mod, type_args]
159
174
  else
160
175
  # including an interface is not supported yet
161
176
  end
@@ -164,7 +179,8 @@ module TypeProf
164
179
  name = member.name
165
180
  if name.kind == :class
166
181
  mod = conv_type_name(name)
167
- extended_modules << mod
182
+ type_args = member.args.map {|type| conv_type(type) }
183
+ extended_modules << [mod, type_args]
168
184
  else
169
185
  # extending a module with an interface is not supported yet
170
186
  end
@@ -246,14 +262,15 @@ module TypeProf
246
262
  end
247
263
  end
248
264
 
249
- def get_super_class_name(name, decls)
265
+ def get_super_class(name, decls)
250
266
  return nil if name == RBS::BuiltinNames::BasicObject.name
251
267
 
252
268
  decls.each do |decl|
253
269
  decl = decl.decl
254
270
  case decl
255
271
  when RBS::AST::Declarations::Class
256
- return decl.super_class.name if decl.super_class
272
+ super_class = decl.super_class
273
+ return super_class.name, super_class.args if super_class
257
274
  when RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface
258
275
  return nil
259
276
  else
@@ -261,7 +278,7 @@ module TypeProf
261
278
  end
262
279
  end
263
280
 
264
- return RBS::BuiltinNames::Object.name
281
+ return RBS::BuiltinNames::Object.name, []
265
282
  end
266
283
 
267
284
  def conv_method_def(rbs_method_types)
@@ -445,6 +462,10 @@ module TypeProf
445
462
  Import.new(scratch, scratch.rbs_reader.load_path(rbs_path)).import(true)
446
463
  end
447
464
 
465
+ def self.import_rbs_code(scratch, rbs_name, rbs_code)
466
+ Import.new(scratch, scratch.rbs_reader.load_rbs_string(rbs_name, rbs_code)).import(true)
467
+ end
468
+
448
469
  def initialize(scratch, json)
449
470
  @scratch = scratch
450
471
  @json = json
@@ -453,8 +474,8 @@ module TypeProf
453
474
  def import(explicit = false)
454
475
  classes = @json[:classes].map do |classpath, cdef|
455
476
  type_params = cdef[:type_params]
456
- superclass = cdef[:superclass]
457
- members = cdef[:members]
477
+ superclass, superclass_type_args = cdef[:superclass]
478
+ members = cdef[:members]
458
479
 
459
480
  name = classpath.last
460
481
  superclass = path_to_klass(superclass) if superclass
@@ -462,7 +483,8 @@ module TypeProf
462
483
 
463
484
  klass = @scratch.get_constant(base_klass, name)
464
485
  if klass.is_a?(Type::Any)
465
- klass = @scratch.new_class(base_klass, name, type_params, superclass, nil)
486
+ superclass_type_args = superclass_type_args&.map {|ty| conv_type(ty) }
487
+ klass = @scratch.new_class(base_klass, name, type_params, superclass, superclass_type_args, nil)
466
488
 
467
489
  # There builtin classes are needed to interpret RBS declarations
468
490
  case classpath
@@ -489,12 +511,14 @@ module TypeProf
489
511
  cvars = members[:cvars]
490
512
  rbs_sources = members[:rbs_sources]
491
513
 
492
- included_modules.each do |mod|
493
- @scratch.include_module(klass, path_to_klass(mod), nil)
514
+ included_modules.each do |mod, type_args|
515
+ type_args = type_args&.map {|ty| conv_type(ty) }
516
+ @scratch.include_module(klass, path_to_klass(mod), type_args, false, nil)
494
517
  end
495
518
 
496
- extended_modules.each do |mod|
497
- @scratch.extend_module(klass, path_to_klass(mod), nil)
519
+ extended_modules.each do |mod, type_args|
520
+ type_args = type_args&.map {|ty| conv_type(ty) }
521
+ @scratch.include_module(klass, path_to_klass(mod), type_args, true, nil)
498
522
  end
499
523
 
500
524
  methods.each do |(singleton, method_name), mdef|
@@ -170,6 +170,34 @@ module TypeProf
170
170
 
171
171
  def do_send(recv_orig, mid, aargs, caller_ep, caller_env, scratch, &ctn)
172
172
  recv = scratch.globalize_type(recv_orig, caller_env, caller_ep)
173
+
174
+ tmp_subst = {}
175
+ case
176
+ when recv.is_a?(Type::Cell) && recv_orig.is_a?(Type::LocalCell)
177
+ tyvars = recv.base_type.klass.type_params.map {|name,| Type::Var.new(name) }
178
+ tyvars.zip(recv.elems.elems) do |tyvar, elem|
179
+ if tmp_subst[tyvar]
180
+ tmp_subst[tyvar] = tmp_subst[tyvar].union(elem)
181
+ else
182
+ tmp_subst[tyvar] = elem
183
+ end
184
+ end
185
+ when recv.is_a?(Type::Array) && recv_orig.is_a?(Type::LocalArray)
186
+ tmp_subst = { Type::Var.new(:Elem) => recv.elems.squash }
187
+ when recv.is_a?(Type::Hash) && recv_orig.is_a?(Type::LocalHash)
188
+ tyvar_k = Type::Var.new(:K)
189
+ tyvar_v = Type::Var.new(:V)
190
+ k_ty0, v_ty0 = recv.elems.squash
191
+ # XXX: need to heuristically replace ret type Hash[K, V] with self, instead of conversative type?
192
+ tmp_subst = { tyvar_k => k_ty0, tyvar_v => v_ty0 }
193
+ end
194
+
195
+ klass, singleton = recv_orig.method_dispatch_info
196
+ cur_subst = {}
197
+ scratch.generate_substitution(klass, singleton, mid, self, tmp_subst) do |subst|
198
+ cur_subst = Type.merge_substitution(cur_subst, subst)
199
+ end
200
+
173
201
  found = false
174
202
  aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
175
203
  @sig_rets.each do |msig, ret_ty|
@@ -178,11 +206,10 @@ module TypeProf
178
206
  # XXX: support self type in msig
179
207
  subst = aargs.consistent_with_method_signature?(msig)
180
208
  next unless subst
181
- # need to check self tyvar?
182
- subst[Type::Var.new(:self)] = recv
183
209
  case
184
210
  when recv.is_a?(Type::Cell) && recv_orig.is_a?(Type::LocalCell)
185
211
  tyvars = recv.base_type.klass.type_params.map {|name,| Type::Var.new(name) }
212
+ # XXX: This should be skipped when the called methods belongs to superclass
186
213
  tyvars.each_with_index do |tyvar, idx|
187
214
  ty = subst[tyvar]
188
215
  if ty
@@ -192,13 +219,6 @@ module TypeProf
192
219
  end
193
220
  end
194
221
  end
195
- tyvars.zip(recv.elems.elems) do |tyvar, elem|
196
- if subst[tyvar]
197
- subst[tyvar] = subst[tyvar].union(elem)
198
- else
199
- subst[tyvar] = elem
200
- end
201
- end
202
222
  when recv.is_a?(Type::Array) && recv_orig.is_a?(Type::LocalArray)
203
223
  tyvar_elem = Type::Var.new(:Elem)
204
224
  if subst[tyvar_elem]
@@ -208,16 +228,12 @@ module TypeProf
208
228
  elems.update(nil, ty)
209
229
  end
210
230
  end
211
- subst.merge!({ tyvar_elem => recv.elems.squash })
212
231
  when recv.is_a?(Type::Hash) && recv_orig.is_a?(Type::LocalHash)
213
232
  tyvar_k = Type::Var.new(:K)
214
233
  tyvar_v = Type::Var.new(:V)
215
- k_ty0, v_ty0 = recv.elems.squash
216
234
  if subst[tyvar_k] && subst[tyvar_v]
217
235
  k_ty = subst[tyvar_k]
218
236
  v_ty = subst[tyvar_v]
219
- k_ty0 = k_ty0.union(k_ty)
220
- v_ty0 = v_ty0.union(v_ty)
221
237
  alloc_site = AllocationSite.new(caller_ep)
222
238
  ncaller_env, k_ty = scratch.localize_type(k_ty, ncaller_env, caller_ep, alloc_site.add_id(:k))
223
239
  ncaller_env, v_ty = scratch.localize_type(v_ty, ncaller_env, caller_ep, alloc_site.add_id(:v))
@@ -225,9 +241,10 @@ module TypeProf
225
241
  elems.update(k_ty, v_ty)
226
242
  end
227
243
  end
228
- # XXX: need to heuristically replace ret type Hash[K, V] with self, instead of conversative type?
229
- subst.merge!({ tyvar_k => k_ty0, tyvar_v => v_ty0 })
230
244
  end
245
+ subst = Type.merge_substitution(subst, cur_subst)
246
+ # need to check self tyvar?
247
+ subst[Type::Var.new(:self)] = recv
231
248
  found = true
232
249
  if aargs.blk_ty.is_a?(Type::Proc)
233
250
  #raise NotImplementedError unless aargs.blk_ty.block_body.is_a?(ISeqBlock) # XXX
@@ -170,7 +170,7 @@ module TypeProf
170
170
  "untyped"
171
171
  end
172
172
 
173
- def get_method(mid, scratch)
173
+ def method_dispatch_info
174
174
  nil
175
175
  end
176
176
 
@@ -430,15 +430,17 @@ module TypeProf
430
430
  end
431
431
 
432
432
  class Class < Type # or Module
433
- def initialize(kind, idx, type_params, superclass, name)
433
+ def initialize(kind, idx, type_params, superclass, superclass_type_args, name)
434
434
  @kind = kind # :class | :module
435
435
  @idx = idx
436
436
  @type_params = type_params
437
437
  @superclass = superclass
438
+ raise if @kind == :class && !@superclass
439
+ @superclass_type_args = superclass_type_args
438
440
  @_name = name
439
441
  end
440
442
 
441
- attr_reader :kind, :idx, :type_params, :superclass
443
+ attr_reader :kind, :idx, :type_params, :superclass, :superclass_type_args
442
444
 
443
445
  def inspect
444
446
  if @_name
@@ -449,11 +451,11 @@ module TypeProf
449
451
  end
450
452
 
451
453
  def screen_name(scratch)
452
- "#{ scratch.get_class_name(self) }.class"
454
+ "singleton(#{ scratch.get_class_name(self) })"
453
455
  end
454
456
 
455
- def get_method(mid, scratch)
456
- scratch.get_method(self, true, mid)
457
+ def method_dispatch_info
458
+ [self, true]
457
459
  end
458
460
 
459
461
  def consistent?(other)
@@ -504,8 +506,8 @@ module TypeProf
504
506
  end
505
507
  end
506
508
 
507
- def get_method(mid, scratch)
508
- scratch.get_method(@klass, false, mid)
509
+ def method_dispatch_info
510
+ [@klass, false]
509
511
  end
510
512
 
511
513
  def consistent?(other)
@@ -558,8 +560,8 @@ module TypeProf
558
560
  end
559
561
  end
560
562
 
561
- def get_method(mid, scratch)
562
- @base_type.get_method(mid, scratch)
563
+ def method_dispatch_info
564
+ @base_type.method_dispatch_info
563
565
  end
564
566
 
565
567
  def substitute(subst, depth)
@@ -600,8 +602,8 @@ module TypeProf
600
602
  end
601
603
  end
602
604
 
603
- def get_method(mid, scratch)
604
- @base_type.get_method(mid, scratch)
605
+ def method_dispatch_info
606
+ @base_type.method_dispatch_info
605
607
  end
606
608
 
607
609
  def substitute(_subst, _depth)
@@ -630,8 +632,8 @@ module TypeProf
630
632
  @base_type
631
633
  end
632
634
 
633
- def get_method(mid, scratch)
634
- @base_type.get_method(mid, scratch)
635
+ def method_dispatch_info
636
+ @base_type.method_dispatch_info
635
637
  end
636
638
 
637
639
  def consistent?(_other)
@@ -785,6 +787,10 @@ module TypeProf
785
787
  end
786
788
  str = str.empty? ? "" : "(#{ str.join(", ") })"
787
789
 
790
+ # Dirty Hack: Stop the iteration at most once!
791
+ # I'll remove this hack if RBS removes the limitation of nesting blocks
792
+ return str if caller_locations.any? {|frame| frame.label == "show_block_signature" }
793
+
788
794
  optional = false
789
795
  blks = []
790
796
  @blk_ty.each_child_global do |ty|