typeprof 0.30.1 → 0.31.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -4
  3. data/lib/typeprof/cli/cli.rb +27 -7
  4. data/lib/typeprof/code_range.rb +9 -7
  5. data/lib/typeprof/core/ast/base.rb +27 -10
  6. data/lib/typeprof/core/ast/call.rb +85 -24
  7. data/lib/typeprof/core/ast/const.rb +7 -12
  8. data/lib/typeprof/core/ast/control.rb +345 -71
  9. data/lib/typeprof/core/ast/meta.rb +5 -5
  10. data/lib/typeprof/core/ast/method.rb +15 -5
  11. data/lib/typeprof/core/ast/misc.rb +21 -2
  12. data/lib/typeprof/core/ast/module.rb +10 -7
  13. data/lib/typeprof/core/ast/pattern.rb +9 -1
  14. data/lib/typeprof/core/ast/sig_decl.rb +163 -42
  15. data/lib/typeprof/core/ast/sig_type.rb +394 -24
  16. data/lib/typeprof/core/ast/value.rb +10 -2
  17. data/lib/typeprof/core/ast/variable.rb +32 -2
  18. data/lib/typeprof/core/ast.rb +15 -4
  19. data/lib/typeprof/core/builtin.rb +15 -9
  20. data/lib/typeprof/core/env/method.rb +21 -16
  21. data/lib/typeprof/core/env/method_entity.rb +11 -2
  22. data/lib/typeprof/core/env/module_entity.rb +57 -0
  23. data/lib/typeprof/core/env/narrowing.rb +131 -0
  24. data/lib/typeprof/core/env/static_read.rb +9 -8
  25. data/lib/typeprof/core/env.rb +37 -12
  26. data/lib/typeprof/core/graph/box.rb +207 -97
  27. data/lib/typeprof/core/graph/change_set.rb +44 -37
  28. data/lib/typeprof/core/graph/vertex.rb +4 -21
  29. data/lib/typeprof/core/service.rb +30 -1
  30. data/lib/typeprof/core/type.rb +48 -123
  31. data/lib/typeprof/core.rb +1 -0
  32. data/lib/typeprof/diagnostic.rb +5 -6
  33. data/lib/typeprof/lsp/messages.rb +21 -15
  34. data/lib/typeprof/lsp/server.rb +132 -39
  35. data/lib/typeprof/lsp/text.rb +1 -0
  36. data/lib/typeprof/version.rb +1 -1
  37. data/typeprof.conf.jsonc +22 -0
  38. data/typeprof.gemspec +1 -0
  39. metadata +19 -6
@@ -39,18 +39,12 @@ module TypeProf::Core
39
39
  @changes.reinstall(genv)
40
40
  end
41
41
 
42
- def diagnostics(genv, &blk)
43
- raise self.to_s if !@changes
44
- @changes.diagnostics.each(&blk)
45
- @changes.boxes.each_value do |box|
46
- box.diagnostics(genv, &blk)
47
- end
42
+ def run0(genv, changes)
43
+ raise NotImplementedError
48
44
  end
49
45
 
50
- #@@new_id = 0
51
-
52
46
  def to_s
53
- "#{ self.class.to_s.split("::").last[0] }#{ @id ||= $new_id += 1 }"
47
+ "#{ self.class.to_s.split("::").last }#{ @id ||= $new_id += 1 }"
54
48
  end
55
49
 
56
50
  alias inspect to_s
@@ -87,7 +81,20 @@ module TypeProf::Core
87
81
  attr_reader :node, :rbs_type, :ret
88
82
 
89
83
  def run0(genv, changes)
90
- vtx = @rbs_type.covariant_vertex(genv, changes, {})
84
+ # Create substitution map for type parameters if we're in a SigInstanceVariableNode within a generic class
85
+ subst = {}
86
+ if @node.is_a?(AST::SigInstanceVariableNode) && @node.cpath
87
+ mod = genv.resolve_cpath(@node.cpath)
88
+ if mod.type_params && !mod.type_params.empty?
89
+ # Create a substitution map where each type parameter maps to a type variable vertex
90
+ subst = mod.type_params.to_h do |param|
91
+ type_var_vtx = Vertex.new(@node)
92
+ [param, type_var_vtx]
93
+ end
94
+ end
95
+ end
96
+
97
+ vtx = @rbs_type.covariant_vertex(genv, changes, subst)
91
98
  changes.add_edge(genv, vtx, @ret)
