typeprof 0.5.1 → 0.6.1

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
 
@@ -52,6 +62,7 @@ module TypeProf
52
62
  class RBS2JSON
53
63
  def initialize(all_env, cur_env)
54
64
  @all_env, @cur_env = all_env, cur_env
65
+ @env_walker = RBS::EnvironmentWalker.new(env: @cur_env) # Currently, only each_type_name is used
55
66
  end
56
67
 
57
68
  def dump_json
@@ -90,9 +101,13 @@ module TypeProf
90
101
  json = {}
91
102
 
92
103
  each_class_decl do |name, decls|
93
- super_class_name = get_super_class_name(name, decls)
94
104
  klass = conv_type_name(name)
95
- superclass = super_class_name ? conv_type_name(super_class_name) : nil
105
+ super_class_name, super_class_args = get_super_class(name, decls)
106
+ if super_class_name
107
+ name = conv_type_name(super_class_name)
108
+ type_args = super_class_args.map {|type| conv_type(type) }
109
+ superclass = [name, type_args]
110
+ end
96
111
 
97
112
  type_params = nil
98
113
  included_modules = []
@@ -155,7 +170,8 @@ module TypeProf
155
170
  name = member.name
156
171
  if name.kind == :class
157
172
  mod = conv_type_name(name)
158
- included_modules << mod
173
+ type_args = member.args.map {|type| conv_type(type) }
174
+ included_modules << [mod, type_args]
159
175
  else
160
176
  # including an interface is not supported yet
161
177
  end
@@ -164,7 +180,8 @@ module TypeProf
164
180
  name = member.name
165
181
  if name.kind == :class
166
182
  mod = conv_type_name(name)
167
- extended_modules << mod
183
+ type_args = member.args.map {|type| conv_type(type) }
184
+ extended_modules << [mod, type_args]
168
185
  else
169
186
  # extending a module with an interface is not supported yet
170
187
  end
@@ -221,7 +238,7 @@ module TypeProf
221
238
  @all_env.class_decls[name].decls.each do |decl|
222
239
  decl = decl.decl
223
240
  next if decl.is_a?(RBS::AST::Declarations::Module)
224
- each_ancestor(decl) {|name| queue << [:visit, name] }
241
+ each_reference(decl) {|name| queue << [:visit, name] }
225
242
  end
226
243
  queue << [:visit, name.namespace.to_type_name] if !name.namespace.empty?
227
244
  end
@@ -236,24 +253,35 @@ module TypeProf
236
253
  end
237
254
  end
238
255
 
239
- def each_ancestor(decl, &blk)
256
+ def each_reference(decl, &blk)
240
257
  yield decl.name
241
- super_class = decl.super_class || RBS::BuiltinNames::Object
258
+ if decl.super_class
259
+ name = decl.super_class.name
260
+ args = decl.super_class.args
261
+ if args
262
+ args.each do |ty|
263
+ @env_walker.each_type_name(ty, &blk)
264
+ end
265
+ end
266
+ else
267
+ name = RBS::BuiltinNames::Object.name
268
+ end
242
269
  return if decl.name == RBS::BuiltinNames::BasicObject.name
243
- return if decl.name == super_class.name
244
- @all_env.class_decls[super_class.name].decls.each do |decl|
245
- each_ancestor(decl.decl, &blk)
270
+ return if decl.name == name
271
+ @all_env.class_decls[name].decls.each do |decl|
272
+ each_reference(decl.decl, &blk)
246
273
  end
247
274
  end
248
275
 
249
- def get_super_class_name(name, decls)
276
+ def get_super_class(name, decls)
250
277
  return nil if name == RBS::BuiltinNames::BasicObject.name
251
278
 
252
279
  decls.each do |decl|
253
280
  decl = decl.decl
254
281
  case decl
255
282
  when RBS::AST::Declarations::Class
256
- return decl.super_class.name if decl.super_class
283
+ super_class = decl.super_class
284
+ return super_class.name, super_class.args if super_class
257
285
  when RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface
258
286
  return nil
259
287
  else
@@ -261,7 +289,7 @@ module TypeProf
261
289
  end
262
290
  end
263
291
 
264
- return RBS::BuiltinNames::Object.name
292
+ return RBS::BuiltinNames::Object.name, []
265
293
  end
266
294
 
267
295
  def conv_method_def(rbs_method_types)
@@ -445,6 +473,10 @@ module TypeProf
445
473
  Import.new(scratch, scratch.rbs_reader.load_path(rbs_path)).import(true)
446
474
  end
447
475
 
476
+ def self.import_rbs_code(scratch, rbs_name, rbs_code)
477
+ Import.new(scratch, scratch.rbs_reader.load_rbs_string(rbs_name, rbs_code)).import(true)
478
+ end
479
+
448
480
  def initialize(scratch, json)
449
481
  @scratch = scratch
450
482
  @json = json
@@ -453,8 +485,8 @@ module TypeProf
453
485
  def import(explicit = false)
454
486
  classes = @json[:classes].map do |classpath, cdef|
455
487
  type_params = cdef[:type_params]
456
- superclass = cdef[:superclass]
457
- members = cdef[:members]
488
+ superclass, superclass_type_args = cdef[:superclass]
489
+ members = cdef[:members]
458
490
 
459
491
  name = classpath.last
460
492
  superclass = path_to_klass(superclass) if superclass
@@ -462,7 +494,8 @@ module TypeProf
462
494
 
463
495
  klass = @scratch.get_constant(base_klass, name)
464
496
  if klass.is_a?(Type::Any)
465
- klass = @scratch.new_class(base_klass, name, type_params, superclass, nil)
497
+ superclass_type_args = superclass_type_args&.map {|ty| conv_type(ty) }
498
+ klass = @scratch.new_class(base_klass, name, type_params, superclass, superclass_type_args, nil)
466
499
 
467
500
  # There builtin classes are needed to interpret RBS declarations
468
501
  case classpath
@@ -489,12 +522,14 @@ module TypeProf
489
522
  cvars = members[:cvars]
490
523
  rbs_sources = members[:rbs_sources]
491
524
 
492
- included_modules.each do |mod|
493
- @scratch.include_module(klass, path_to_klass(mod), nil)
525
+ included_modules.each do |mod, type_args|
526
+ type_args = type_args&.map {|ty| conv_type(ty) }
527
+ @scratch.include_module(klass, path_to_klass(mod), type_args, false, nil)
494
528
  end
495
529
 
496
- extended_modules.each do |mod|
497
- @scratch.extend_module(klass, path_to_klass(mod), nil)
530
+ extended_modules.each do |mod, type_args|
531
+ type_args = type_args&.map {|ty| conv_type(ty) }
532
+ @scratch.include_module(klass, path_to_klass(mod), type_args, true, nil)
498
533
  end
499
534
 
500
535
  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