typeprof 0.21.11 → 0.30.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -31
  3. data/bin/typeprof +5 -0
  4. data/doc/doc.ja.md +134 -0
  5. data/doc/doc.md +136 -0
  6. data/lib/typeprof/cli/cli.rb +180 -0
  7. data/lib/typeprof/cli.rb +2 -133
  8. data/lib/typeprof/code_range.rb +112 -0
  9. data/lib/typeprof/core/ast/base.rb +263 -0
  10. data/lib/typeprof/core/ast/call.rb +251 -0
  11. data/lib/typeprof/core/ast/const.rb +126 -0
  12. data/lib/typeprof/core/ast/control.rb +432 -0
  13. data/lib/typeprof/core/ast/meta.rb +150 -0
  14. data/lib/typeprof/core/ast/method.rb +335 -0
  15. data/lib/typeprof/core/ast/misc.rb +263 -0
  16. data/lib/typeprof/core/ast/module.rb +123 -0
  17. data/lib/typeprof/core/ast/pattern.rb +140 -0
  18. data/lib/typeprof/core/ast/sig_decl.rb +471 -0
  19. data/lib/typeprof/core/ast/sig_type.rb +663 -0
  20. data/lib/typeprof/core/ast/value.rb +319 -0
  21. data/lib/typeprof/core/ast/variable.rb +315 -0
  22. data/lib/typeprof/core/ast.rb +472 -0
  23. data/lib/typeprof/core/builtin.rb +146 -0
  24. data/lib/typeprof/core/env/method.rb +137 -0
  25. data/lib/typeprof/core/env/method_entity.rb +55 -0
  26. data/lib/typeprof/core/env/module_entity.rb +408 -0
  27. data/lib/typeprof/core/env/static_read.rb +155 -0
  28. data/lib/typeprof/core/env/type_alias_entity.rb +27 -0
  29. data/lib/typeprof/core/env/value_entity.rb +32 -0
  30. data/lib/typeprof/core/env.rb +360 -0
  31. data/lib/typeprof/core/graph/box.rb +991 -0
  32. data/lib/typeprof/core/graph/change_set.rb +224 -0
  33. data/lib/typeprof/core/graph/filter.rb +155 -0
  34. data/lib/typeprof/core/graph/vertex.rb +222 -0
  35. data/lib/typeprof/core/graph.rb +3 -0
  36. data/lib/typeprof/core/service.rb +522 -0
  37. data/lib/typeprof/core/type.rb +348 -0
  38. data/lib/typeprof/core/util.rb +81 -0
  39. data/lib/typeprof/core.rb +32 -0
  40. data/lib/typeprof/diagnostic.rb +35 -0
  41. data/lib/typeprof/lsp/messages.rb +430 -0
  42. data/lib/typeprof/lsp/server.rb +177 -0
  43. data/lib/typeprof/lsp/text.rb +69 -0
  44. data/lib/typeprof/lsp/util.rb +61 -0
  45. data/lib/typeprof/lsp.rb +4 -907
  46. data/lib/typeprof/version.rb +1 -1
  47. data/lib/typeprof.rb +4 -18
  48. data/typeprof.gemspec +5 -7
  49. metadata +48 -35
  50. data/.github/dependabot.yml +0 -6
  51. data/.github/workflows/main.yml +0 -39
  52. data/.gitignore +0 -9
  53. data/Gemfile +0 -17
  54. data/Gemfile.lock +0 -41
  55. data/Rakefile +0 -10
  56. data/exe/typeprof +0 -10
  57. data/lib/typeprof/analyzer.rb +0 -2598
  58. data/lib/typeprof/arguments.rb +0 -414
  59. data/lib/typeprof/block.rb +0 -176
  60. data/lib/typeprof/builtin.rb +0 -893
  61. data/lib/typeprof/code-range.rb +0 -177
  62. data/lib/typeprof/config.rb +0 -158
  63. data/lib/typeprof/container-type.rb +0 -912
  64. data/lib/typeprof/export.rb +0 -589
  65. data/lib/typeprof/import.rb +0 -852
  66. data/lib/typeprof/insns-def.rb +0 -65
  67. data/lib/typeprof/iseq.rb +0 -864
  68. data/lib/typeprof/method.rb +0 -355
  69. data/lib/typeprof/type.rb +0 -1140
  70. data/lib/typeprof/utils.rb +0 -212
  71. data/tools/coverage.rb +0 -14
  72. data/tools/setup-insns-def.rb +0 -30
  73. data/typeprof-lsp +0 -3