92
99
  end
93
100
  end
@@ -142,13 +149,11 @@ module TypeProf::Core
142
149
  end
143
150
 
144
151
  method_type.req_positionals.each_with_index do |ty, i|
145
- f_arg = ty.contravariant_vertex(genv, changes, param_map)
146
- return false unless a_args.positionals[i].check_match(genv, changes, f_arg)
152
+ return false unless ty.typecheck(genv, changes, a_args.positionals[i], param_map)
147
153
  end
148
154
  method_type.post_positionals.each_with_index do |ty, i|
149
- f_arg = ty.contravariant_vertex(genv, changes, param_map)
150
155
  i -= method_type.post_positionals.size
151
- return false unless a_args.positionals[i].check_match(genv, changes, f_arg)
156
+ return false unless ty.typecheck(genv, changes, a_args.positionals[i], param_map)
152
157
  end
153
158
 
154
159
  start_rest = method_type.req_positionals.size
@@ -157,61 +162,100 @@ module TypeProf::Core
157
162
  i = 0
158
163
  while i < method_type.opt_positionals.size && start_rest < end_rest
159
164
  break if a_args.splat_flags[start_rest]
160
- f_arg = method_type.opt_positionals[i].contravariant_vertex(genv, changes, param_map)
161
- return false unless a_args.positionals[start_rest].check_match(genv, changes, f_arg)
165
+ return false unless method_type.opt_positionals[i].typecheck(genv, changes, a_args.positionals[start_rest], param_map)
162
166
  i += 1
163
167
  start_rest += 1
164
168
  end
165
169
 
166
170
  if start_rest < end_rest
167
- vtxs = a_args.get_rest_args(genv, start_rest, end_rest)
171
+ vtxs = a_args.get_rest_args(genv, changes, start_rest, end_rest)
168
172
  while i < method_type.opt_positionals.size
169
- f_arg = method_type.opt_positionals[i].contravariant_vertex(genv, changes, param_map)
170
- return false if vtxs.any? {|vtx| !vtx.check_match(genv, changes, f_arg) }
173
+ ty = method_type.opt_positionals[i]
174
+ return false if vtxs.any? {|vtx| !ty.typecheck(genv, changes, vtx, param_map) }
171
175
  i += 1
172
176
  end
173
177
  if method_type.rest_positionals
174
- f_arg = method_type.rest_positionals.contravariant_vertex(genv, changes, param_map)
175
- return false if vtxs.any? {|vtx| !vtx.check_match(genv, changes, f_arg) }
178
+ return false if vtxs.any? {|vtx| !method_type.rest_positionals.typecheck(genv, changes, vtx, param_map) }
176
179
  end
177
180
  end
178
181
 
179
182
  return true
180
183
  end
181
184
 
182
- def resolve_overloads(changes, genv, node, param_map, a_args, ret)
183
- match_any_overload = false
184
- @method_types.each do |method_type|
185
- param_map0 = param_map.dup
186
- if method_type.type_params
187
- method_type.type_params.zip(yield(method_type)) do |var, vtx|
188
- param_map0[var] = vtx
189
- end
185
+ def resolve_overload(changes, genv, method_type, node, param_map, a_args, ret, force)
186
+ param_map0 = param_map.dup
187
+ if method_type.type_params
188
+ method_type.type_params.zip(yield(method_type)) do |var, vtx|
189
+ param_map0[var] = vtx
190
190
  end
191
+ end
191
192
 
192
- next unless match_arguments?(genv, changes, param_map0, a_args, method_type)
193
+ unless match_arguments?(genv, changes, param_map0, a_args, method_type)
194
+ if force
195
+ meth = node.mid_code_range ? :mid_code_range : :code_range
196
+ changes.add_diagnostic(meth, "wrong type of arguments") # XXX: more friendly and fine-grained error message
197
+ end
198
+ return false
199
+ end
193
200
 
