typeprof 0.4.1 → 0.5.3

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
@@ -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 < Type
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 consistent?(other, subst)
128
- false if @elems.size != other.elems.size
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
- return false unless ty0.consistent?(ty1, subst)
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 < Type
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 < Type
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)
@@ -318,14 +324,24 @@ module TypeProf
318
324
  end
319
325
  end
320
326
 
321
- def consistent?(other, subst)
327
+ def match?(other)
322
328
  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
329
  rest_ty1 = @lead_tys[n..].inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) }
327
330
  rest_ty2 = other.lead_tys[n..].inject(other.rest_ty) {|ty1, ty2| ty1.union(ty2) }
328
- rest_ty1.consistent?(rest_ty2, subst)
331
+ subst = nil
332
+ (@lead_tys[0, n] + [rest_ty1]).zip(other.lead_tys[0, n] + [rest_ty2]) do |ty0, ty1|
333
+ subst2 = Type.match?(ty0, ty1)
334
+ return nil unless subst2
335
+ subst = Type.merge_substitution(subst, subst2)
336
+ end
337
+ subst
338
+ end
339
+
340
+ def each_free_type_variable(&blk)
341
+ @lead_tys.each do |ty|
342
+ ty.each_free_type_variable(&blk)
343
+ end
344
+ @rest_ty&.each_free_type_variable(&blk)
329
345
  end
330
346
 
331
347
  def substitute(subst, depth)
@@ -476,7 +492,7 @@ module TypeProf
476
492
  end
477
493
 
478
494
  # Do not insert Array type to local environment, stack, etc.
479
- class LocalArray < Type
495
+ class LocalArray < ContainerType
480
496
  def initialize(id, base_type)
481
497
  @id = id
482
498
  raise unless base_type
@@ -506,6 +522,7 @@ module TypeProf
506
522
  # TODO: currently out-of-scope array cannot be accessed
507
523
  elems = Array::Elements.new([], Type.any)
508
524
  end
525
+ visited.delete(self)
509
526
  Array.new(elems, @base_type)
510
527
  end
511
528
  end
@@ -513,14 +530,10 @@ module TypeProf
513
530
  def get_method(mid, scratch)
514
531
  @base_type.get_method(mid, scratch)
515
532
  end
516
-
517
- def consistent?(other, subst)
518
- raise "must not be used"
519
- end
520
533
  end
521
534
 
522
535
 
523
- class Hash < Type
536
+ class Hash < ContainerType
524
537
  def initialize(elems, base_type)
525
538
  @elems = elems
526
539
  raise unless elems
@@ -539,7 +552,7 @@ module TypeProf
539
552
 
540
553
  def localize(env, alloc_site, depth)
541
554
  return env, Type.any if depth <= 0
542
- alloc_site = alloc_site.add_id(:hash)
555
+ alloc_site = alloc_site.add_id(:hash).add_id(@base_type)
543
556
  env, elems = @elems.localize(env, alloc_site, depth - 1)
544
557
  env.deploy_type(LocalHash, alloc_site, elems, @base_type)
545
558
  end
@@ -553,29 +566,13 @@ module TypeProf
553
566
  raise
554
567
  end
555
568
 
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
569
  def substitute(subst, depth)
573
570
  return Type.any if depth <= 0
574
571
  elems = @elems.substitute(subst, depth - 1)
575
572
  Hash.new(elems, @base_type)
576
573
  end
577
574
 
578
- class Elements
575
+ class Elements # Hash
579
576
  include Utils::StructuralEquality
580
577
 
581
578
  def initialize(map_tys)
@@ -635,9 +632,13 @@ module TypeProf
635
632
 
636
633
  def screen_name(scratch)
637
634
  s = @map_tys.map do |k_ty, v_ty|
638
- k = k_ty.screen_name(scratch)
639
635
  v = v_ty.screen_name(scratch)
640
- "#{ k }=>#{ v }"
636
+ if k_ty.is_a?(Type::Symbol)
637
+ "#{ k_ty.sym }: #{ v }"
638
+ else
639
+ k = k_ty.screen_name(scratch)
640
+ "#{ k }=>#{ v }"
641
+ end
641
642
  end.join(", ")
642
643
  "{#{ s }}"
643
644
  end
@@ -657,22 +658,31 @@ module TypeProf
657
658
  end
658
659
  end
659
660
 
660
- def consistent?(other, subst)
661
- subst2 = subst.dup
661
+ def match?(other)
662
+ subst = nil
662
663
  other.map_tys.each do |k1, v1|
663
- found = false
664
+ subst2 = nil
664
665
  @map_tys.each do |k0, v0|
665
- subst3 = subst2.dup
666
- if k0.consistent?(k1, subst3) && v0.consistent?(v1, subst3)
667
- subst2.replace(subst3)
668
- found = true
669
- break
666
+ subst3 = Type.match?(k0, k1)
667
+ if subst3
668
+ subst4 = Type.match?(v0, v1)
669
+ if subst4
670
+ subst2 = Type.merge_substitution(subst2, subst3)
671
+ subst2 = Type.merge_substitution(subst2, subst4)
672
+ end
670
673
  end
671
674
  end
672
- return false unless found
675
+ return nil unless subst2
676
+ subst = Type.merge_substitution(subst, subst2)
677
+ end
678
+ subst
679
+ end
680
+
681
+ def each_free_type_variable(&blk)
682
+ @map_tys.each do |k, v|
683
+ k.each_free_type_variable(&blk)
684
+ v.each_free_type_variable(&blk)
673
685
  end
674
- subst.replace(subst2)
675
- true
676
686
  end
677
687
 
678
688
  def substitute(subst, depth)
@@ -706,7 +716,7 @@ module TypeProf
706
716
  def [](key_ty)
707
717
  val_ty = Type.bot
708
718
  @map_tys.each do |k_ty, v_ty|
709
- if k_ty.consistent?(key_ty, {})
719
+ if Type.match?(k_ty, key_ty)
710
720
  val_ty = val_ty.union(v_ty)
711
721
  end
712
722
  end
@@ -763,7 +773,7 @@ module TypeProf
763
773
  end
764
774
  end
765
775
 
766
- class LocalHash < Type
776
+ class LocalHash < ContainerType
767
777
  def initialize(id, base_type)
768
778
  @id = id
769
779
  @base_type = base_type
@@ -791,6 +801,7 @@ module TypeProf
791
801
  else
792
802
  elems = Hash::Elements.new({Type.any => Type.any})
793
803
  end
804
+ visited.delete(self)
794
805
  Hash.new(elems, @base_type)
795
806
  end
796
807
  end
@@ -798,10 +809,6 @@ module TypeProf
798
809
  def get_method(mid, scratch)
799
810
  @base_type.get_method(mid, scratch)
800
811
  end
801
-
802
- def consistent?(other, subst)
803
- raise "must not be used"
804
- end
805
812
  end
806
813
  end
807
814
  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
 
@@ -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