@@ -1,414 +0,0 @@
1
- module TypeProf
2
- # Arguments from caller side
3
- class ActualArguments
4
- def initialize(lead_tys, rest_ty, kw_tys, blk_ty)
5
- @lead_tys = lead_tys
6
- raise unless lead_tys
7
- @rest_ty = rest_ty
8
- @kw_tys = kw_tys # kw_tys should be {:key1 => Type, :key2 => Type, ...} or {nil => Type}
9
- raise if !kw_tys.is_a?(::Hash)
10
- @blk_ty = blk_ty
11
- raise unless blk_ty
12
- end
13
-
14
- def for_method_missing(mid)
15
- ActualArguments.new([mid] + @lead_tys, @rest_ty, @kw_tys, @blk_ty)
16
- end
17
-
18
- attr_reader :lead_tys, :rest_ty, :kw_tys, :blk_ty
19
- attr_accessor :node_id
20
-
21
- def globalize(caller_env, visited, depth)
22
- lead_tys = @lead_tys.map {|ty| ty.globalize(caller_env, visited, depth) }
23
- rest_ty = @rest_ty.globalize(caller_env, visited, depth) if @rest_ty
24
- kw_tys = @kw_tys.to_h do |key, ty|
25
- [key, ty.globalize(caller_env, visited, depth)]
26
- end
27
- ActualArguments.new(lead_tys, rest_ty, kw_tys, @blk_ty)
28
- end
29
-
30
- def limit_size(limit)
31
- self
32
- end
33
-
34
- def consistent_with_method_signature?(msig)
35
- aargs = @lead_tys.dup
36
-
37
- # aargs: lead_tys, rest_ty
38
- # msig: lead_tys, opt_tys, rest_ty, post_tys
39
- if @rest_ty
40
- lower_bound = [0, msig.lead_tys.size + msig.post_tys.size - aargs.size].max
41
- upper_bound = [0, lower_bound + msig.opt_tys.size].max
42
- (lower_bound..upper_bound).each do |n|
43
- # BUG: @rest_ty is an Array, so need to squash
44
- tmp_aargs = ActualArguments.new(@lead_tys + [@rest_ty] * n, nil, @kw_tys, @blk_ty)
45
- subst = tmp_aargs.consistent_with_method_signature?(msig) # XXX: wrong subst handling in the loop!
46
- return subst if subst
47
- end
48
- return nil
49
- end
50
-
51
- subst = {}
52
- if msig.rest_ty
53
- return nil if aargs.size < msig.lead_tys.size + msig.post_tys.size
54
- aargs.shift(msig.lead_tys.size).zip(msig.lead_tys) do |aarg, farg|
55
- return nil unless subst2 = Type.match?(aarg, farg)
56
- subst = Type.merge_substitution(subst, subst2)
57
- end
58
- aargs.pop(msig.post_tys.size).zip(msig.post_tys) do |aarg, farg|
59
- return nil unless subst2 = Type.match?(aarg, farg)
60
- subst = Type.merge_substitution(subst, subst2)
61
- end
62
- msig.opt_tys.each do |farg|
63
- break if aargs.empty?
64
- aarg = aargs.shift
65
- return nil unless subst2 = Type.match?(aarg, farg)
66
- subst = Type.merge_substitution(subst, subst2)
67
- end
68
- aargs.each do |aarg|
69
- return nil unless subst2 = Type.match?(aarg, msig.rest_ty)
70
- subst = Type.merge_substitution(subst, subst2)
71
- end
72
- else
73
- return nil if aargs.size < msig.lead_tys.size + msig.post_tys.size
74
- return nil if aargs.size > msig.lead_tys.size + msig.post_tys.size + msig.opt_tys.size
75
- aargs.shift(msig.lead_tys.size).zip(msig.lead_tys) do |aarg, farg|
76
- return nil unless subst2 = Type.match?(aarg, farg)
77
- subst = Type.merge_substitution(subst, subst2)
78
- end
79
- aargs.pop(msig.post_tys.size).zip(msig.post_tys) do |aarg, farg|
80
- return nil unless subst2 = Type.match?(aarg, farg)
81
- subst = Type.merge_substitution(subst, subst2)
82
- end
83
- aargs.zip(msig.opt_tys) do |aarg, farg|
84
- return nil unless subst2 = Type.match?(aarg, farg)
85
- subst = Type.merge_substitution(subst, subst2)
86
- end
87
- end
88
- # XXX: msig.keyword_tys
89
-
90
- case msig.blk_ty
91
- when Type::Proc
92
- return nil if @blk_ty == Type.nil
93
- when Type.nil
94
- return nil if @blk_ty != Type.nil
95
- when Type::Any
96
- else
97
- raise "unknown type of formal block signature"
98
- end
99
-
100
- subst
101
- end
102
-
103
- def argument_error(given, exp_lower, exp_upper)
104
- case
105
- when !exp_upper then exp = "#{ exp_lower }+"
106
- when exp_lower == exp_upper then exp = "#{ exp_lower }"
107
- else exp = "#{ exp_lower }..#{ exp_upper }"
108
- end
109
- "wrong number of arguments (given #{ given }, expected #{ exp })"
110
- end
111
-
112
- def to_block_signature
113
- if @rest_ty
114
- rest_ty = Type.bot
115
- @rest_ty.each_child_global do |ty|
116
- if ty.is_a?(Type::Array)
117
- rest_ty = rest_ty.union(ty.elems.squash)
118
- else
119
- # XXX: to_ary?
120
- rest_ty = rest_ty.union(ty)
121
- end
122
- end
123
- end
124
- BlockSignature.new(@lead_tys, [], rest_ty, @blk_ty)
125
- end
126
-
127
- def setup_formal_arguments(kind, locals, fargs_format)
128
- lead_num = fargs_format[:lead_num] || 0
129
- post_num = fargs_format[:post_num] || 0
130
- post_index = fargs_format[:post_start]
131
- rest_index = fargs_format[:rest_start]
132
- keyword = fargs_format[:keyword]
133
- kw_index = fargs_format[:kwbits] - keyword.size if keyword
134
- kwrest_index = fargs_format[:kwrest]
135
- block_index = fargs_format[:block_start]
136
- opt = fargs_format[:opt] || [0]
137
- ambiguous_param0 = fargs_format[:ambiguous_param0]
138
-
139
- lead_tys = @lead_tys
140
- rest_ty = @rest_ty
141
-
142
- if kind == :block
143
- # The rule of passing arguments to block:
144
- #
145
- # Let A is actual arguments and F is formal arguments.
146
- # If F is NOT ambiguous_param0, and if length(A) == 1, and if A[0] is an Array,
147
- # then replace A with A[0]. And then, F[i] = A[i] for all 0 <= i < length(F).
148
-
149
- # Handling the special case
150
- if !ambiguous_param0
151
- if lead_tys.size == 1 && !rest_ty && @kw_tys.empty? # length(A) == 1
152
- ty = lead_tys[0]
153
- case ty
154
- when Type::Array
155
- lead_tys = ty.elems.lead_tys
156
- rest_ty = ty.elems.rest_ty
157
- when Type::Union
158
- if ty.elems
159
- other_elems = {}
160
- ty.elems.each do |(container_kind, base_type), elems|
161
- if container_kind == Type::Array
162
- rest_ty = rest_ty ? rest_ty.union(elems.squash) : elems.squash
163
- else
164
- other_elems[[container_kind, base_type]] = elems
165
- end
166
- end
167
- end
168
- lead_tys = [Type::Union.new(ty.types, other_elems)]
169
- end
170
- end
171
- end
172
- end
173
-
174
- # Normal case: copy actual args to formal args
175
- if rest_ty
176
- ty = Type.bot
177
- additional_lead_size = nil
178
- rest_ty.each_child_global do |ty0|
179
- if ty0.is_a?(Type::Array)
180
- additional_lead_size = [additional_lead_size, ty0.elems.lead_tys.size].compact.min
181
- else
182
- additional_lead_size = 0
183
- end
184
- end
185
- additional_lead_tys = [Type.bot] * (additional_lead_size || 0)
186
- rest_ty.each_child_global do |ty0|
187
- if ty0.is_a?(Type::Array)
188
- tys, new_rest_ty = ty0.elems.take_first(additional_lead_size)
189
- tys.each_with_index do |ty00, i|
190
- additional_lead_tys[i] = additional_lead_tys[i].union(ty00)
191
- end
192
- ty = ty.union(new_rest_ty.elems.squash)
193
- else
194
- # XXX: to_ary?
195
- ty = ty.union(ty0)
196
- end
197
- end
198
- lead_tys += additional_lead_tys
199
- rest_ty = ty
200
-
201
- # XXX: Strictly speaking, this is needed, but it brings false positives. Which is better?
202
- #rest_ty = rest_ty.union(Type.nil)
203
-
204
- if rest_index
205
- # foo(a0, a1, a2, ...(rest_ty)) -->
206
- # def foo(l0, l1, o0=, o1=, *rest, p0, p1)
207
- # lead_ty argc == 0: - - - - - - -
208
- # lead_ty argc == 1: a0 - - - - - -
209
- # lead_ty argc == 2: a0 a1 - - - - -
210
- # lead_ty argc == 3: a0 a1 - - - a2 -
211
- # lead_ty argc == 4: a0 a1 - - - a2 a3
212
- # lead_ty argc == 5: a0 a1 a2 - - a3 a4
213
- # lead_ty argc == 6: a0 a1 a2 a3 - a4 a5
214
- # lead_ty argc == 7: a0 a1 a2 a3 a4 a5 a6
215
- # lead_ty argc == 8: a0 a1 a2 a3 a4|a5 a6 a7
216
- #
217
- # l0 = a0
218
- # l1 = a1
219
- # o0 = a2
220
- # o1 = a3
221
- # rest = a4|a5|...|rest_ty (= cum_lead_tys[4])
222
- # p0 = a2|a3|...|rest_ty (= cum_lead_tys[2])
223
- # p1 = a3|a4|...|rest_ty (= cum_lead_tys[3])
224
-
225
- cum_lead_tys = []
226
- ty = rest_ty
227
- lead_tys.reverse_each do |ty0|
228
- cum_lead_tys.unshift(ty = ty.union(ty0))
229
- end
230
-
231
- # l1, l2, o1, o2
232
- (lead_num + opt.size - 1).times {|i| locals[i] = lead_tys[i] || rest_ty }
233
- opt_count = opt.size - 1
234
-
235
- # rest
236
- ty = cum_lead_tys[lead_num + opt.size - 1] || rest_ty
237
- locals[rest_index] = Type::Array.new(Type::Array::Elements.new([], ty), Type::Instance.new(Type::Builtin[:ary]))
238
-
239
- # p0, p1
240
- off = [lead_num, lead_tys.size - post_num].max
241
- post_num.times {|i| locals[post_index + i] = cum_lead_tys[off + i] || rest_ty }
242
- else
243
- # foo(a0, a1, a2, ...(rest_ty)) -->
244
- # def foo(l0, l1, o0=, o1=, p0, p1)
245
- # lead_ty argc == 0: - - - - - -
246
- # lead_ty argc == 1: a0 - - - - -
247
- # lead_ty argc == 2: a0 a1 - - - -
248
- # lead_ty argc == 3: a0 a1 - - a2 -
249
- # lead_ty argc == 4: a0 a1 - - a2 a3
250
- # lead_ty argc == 5: a0 a1 a2 - a3 a4
251
- # lead_ty argc == 6: a0 a1 a2 a3 a4 a5
252
- # lead_ty argc == 7: a0 a1 a2 a3 a4 a5 (if there is a6, report error if kind is method, or ignore if kind is block)
253
- #
254
- # l0 = a0
255
- # l1 = a1
256
- # o0 = a2
257
- # o1 = a3
258
- # p0 = a2|a3|a4
259
- # p1 = a3|a4|a5
260
-
261
- if kind == :method && lead_num + opt.size - 1 + post_num < lead_tys.size
262
- return argument_error(lead_tys.size, lead_num + post_num, lead_num + post_num + opt.size - 1)
263
- end
264
-
265
- # l1, l2, o1, o2
266
- (lead_num + opt.size - 1).times {|i| locals[i] = lead_tys[i] || rest_ty }
267
- opt_count = opt.size - 1
268
-
269
- # p0, p1
270
- post_num.times do |i|
271
- candidates = lead_tys[lead_num, opt.size] || []
272
- candidates << rest_ty if candidates.size < opt.size
273
- locals[post_index + i] = candidates.inject(&:union)
274
- end
275
- end
276
- else
277
- if rest_index
278
- # foo(a0, a1, a2) -->
279
- # def foo(l0, l1, o0=, o1=, *rest, p0, p1)
280
- # lead_ty argc == 0: - - - - - - - (error if kind is method)
281
- # lead_ty argc == 1: a0 - - - - - - (error if kind is method)
282
- # lead_ty argc == 2: a0 a1 - - - - - (error if kind is method)
283
- # lead_ty argc == 3: a0 a1 - - - a2 - (error if kind is method)
284
- # lead_ty argc == 4: a0 a1 - - - a2 a3
285
- # lead_ty argc == 5: a0 a1 a2 - - a3 a4
286
- # lead_ty argc == 6: a0 a1 a2 a3 - a4 a5
287
- # lead_ty argc == 7: a0 a1 a2 a3 a4 a5 a6
288
- # lead_ty argc == 8: a0 a1 a2 a3 a4|a5 a6 a7
289
- #
290
- # len(a) < 4 -> error
291
- #
292
- # l0 = a0
293
- # l1 = a1
294
- # o0 = a2
295
- # o1 = a3
296
- # rest = a4|a5|...|a[[4,len(a)-3].max]
297
- # p0 = a[[2,len(a)-2].max]
298
- # p1 = a[[3,len(a)-1].max]
299
-
300
- if kind == :method && lead_tys.size < lead_num + post_num
301
- return argument_error(lead_tys.size, lead_num + post_num, nil)
302
- end
303
-
304
- # l0, l1
305
- lead_num.times {|i| locals[i] = lead_tys[i] || Type.nil }
306
-
307
- # o0, o1
308
- opt_count = (lead_tys.size - lead_num - post_num).clamp(0, opt.size - 1)
309
- (opt.size - 1).times {|i| locals[lead_num + i] = i < opt_count ? lead_tys[lead_num + i] : Type.nil }
310
-
311
- # rest
312
- rest_b = lead_num + opt_count
313
- rest_e = [0, lead_tys.size - post_num].max
314
- locals[rest_index] = Type::Array.new(Type::Array::Elements.new(lead_tys[rest_b...rest_e] || [], Type.bot), Type::Instance.new(Type::Builtin[:ary]))
315
-
316
- # p0, p1
317
- off = [lead_num, lead_tys.size - post_num].max
318
- post_num.times {|i| locals[post_index + i] = lead_tys[off + i] || Type.nil }
319
- else
320
- # yield a0, a1, a2 -->
321
- # do |l0, l1, o0=, o1=, p0, p1|
322
- # lead_ty argc == 0: - - - - - - (error if kind is method)
323
- # lead_ty argc == 1: a0 - - - - - (error if kind is method)
324
- # lead_ty argc == 2: a0 a1 - - - - (error if kind is method)
325
- # lead_ty argc == 3: a0 a1 - - a2 - (error if kind is method)
326
- # lead_ty argc == 4: a0 a1 - - a2 a3
327
- # lead_ty argc == 5: a0 a1 a2 - a3 a4
328
- # lead_ty argc == 6: a0 a1 a2 a3 a4 a5
329
- # lead_ty argc == 7: a0 a1 a2 a3 a4 a5 (if there is a6, report error if kind is method, or ignore if kind is block)
330
- #
331
- # l0 = a0
332
- # l1 = a1
333
- # o0 = a2
334
- # o1 = a3
335
- # p0 = a2|a3|a4
336
- # p1 = a3|a4|a5
337
-
338
- if kind == :method && (lead_tys.size < lead_num + post_num || lead_num + opt.size - 1 + post_num < lead_tys.size)
339
- return argument_error(lead_tys.size, lead_num + post_num, lead_num + post_num + opt.size - 1)
340
- end
341
-
342
- # l0, l1
343
- lead_num.times {|i| locals[i] = lead_tys[i] || Type.nil }
344
-
345
- # o0, o1
346
- opt_count = (lead_tys.size - lead_num - post_num).clamp(0, opt.size - 1)
347
- (opt.size - 1).times {|i| locals[lead_num + i] = i < opt_count ? lead_tys[lead_num + i] : Type.nil }
348
-
349
- # p0, p1
350
- off = lead_num + opt_count
351
- post_num.times {|i| locals[post_index + i] = lead_tys[off + i] || Type.nil }
352
- end
353
- end
354
-
355
- kw_tys = @kw_tys.dup
356
- if keyword
357
- keyword.each_with_index do |kw, i|
358
- case
359
- when kw.is_a?(Symbol) # required keyword
360
- key = kw
361
- req = true
362
- when kw.size == 2 # optional keyword (default value is a literal)
363
- key, default_ty = *kw
364
- default_ty = Type.guess_literal_type(default_ty)
365
- default_ty = default_ty.base_type if default_ty.is_a?(Type::Literal)
366
- req = false
367
- else # optional keyword (default value is an expression)
368
- key, = kw
369
- req = false
370
- end
371
-
372
- if kw_tys.key?(key)
373
- ty = kw_tys.delete(key)
374
- else
375
- ty = kw_tys[nil] || Type.bot
376
- end
377
-
378
- if ty == Type.bot && req
379
- return "no argument for required keywords"
380
- end
381
-
382
- ty = ty.union(default_ty) if default_ty
383
- locals[kw_index + i] = ty
384
- end
385
- end
386
-
387
- if kwrest_index
388
- if kw_tys.key?(nil)
389
- kw_rest_ty = Type.gen_hash {|h| h[Type.any] = kw_tys[nil] }
390
- else
391
- kw_rest_ty = Type.gen_hash do |h|
392
- kw_tys.each do |key, ty|
393
- sym = Type::Symbol.new(key, Type::Instance.new(Type::Builtin[:sym]))
394
- h[sym] = ty
395
- end
396
- end
397
- end
398
- locals[kwrest_index] = kw_rest_ty
399
- else
400
- if !kw_tys.empty?
401
- return "unknown keyword: #{ kw_tys.keys.join(", ") }"
402
- end
403
- end
404
-
405
- if block_index
406
- locals[block_index] = @blk_ty
407
- end
408
-
409
- start_pcs = opt[0..opt_count]
410
-
411
- return @blk_ty, start_pcs
412
- end
413
- end
414
- end
@@ -1,176 +0,0 @@
1
- module TypeProf
2
- class Block
3
- include Utils::StructuralEquality
4
- end
5
-
6
- class ISeqBlock < Block
7
- def initialize(iseq, ep)
8
- @iseq = iseq
9
- @outer_ep = ep
10
- end
11
-
12
- attr_reader :iseq, :outer_ep
13
-
14
- def inspect
15
- "#<ISeqBlock: #{ @outer_ep.source_location }>"
16
- end
17
-
18
- def consistent?(other)
19
- if other.is_a?(ISeqBlock)
20
- self == other
21
- else
22
- true # XXX
23
- end
24
- end
25
-
26
- def substitute(_subst, _depth)
27
- self
28
- end
29
-
30
- def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, replace_cref:, &ctn)
31
- blk_env = scratch.return_envs[@outer_ep]
32
- if replace_recv_ty
33
- replace_recv_ty = scratch.globalize_type(replace_recv_ty, caller_env, caller_ep)
34
- blk_env = blk_env.replace_recv_ty(replace_recv_ty)
35
- end
36
- aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
37
-
38
- scratch.add_block_signature!(self, aargs.to_block_signature)
39
-
40
- locals = [Type.nil] * @iseq.locals.size
41
-
42
- blk_ty, start_pcs = aargs.setup_formal_arguments(:block, locals, @iseq.fargs_format)
43
- if blk_ty.is_a?(String)
44
- scratch.error(caller_ep, blk_ty)
45
- ctn[Type.any, caller_ep, caller_env]
46
- return
47
- end
48
-
49
- cref = replace_cref || @outer_ep.ctx.cref
50
- nctx = Context.new(@iseq, cref, nil)
51
- callee_ep = ExecutionPoint.new(nctx, 0, @outer_ep)
52
- nenv = Env.new(blk_env.static_env, locals, [], nil)
53
- alloc_site = AllocationSite.new(callee_ep)
54
- locals.each_with_index do |ty, i|
55
- alloc_site2 = alloc_site.add_id(i)
56
- nenv, ty = scratch.localize_type(ty, nenv, callee_ep, alloc_site2)
57
- nenv = nenv.local_update(i, ty)
58
- end
59
-
60
- start_pcs.each do |start_pc|
61
- scratch.merge_env(ExecutionPoint.new(nctx, start_pc, @outer_ep), nenv)
62
- end
63
-
64
- scratch.add_block_to_ctx!(self, callee_ep.ctx)
65
- scratch.add_callsite!(callee_ep.ctx, caller_ep, caller_env, &ctn)
66
- end
67
- end
68
-
69
- class TypedBlock < Block
70
- def initialize(msig, ret_ty)
71
- @msig = msig
72
- @ret_ty = ret_ty
73
- end
74
-
75
- attr_reader :msig, :ret_ty
76
-
77
- def consistent?(other)
78
- if other.is_a?(ISeqBlock)
79
- raise "assert false"
80
- else
81
- self == other
82
- end
83
- end
84
-
85
- def substitute(subst, depth)
86
- msig = @msig.substitute(subst, depth)
87
- ret_ty = @ret_ty.substitute(subst, depth)
88
- TypedBlock.new(msig, ret_ty)
89
- end
90
-
91
- def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, replace_cref:, &ctn)
92
- aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
93
- subst = aargs.consistent_with_method_signature?(@msig)
94
- unless subst
95
- scratch.warn(caller_ep, "The arguments is not compatible to RBS block")
96
- end
97
- # check?
98
- #subst = { Type::Var.new(:self) => caller_env.static_env.recv_ty }
99
- # XXX: Update type vars
100
- ret_ty = @ret_ty.remove_type_vars
101
- ctn[ret_ty, caller_ep, caller_env]
102
- end
103
- end
104
-
105
- class SymbolBlock < Block
106
- def initialize(sym)
107
- @sym = sym
108
- end
109
-
110
- attr_reader :iseq, :outer_ep
111
-
112
- def inspect
113
- "#<SymbolBlock: #{ @sym }>"
114
- end
115
-
116
- def consistent?(other)
117
- true # XXX
118
- end
119
-
120
- def substitute(_subst, _depth)
121
- self
122
- end
123
-
124
- def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, replace_cref:, &ctn)
125
- if aargs.lead_tys.size >= 1
126
- recv = aargs.lead_tys[0]
127
- recv = Type.any if recv == Type.bot
128
- aargs = ActualArguments.new(aargs.lead_tys[1..], aargs.rest_ty, aargs.kw_tys, aargs.blk_ty)
129
- elsif aargs.rest_ty
130
- recv = aargs.rest_ty.elems.squash_or_any # XXX: need to shift
131
- else
132
- recv = Type.any
133
- end
134
-
135
- scratch.add_block_signature!(self, aargs.to_block_signature)
136
-
137
- recv.each_child do |recv|
138
- scratch.do_send(recv, @sym, aargs, caller_ep, caller_env, &ctn)
139
- end
140
- end
141
- end
142
-
143
- class CustomBlock < Block
144
- def initialize(caller_ep, mid, &blk)
145
- @caller_ep = caller_ep
146
- @mid = mid
147
- @blk = blk
148
- end
149
-
150
- def inspect
151
- "#<CustomBlock>"
152
- end
153
-
154
- def consistent?(other)
155
- true # XXX
156
- end
157
-
158
- def substitute(_subst, _depth)
159
- self
160
- end
161
-
162
- def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, replace_cref:, &ctn)
163
- aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
164
-
165
- dummy_ctx = TypedContext.new(@caller_ep, @mid)
166
-
167
- scratch.add_block_signature!(self, aargs.to_block_signature)
168
- scratch.add_block_to_ctx!(self, dummy_ctx)
169
-
170
- @blk.call(aargs, caller_ep, caller_env, scratch, replace_recv_ty: replace_recv_ty, replace_cref: replace_cref) do |ret_ty, ep, env|
171
- scratch.add_return_value!(dummy_ctx, ret_ty)
172
- ctn[ret_ty, ep, env]
173
- end
174
- end
175
- end
176
- end