194
- rbs_blk = method_type.block
195
- next if method_type.block_required && !a_args.block
196
- next if !rbs_blk && a_args.block
197
- if rbs_blk && a_args.block
198
- # rbs_blk_func.optional_keywords, ...
199
- a_args.block.each_type do |ty|
200
- case ty
201
- when Type::Proc
202
- blk_f_ret = rbs_blk.return_type.contravariant_vertex(genv, changes, param_map0)
203
- blk_a_args = rbs_blk.req_positionals.map do |blk_a_arg|
204
- blk_a_arg.covariant_vertex(genv, changes, param_map0)
201
+ rbs_blk = method_type.block
202
+ if method_type.block_required && !a_args.block
203
+ if force
204
+ meth = node.mid_code_range ? :mid_code_range : :code_range
205
+ changes.add_diagnostic(meth, "block is expected") # XXX: more friendly error message
206
+ end
207
+ return false
208
+ end
209
+ if !rbs_blk && a_args.block
210
+ if force
211
+ meth = node.mid_code_range ? :mid_code_range : :code_range
212
+ changes.add_diagnostic(meth, "block is not expected") # XXX: more friendly error message
213
+ end
214
+ return false
215
+ end
216
+ if rbs_blk && a_args.block
217
+ # rbs_blk_func.optional_keywords, ...
218
+ blk_a_args = rbs_blk.req_positionals.map do |blk_a_arg|
219
+ blk_a_arg.covariant_vertex(genv, changes, param_map0)
220
+ end
221
+ a_args.block.each_type do |ty|
222
+ case ty
223
+ when Type::Proc
224
+ ty.block.accept_args(genv, changes, blk_a_args)
225
+
226
+ if ty.block.is_a?(Block)
227
+ ty.block.next_boxes.each do |next_box|
228
+ unless rbs_blk.return_type.typecheck(genv, changes, next_box.a_ret, param_map0)
229
+ next_box.wrong_return_type(rbs_blk.return_type.show, changes)
230
+ end
205
231
  end
206
-
207
- ty.block.accept_args(genv, changes, blk_a_args, blk_f_ret, true)
208
232
  end
209
233
  end
210
234
  end
211
- ret_vtx = method_type.return_type.covariant_vertex(genv, changes, param_map0)
235
+ end
236
+
237
+ force = true
238
+ return true
212
239
 
240
+ ensure
241
+ if force
242
+ ret_vtx = method_type.return_type.covariant_vertex(genv, changes, param_map0)
213
243
  changes.add_edge(genv, ret_vtx, ret)
214
- match_any_overload = true
244
+ end
245
+ end
246
+
247
+ def resolve_overloads(changes, genv, node, param_map, a_args, ret, &blk)
248
+ if @method_types.size == 1
249
+ method_type = @method_types.first
250
+ resolve_overload(changes, genv, method_type, node, param_map, a_args, ret, true, &blk)
251
+ return
252
+ end
253
+
254
+ match_any_overload = false
255
+ @method_types.each do |method_type|
256
+ if resolve_overload(changes, genv, method_type, node, param_map, a_args, ret, false, &blk)
257
+ match_any_overload = true
258
+ end
215
259
  end
216
260
  unless match_any_overload
217
261
  meth = node.mid_code_range ? :mid_code_range : :code_range
@@ -252,53 +296,66 @@ module TypeProf::Core
252
296
  end
253
297
 
254
298
  class EscapeBox < Box
255
- def initialize(node, genv, a_ret, f_ret)
299
+ def initialize(node, genv, a_ret)
256
300
  super(node)
257
301
  @a_ret = a_ret.new_vertex(genv, node)
258
- @f_ret = f_ret
259
- @f_ret.add_edge(genv, self)
260
302
  end
261
303
 
262
- attr_reader :a_ret, :f_ret
304
+ attr_reader :a_ret
263
305
 
264
306
  def ret = @a_ret
265
307
 
266
308
  def run0(genv, changes)
267
- unless @a_ret.check_match(genv, changes, @f_ret)
268
- msg = "expected: #{ @f_ret.show }; actual: #{ @a_ret.show }"
269
- case @node
270
- when AST::ReturnNode
271
- changes.add_diagnostic(:code_range, msg)
272
- when AST::DefNode
273
- changes.add_diagnostic(:last_stmt_code_range, msg)
274
- when AST::NextNode
275
- changes.add_diagnostic(:code_range, msg)
276
- when AST::CallNode
277
- changes.add_diagnostic(:block_last_stmt_code_range, msg)
278
- when AST::AttrReaderMetaNode, AST::AttrAccessorMetaNode
279
- changes.add_diagnostic(:code_range, msg)
280
- else
281
- pp @node.class
282
- end
309
+ return
310
+ end
311
+
312
+ def wrong_return_type(f_ret_show, changes)
313
+ actual_ty = @a_ret.show
314
+ return if actual_ty == "untyped" # XXX: too ad-hoc?
315
+ msg = "expected: #{ f_ret_show }; actual: #{ actual_ty }"
316
+ case @node
317
+ when AST::ReturnNode
318
+ changes.add_diagnostic(:code_range, msg, @node)
319
+ when AST::DefNode
320
+ changes.add_diagnostic(:last_stmt_code_range, msg, @node)
321
+ when AST::NextNode
322
+ changes.add_diagnostic(:code_range, msg, @node)
323
+ when AST::CallNode
324
+ changes.add_diagnostic(:block_last_stmt_code_range, msg, @node)
325
+ when AST::AttrReaderMetaNode, AST::AttrAccessorMetaNode
326
+ changes.add_diagnostic(:code_range, msg, @node)
327
+ else
328
+ pp @node.class
283
329
  end
284
330
  end
285
331
  end
286
332
 
287
333
  class SplatBox < Box
288
- def initialize(node, genv, ary)
334
+ def initialize(node, genv, ary, idx)
289
335
  super(node)
290
336
  @ary = ary
337
+ @idx = idx
291
338
  @ary.add_edge(genv, self)
292
339
  @ret = Vertex.new(node)
293
340
  end
294
341
 
295
- attr_reader :ary, :ret
342
+ attr_reader :ary, :idx, :ret
296
343
 
297
344
  def run0(genv, changes)
298
345
  @ary.each_type do |ty|
299
- ty = ty.base_type(genv)
300
- if ty.mod == genv.mod_ary
301
- changes.add_edge(genv, ty.args[0], @ret)
346
+ case ty
347
+ when Type::Instance
348
+ if ty.mod == genv.mod_ary
349
+ changes.add_edge(genv, ty.args[0], @ret)
350
+ else
351
+ "???"
352
+ end
353
+ when Type::Array
354
+ if @idx && @idx < ty.elems.size
355
+ changes.add_edge(genv, ty.elems[@idx], @ret)
356
+ else
357
+ changes.add_edge(genv, ty.get_elem(genv, @idx), @ret)
358
+ end
302
359
  else
303
360
  "???"
304
361
  end
@@ -323,8 +380,8 @@ module TypeProf::Core
323
380
  @hsh.each_type do |ty|
324
381
  ty = ty.base_type(genv)
325
382
  if ty.mod == genv.mod_hash
326
- changes.add_edge(genv, ty.args[0], @unified_key)
327
- changes.add_edge(genv, ty.args[1], @unified_val)
383
+ changes.add_edge(genv, ty.args[0].new_vertex(genv, :__hash_splat), @unified_key)
384
+ changes.add_edge(genv, ty.args[1].new_vertex(genv, :__hash_splat), @unified_val)
328
385
  else
329
386
  "???"
330
387
  end
@@ -355,11 +412,8 @@ module TypeProf::Core
355
412
  end
356
413
  me = genv.resolve_method(@cpath, @singleton, @mid)
357
414
  me.add_def(self)
358
- if me.decls.empty?
359
- me.add_run_all_method_call_boxes(genv)
360
- else
361
- genv.add_run(self)
362
- end
415
+ me.add_run_all_method_call_boxes(genv) if me.decls.empty?
416
+ genv.add_run(self)
363
417
  end
364
418
 
365
419
  attr_accessor :node
@@ -369,11 +423,8 @@ module TypeProf::Core
369
423
  def destroy(genv)
370
424
  me = genv.resolve_method(@cpath, @singleton, @mid)
371
425
  me.remove_def(self)
372
- if me.decls.empty?
373
- me.add_run_all_method_call_boxes(genv)
374
- else
375
- genv.add_run(self)
376
- end
426
+ me.add_run_all_method_call_boxes(genv) if me.decls.empty?
427
+ genv.add_run(self)
377
428
  super(genv)
378
429
  end
379
430
 
@@ -430,8 +481,11 @@ module TypeProf::Core
430
481
  if pass_arguments(changes, genv, a_args)
431
482
  # TODO: block
432
483
  f_ret = method_type.return_type.contravariant_vertex(genv, changes, param_map0)
484
+ changes.add_edge(genv, f_ret, @ret)
433
485
  @ret_boxes.each do |ret_box|
434
- changes.add_edge(genv, f_ret, ret_box.f_ret)
486
+ unless method_type.return_type.typecheck(genv, changes, ret_box.a_ret, param_map0)
487
+ ret_box.wrong_return_type(method_type.return_type.show, changes)
488
+ end
435
489
  end
436
490
  end
437
491
  end
@@ -451,7 +505,7 @@ module TypeProf::Core
451
505
 
452
506
  start_rest = [a_args.splat_flags.index(true), @f_args.req_positionals.size + @f_args.opt_positionals.size].min
453
507
  end_rest = [a_args.splat_flags.rindex(true) + 1, a_args.positionals.size - @f_args.post_positionals.size].max
454
- rest_vtxs = a_args.get_rest_args(genv, start_rest, end_rest)
508
+ rest_vtxs = a_args.get_rest_args(genv, changes, start_rest, end_rest)
455
509
 
456
510
  @f_args.req_positionals.each_with_index do |f_vtx, i|
457
511
  if i < start_rest
@@ -590,7 +644,7 @@ module TypeProf::Core
590
644
  end
591
645
  end
592
646
  if @f_args.rest_keywords
593
- args << "**#{ Type.strip_parens(@f_args.rest_keywords.show) }"
647
+ args << "**#{ Type.extract_hash_value_type(Type.strip_parens(@f_args.rest_keywords.show)) }"
594
648
  end
595
649
 
596
650
  if output_parameter_names && @node.is_a?(AST::DefNode)
@@ -610,7 +664,7 @@ module TypeProf::Core
610
664
  args = args.join(", ")
611
665
  s = args.empty? ? [] : ["(#{ args })"]
612
666
  s << "#{ block_show.sort.join(" | ") }" unless block_show.empty?
613
- s << "-> #{ @ret.show }"
667
+ s << "-> #{ @mid == :initialize ? "void" : @ret.show }"
614
668
  s.join(" ")
615
669
  end
616
670
  end
@@ -626,11 +680,8 @@ module TypeProf::Core
626
680
 
627
681
  me = genv.resolve_method(@cpath, @singleton, @new_mid)
628
682
  me.add_alias(self, @old_mid)
629
- if me.decls.empty?
630
- me.add_run_all_method_call_boxes(genv)
631
- else
632
- genv.add_run(self)
633
- end
683
+ me.add_run_all_method_call_boxes(genv) if me.decls.empty?
684
+ genv.add_run(self)
634
685
  end
635
686
 
636
687
  attr_accessor :node
@@ -640,11 +691,8 @@ module TypeProf::Core
640
691
  def destroy(genv)
641
692
  me = genv.resolve_method(@cpath, @singleton, @new_mid)
642
693
  me.remove_alias(self)
643
- if me.decls.empty?
644
- me.add_run_all_method_call_boxes(genv)
645
- else
646
- genv.add_run(self)
647
- end
694
+ me.add_run_all_method_call_boxes(genv) if me.decls.empty?
695
+ genv.add_run(self)
648
696
  super(genv)
649
697
  end
650
698
 
@@ -661,7 +709,6 @@ module TypeProf::Core
661
709
  @recv.add_edge(genv, self)
662
710
  @mid = mid
663
711
  @a_args = a_args.new_vertexes(genv, node)
664
- @a_args.positionals.each {|arg| arg.add_edge(genv, self) }
665
712
  @a_args.keywords.add_edge(genv, self) if @a_args.keywords
666
713
  @a_args.block.add_edge(genv, self) if @a_args.block
667
714
  @ret = Vertex.new(node)
@@ -749,6 +796,16 @@ module TypeProf::Core
749
796
  alias_limit = 0
750
797
  while ty
751
798
  unless skip
799
+ # First check prepended modules
800
+ if !ty.is_a?(Type::Singleton)
801
+ if resolve_prepended_modules(genv, changes, base_ty_env, ty, mid) do |me, ty, mid|
802
+ yield me, ty, mid, orig_ty
803
+ end
804
+ break
805
+ end
806
+ end
807
+
808
+ # Then check the class/module itself
752
809
  me = ty.mod.get_method(ty.is_a?(Type::Singleton), mid)
753
810
  changes.add_depended_method_entity(me) if changes
754
811
  if !me.aliases.empty?
@@ -767,6 +824,7 @@ module TypeProf::Core
767
824
  if ty.is_a?(Type::Singleton)
768
825
  # TODO: extended modules
769
826
  else
827
+ # Finally check included modules
770
828
  break if resolve_included_modules(genv, changes, base_ty_env, ty, mid) do |me, ty, mid|
771
829
  yield me, ty, mid, orig_ty
772
830
  end
@@ -779,6 +837,38 @@ module TypeProf::Core
779
837
  end
780
838
  end
781
839
 
840
+ def resolve_prepended_modules(genv, changes, base_ty_env, ty, mid, &blk)
841
+ found = false
842
+
843
+ alias_limit = 0
844
+ # Process prepended modules in reverse order (last prepended = first in ancestor chain)
845
+ ty.mod.prepended_modules.reverse_each do |prep_decl, prep_mod|
846
+ if prep_decl.is_a?(AST::SigPrependNode) && prep_mod.type_params
847
+ prep_ty = genv.get_instance_type(prep_mod, prep_decl.args, changes, base_ty_env, ty)
848
+ else
849
+ type_params = prep_mod.type_params.map {|ty_param| Source.new() } # TODO: better support
850
+ prep_ty = Type::Instance.new(genv, prep_mod, type_params)
851
+ end
852
+
853
+ me = prep_ty.mod.get_method(false, mid)
854
+ changes.add_depended_method_entity(me) if changes
855
+ if !me.aliases.empty?
856
+ mid = me.aliases.values.first
857
+ alias_limit += 1
858
+ redo if alias_limit < 5
859
+ end
860
+ if me.exist?
861
+ found = true
862
+ yield me, prep_ty, mid
863
+ else
864
+ found = resolve_prepended_modules(genv, changes, base_ty_env, prep_ty, mid, &blk)
865
+ end
866
+ break if found
867
+ end
868
+
869
+ found
870
+ end
871
+
782
872
  def resolve_included_modules(genv, changes, base_ty_env, ty, mid, &blk)
783
873
  found = false
784
874
 
@@ -995,4 +1085,24 @@ module TypeProf::Core
995
1085
  end
996
1086
  end
997
1087
  end
1088
+
1089
+ class InstanceTypeBox < Box
1090
+ def initialize(node, genv, singleton_ty_vtx)
1091
+ super(node)
1092
+ @singleton_ty_vtx = singleton_ty_vtx
1093
+ @ret = Vertex.new(node)
1094
+ genv.add_run(self)
1095
+ end
1096
+
1097
+ attr_reader :ret
1098
+
1099
+ def run0(genv, changes)
1100
+ instance_tys = []
1101
+ @singleton_ty_vtx.each_type do |ty|
1102
+ instance_tys << ty.get_instance_type(genv)
1103
+ end
1104
+ source_vtx = Source.new(*instance_tys)
1105
+ changes.add_edge(genv, source_vtx, @ret)
1106
+ end
1107
+ end
998
1108
  end
@@ -3,6 +3,7 @@ module TypeProf::Core
3
3
  def initialize(node, target)
4
4
  @node = node
5
5
  @target = target
6
+ @new_vertexes = {}
6
7
  @covariant_types = {}
7
8
  @contravariant_types = {}
8
9
  @edges = []
@@ -21,30 +22,35 @@ module TypeProf::Core
21
22
  @new_depended_superclasses = []
22
23
  end
23
24
 
24
- attr_reader :node, :covariant_types, :edges, :boxes, :diagnostics
25
+ attr_reader :node, :target, :covariant_types, :contravariant_types, :edges, :boxes, :diagnostics
25
26
 
26
27
  def reuse(new_node)
27
28
  @node = new_node
28
29
  @boxes.each_value do |box|
29
30
  box.reuse(new_node)
30
31
  end
31
- @diagnostics.each do |diag|
32
- diag.reuse(new_node)
33
- end
34
32
  end
35
33
 
36
34
  def copy_from(other)
37
35
  @covariant_types = other.covariant_types.dup
36
+ @contravariant_types = other.contravariant_types.dup
38
37
  @edges = other.edges.dup
39
38
  @boxes = other.boxes.dup
40
39
  @diagnostics = other.diagnostics.dup
41
40
 
42
41
  other.covariant_types.clear
42
+ other.contravariant_types.clear
43
43
  other.edges.clear
44
44
  other.boxes.clear
45
45
  other.diagnostics.clear
46
46
  end
47
47
 
48
+ def new_vertex(genv, origin, base_vtx)
49
+ new_vtx = @new_vertexes[base_vtx] ||= Vertex.new(origin)
50
+ add_edge(genv, base_vtx, new_vtx)
51
+ new_vtx
52
+ end
53
+
48
54
  def new_covariant_vertex(genv, sig_type_node)
49
55
  # This is used to avoid duplicated vertex generation for the same sig node
50
56
  @covariant_types[sig_type_node] ||= Vertex.new(sig_type_node)
@@ -56,8 +62,6 @@ module TypeProf::Core
56
62
  end
57
63
 
58
64
  def add_edge(genv, src, dst)
59
- raise src.class.to_s unless src.is_a?(BasicVertex)
60
- src.add_edge(genv, dst) if !@edges.include?([src, dst]) && !@new_edges.include?([src, dst])
61
65
  @new_edges << [src, dst]
62
66
  end
63
67
 
@@ -65,84 +69,76 @@ module TypeProf::Core
65
69
 
66
70
  def add_method_call_box(genv, recv, mid, a_args, subclasses)
67
71
  key = [:mcall, recv, mid, a_args, subclasses]
68
- return if @new_boxes[key]
69
- @new_boxes[key] = MethodCallBox.new(@node, genv, recv, mid, a_args, subclasses)
72
+ @new_boxes[key] ||= MethodCallBox.new(@node, genv, recv, mid, a_args, subclasses)
70
73
  end
71
74
 
72
- def add_escape_box(genv, a_ret, f_ret)
75
+ def add_escape_box(genv, a_ret)
73
76
  key = [:return, a_ret]
74
- return if @new_boxes[key]
75
- @new_boxes[key] = EscapeBox.new(@node, genv, a_ret, f_ret)
77
+ @new_boxes[key] ||= EscapeBox.new(@node, genv, a_ret)
76
78
  end
77
79
 
78
- def add_splat_box(genv, arg)
79
- key = [:splat, arg]
80
- return if @new_boxes[key]
81
- @new_boxes[key] = SplatBox.new(@node, genv, arg)
80
+ def add_splat_box(genv, arg, idx = nil)
81
+ key = [:splat, arg, idx]
82
+ @new_boxes[key] ||= SplatBox.new(@node, genv, arg, idx)
82
83
  end
83
84
 
84
85
  def add_hash_splat_box(genv, arg, unified_key, unified_val)
85
86
  key = [:hash_splat, arg, unified_key, unified_val]
86
- return if @new_boxes[key]
87
- @new_boxes[key] = HashSplatBox.new(@node, genv, arg, unified_key, unified_val)
87
+ @new_boxes[key] ||= HashSplatBox.new(@node, genv, arg, unified_key, unified_val)
88
88
  end
89
89
 
90
90
  def add_masgn_box(genv, value, lefts, rest_elem, rights)
91
91
  key = [:masgn, value, lefts, rest_elem, rights]
92
- return if @new_boxes[key]
93
- @new_boxes[key] = MAsgnBox.new(@node, genv, value, lefts, rest_elem, rights)
92
+ @new_boxes[key] ||= MAsgnBox.new(@node, genv, value, lefts, rest_elem, rights)
94
93
  end
95
94
 
96
95
  def add_method_def_box(genv, cpath, singleton, mid, f_args, ret_boxes)
97
96
  key = [:mdef, cpath, singleton, mid, f_args, ret_boxes]
98
- return if @new_boxes[key]
99
- @new_boxes[key] = MethodDefBox.new(@node, genv, cpath, singleton, mid, f_args, ret_boxes)
97
+ @new_boxes[key] ||= MethodDefBox.new(@node, genv, cpath, singleton, mid, f_args, ret_boxes)
100
98
  end
101
99
 
102
100
  def add_method_decl_box(genv, cpath, singleton, mid, method_types, overloading)
103
101
  key = [:mdecl, cpath, singleton, mid, method_types, overloading]
104
- return if @new_boxes[key]
105
- @new_boxes[key] = MethodDeclBox.new(@node, genv, cpath, singleton, mid, method_types, overloading)
102
+ @new_boxes[key] ||= MethodDeclBox.new(@node, genv, cpath, singleton, mid, method_types, overloading)
106
103
  end
107
104
 
108
105
  def add_method_alias_box(genv, cpath, singleton, new_mid, old_mid)
109
106
  key = [:mdecl, cpath, singleton, new_mid, old_mid]
110
- return if @new_boxes[key]
111
- @new_boxes[key] = MethodAliasBox.new(@node, genv, cpath, singleton, new_mid, old_mid)
107
+ @new_boxes[key] ||= MethodAliasBox.new(@node, genv, cpath, singleton, new_mid, old_mid)
112
108
  end
113
109
 
114
110
  def add_const_read_box(genv, static_ret)
115
111
  key = [:cread, static_ret]
116
- return if @new_boxes[key]
117
- @new_boxes[key] = ConstReadBox.new(@node, genv, static_ret)
112
+ @new_boxes[key] ||= ConstReadBox.new(@node, genv, static_ret)
118
113
  end
119
114
 
120
115
  def add_gvar_read_box(genv, var)
121
116
  key = [:gvar_read, var]
122
- return if @new_boxes[key]
123
- @new_boxes[key] = GVarReadBox.new(@node, genv, var)
117
+ @new_boxes[key] ||= GVarReadBox.new(@node, genv, var)
124
118
  end
125
119
 
126
120
  def add_ivar_read_box(genv, cpath, singleton, name)
127
121
  key = [:ivar_read, cpath, singleton, name]
128
- return if @new_boxes[key]
129
- @new_boxes[key] = IVarReadBox.new(@node, genv, cpath, singleton, name)
122
+ @new_boxes[key] ||= IVarReadBox.new(@node, genv, cpath, singleton, name)
130
123
  end
131
124
 
132
125
  def add_cvar_read_box(genv, cpath, name)
133
126
  key = [:cvar_read, cpath, name]
134
- return if @new_boxes[key]
135
- @new_boxes[key] = CVarReadBox.new(@node, genv, cpath, name)
127
+ @new_boxes[key] ||= CVarReadBox.new(@node, genv, cpath, name)
136
128
  end
137
129
 
138
130
  def add_type_read_box(genv, type)
139
131
  key = [:type_read, type]
140
- return if @new_boxes[key]
141
- @new_boxes[key] = TypeReadBox.new(@node, genv, type)
132
+ @new_boxes[key] ||= TypeReadBox.new(@node, genv, type)
133
+ end
134
+
135
+ def add_instance_type_box(genv, singleton_ty_vtx)
136
+ key = [:instance_type, singleton_ty_vtx]
137
+ @new_boxes[key] ||= InstanceTypeBox.new(@node, genv, singleton_ty_vtx)
142
138
  end
143
139
 
144
- def add_diagnostic(meth, msg)
145
- @new_diagnostics << TypeProf::Diagnostic.new(@node, meth, msg)
140
+ def add_diagnostic(meth, msg, node = @node)
141
+ @new_diagnostics << TypeProf::Diagnostic.new(node, meth, msg)
146
142
  end
147
143
 
148
144
  def add_depended_value_entity(ve)
@@ -163,6 +159,9 @@ module TypeProf::Core
163
159
 
164
160
  def reinstall(genv)
165
161
  @new_edges.uniq!
162
+ @new_edges.each do |src, dst|
163
+ src.add_edge(genv, dst) unless @edges.include?([src, dst])
164
+ end
166
165
  @edges.each do |src, dst|
167
166
  src.remove_edge(genv, dst) unless @new_edges.include?([src, dst])
168
167
  end
@@ -175,6 +174,14 @@ module TypeProf::Core
175
174
  @boxes, @new_boxes = @new_boxes, @boxes
176
175
  @new_boxes.clear
177
176
 
177
+ @diagnostics.each do |diag|
178
+ genv.add_diagnostic_path(diag.node.lenv.path)
179
+ diag.node.remove_diagnostic(diag)
180
+ end
181
+ @new_diagnostics.each do |diag|
182
+ genv.add_diagnostic_path(diag.node.lenv.path)
183
+ diag.node.add_diagnostic(diag)
184
+ end
178
185
  @diagnostics, @new_diagnostics = @new_diagnostics, @diagnostics
179
186
  @new_diagnostics.clear
180
187