typeprof 0.1.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 (218) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +26 -0
  3. data/.gitignore +7 -0
  4. data/.gitmodules +6 -0
  5. data/Gemfile +12 -0
  6. data/Gemfile.lock +41 -0
  7. data/README.md +53 -0
  8. data/Rakefile +10 -0
  9. data/doc/doc.ja.md +415 -0
  10. data/doc/doc.md +429 -0
  11. data/doc/ppl2019.pdf +0 -0
  12. data/exe/typeprof +5 -0
  13. data/lib/typeprof.rb +13 -0
  14. data/lib/typeprof/analyzer.rb +1911 -0
  15. data/lib/typeprof/builtin.rb +554 -0
  16. data/lib/typeprof/cli.rb +110 -0
  17. data/lib/typeprof/container-type.rb +626 -0
  18. data/lib/typeprof/export.rb +203 -0
  19. data/lib/typeprof/import.rb +546 -0
  20. data/lib/typeprof/insns-def.rb +61 -0
  21. data/lib/typeprof/iseq.rb +387 -0
  22. data/lib/typeprof/method.rb +267 -0
  23. data/lib/typeprof/type.rb +1092 -0
  24. data/lib/typeprof/utils.rb +209 -0
  25. data/run.sh +3 -0
  26. data/smoke/alias.rb +30 -0
  27. data/smoke/alias2.rb +19 -0
  28. data/smoke/any-cbase.rb +5 -0
  29. data/smoke/any1.rb +15 -0
  30. data/smoke/any2.rb +17 -0
  31. data/smoke/arguments.rb +16 -0
  32. data/smoke/array-each.rb +14 -0
  33. data/smoke/array-each2.rb +15 -0
  34. data/smoke/array-each3.rb +15 -0
  35. data/smoke/array-ltlt.rb +13 -0
  36. data/smoke/array-ltlt2.rb +16 -0
  37. data/smoke/array-map.rb +11 -0
  38. data/smoke/array-map2.rb +10 -0
  39. data/smoke/array-map3.rb +22 -0
  40. data/smoke/array-mul.rb +17 -0
  41. data/smoke/array-plus1.rb +10 -0
  42. data/smoke/array-plus2.rb +15 -0
  43. data/smoke/array-pop.rb +11 -0
  44. data/smoke/array-replace.rb +12 -0
  45. data/smoke/array-s-aref.rb +11 -0
  46. data/smoke/array1.rb +26 -0
  47. data/smoke/array10.rb +14 -0
  48. data/smoke/array11.rb +13 -0
  49. data/smoke/array12.rb +24 -0
  50. data/smoke/array13.rb +30 -0
  51. data/smoke/array14.rb +13 -0
  52. data/smoke/array2.rb +27 -0
  53. data/smoke/array3.rb +25 -0
  54. data/smoke/array4.rb +14 -0
  55. data/smoke/array5.rb +13 -0
  56. data/smoke/array6.rb +14 -0
  57. data/smoke/array7.rb +13 -0
  58. data/smoke/array8.rb +13 -0
  59. data/smoke/array9.rb +12 -0
  60. data/smoke/attr.rb +28 -0
  61. data/smoke/backtrace.rb +32 -0
  62. data/smoke/block1.rb +22 -0
  63. data/smoke/block10.rb +14 -0
  64. data/smoke/block11.rb +39 -0
  65. data/smoke/block12.rb +22 -0
  66. data/smoke/block2.rb +14 -0
  67. data/smoke/block3.rb +38 -0
  68. data/smoke/block4.rb +18 -0
  69. data/smoke/block5.rb +18 -0
  70. data/smoke/block6.rb +20 -0
  71. data/smoke/block7.rb +20 -0
  72. data/smoke/block8.rb +27 -0
  73. data/smoke/block9.rb +12 -0
  74. data/smoke/blown.rb +12 -0
  75. data/smoke/break1.rb +18 -0
  76. data/smoke/break2.rb +15 -0
  77. data/smoke/case.rb +16 -0
  78. data/smoke/case2.rb +17 -0
  79. data/smoke/class.rb +5 -0
  80. data/smoke/class_instance_var.rb +9 -0
  81. data/smoke/class_method.rb +25 -0
  82. data/smoke/class_method2.rb +21 -0
  83. data/smoke/class_method3.rb +27 -0
  84. data/smoke/constant1.rb +38 -0
  85. data/smoke/constant2.rb +33 -0
  86. data/smoke/constant3.rb +9 -0
  87. data/smoke/constant4.rb +11 -0
  88. data/smoke/context-sensitive1.rb +12 -0
  89. data/smoke/cvar.rb +28 -0
  90. data/smoke/cvar2.rb +17 -0
  91. data/smoke/demo.rb +80 -0
  92. data/smoke/demo1.rb +16 -0
  93. data/smoke/demo10.rb +20 -0
  94. data/smoke/demo11.rb +11 -0
  95. data/smoke/demo2.rb +14 -0
  96. data/smoke/demo3.rb +16 -0
  97. data/smoke/demo4.rb +27 -0
  98. data/smoke/demo5.rb +13 -0
  99. data/smoke/demo6.rb +21 -0
  100. data/smoke/demo7.rb +14 -0
  101. data/smoke/demo8.rb +18 -0
  102. data/smoke/demo9.rb +18 -0
  103. data/smoke/dummy-execution1.rb +14 -0
  104. data/smoke/dummy-execution2.rb +16 -0
  105. data/smoke/ensure1.rb +20 -0
  106. data/smoke/enumerator.rb +15 -0
  107. data/smoke/expandarray1.rb +22 -0
  108. data/smoke/expandarray2.rb +23 -0
  109. data/smoke/fib.rb +28 -0
  110. data/smoke/flow1.rb +16 -0
  111. data/smoke/flow2.rb +14 -0
  112. data/smoke/flow3.rb +14 -0
  113. data/smoke/flow4.rb +5 -0
  114. data/smoke/flow5.rb +19 -0
  115. data/smoke/flow6.rb +19 -0
  116. data/smoke/flow7.rb +26 -0
  117. data/smoke/for.rb +9 -0
  118. data/smoke/freeze.rb +11 -0
  119. data/smoke/function.rb +16 -0
  120. data/smoke/gvar.rb +13 -0
  121. data/smoke/hash-fetch.rb +27 -0
  122. data/smoke/hash1.rb +18 -0
  123. data/smoke/hash2.rb +12 -0
  124. data/smoke/hash3.rb +13 -0
  125. data/smoke/hash4.rb +10 -0
  126. data/smoke/hash5.rb +14 -0
  127. data/smoke/inheritance.rb +34 -0
  128. data/smoke/inheritance2.rb +29 -0
  129. data/smoke/initialize.rb +26 -0
  130. data/smoke/instance_eval.rb +18 -0
  131. data/smoke/int_times.rb +14 -0
  132. data/smoke/integer.rb +10 -0
  133. data/smoke/ivar.rb +29 -0
  134. data/smoke/ivar2.rb +30 -0
  135. data/smoke/kernel-class.rb +12 -0
  136. data/smoke/keyword1.rb +11 -0
  137. data/smoke/keyword2.rb +11 -0
  138. data/smoke/keyword3.rb +12 -0
  139. data/smoke/keyword4.rb +11 -0
  140. data/smoke/keyword5.rb +15 -0
  141. data/smoke/kwsplat1.rb +42 -0
  142. data/smoke/kwsplat2.rb +12 -0
  143. data/smoke/manual-rbs.rb +27 -0
  144. data/smoke/manual-rbs.rbs +3 -0
  145. data/smoke/manual-rbs2.rb +20 -0
  146. data/smoke/manual-rbs2.rbs +8 -0
  147. data/smoke/masgn1.rb +13 -0
  148. data/smoke/masgn2.rb +17 -0
  149. data/smoke/masgn3.rb +12 -0
  150. data/smoke/method_in_branch.rb +22 -0
  151. data/smoke/module1.rb +29 -0
  152. data/smoke/module2.rb +28 -0
  153. data/smoke/module3.rb +33 -0
  154. data/smoke/module4.rb +29 -0
  155. data/smoke/module_function1.rb +28 -0
  156. data/smoke/module_function2.rb +28 -0
  157. data/smoke/multiple-include.rb +14 -0
  158. data/smoke/multiple-superclass.rb +16 -0
  159. data/smoke/next1.rb +20 -0
  160. data/smoke/next2.rb +16 -0
  161. data/smoke/object-send1.rb +22 -0
  162. data/smoke/once.rb +12 -0
  163. data/smoke/optional1.rb +13 -0
  164. data/smoke/optional2.rb +15 -0
  165. data/smoke/parameterizedd-self.rb +18 -0
  166. data/smoke/pathname1.rb +13 -0
  167. data/smoke/pathname2.rb +13 -0
  168. data/smoke/printf.rb +20 -0
  169. data/smoke/proc.rb +19 -0
  170. data/smoke/proc2.rb +16 -0
  171. data/smoke/proc3.rb +14 -0
  172. data/smoke/proc4.rb +11 -0
  173. data/smoke/range.rb +13 -0
  174. data/smoke/redo1.rb +21 -0
  175. data/smoke/redo2.rb +22 -0
  176. data/smoke/req-keyword.rb +12 -0
  177. data/smoke/rescue1.rb +20 -0
  178. data/smoke/rescue2.rb +22 -0
  179. data/smoke/respond_to.rb +22 -0
  180. data/smoke/rest-farg.rb +10 -0
  181. data/smoke/rest1.rb +25 -0
  182. data/smoke/rest2.rb +30 -0
  183. data/smoke/rest3.rb +36 -0
  184. data/smoke/rest4.rb +18 -0
  185. data/smoke/rest5.rb +10 -0
  186. data/smoke/rest6.rb +11 -0
  187. data/smoke/retry1.rb +20 -0
  188. data/smoke/return.rb +13 -0
  189. data/smoke/reveal.rb +13 -0
  190. data/smoke/singleton_class.rb +8 -0
  191. data/smoke/singleton_method.rb +9 -0
  192. data/smoke/step.rb +17 -0
  193. data/smoke/string-split.rb +11 -0
  194. data/smoke/struct.rb +9 -0
  195. data/smoke/struct2.rb +24 -0
  196. data/smoke/super1.rb +50 -0
  197. data/smoke/super2.rb +16 -0
  198. data/smoke/super3.rb +19 -0
  199. data/smoke/svar1.rb +12 -0
  200. data/smoke/tap1.rb +17 -0
  201. data/smoke/toplevel.rb +12 -0
  202. data/smoke/two-map.rb +17 -0
  203. data/smoke/type_var.rb +10 -0
  204. data/smoke/typed_method.rb +15 -0
  205. data/smoke/union-recv.rb +29 -0
  206. data/smoke/variadic1.rb.notyet +5 -0
  207. data/smoke/wrong-extend.rb +25 -0
  208. data/smoke/wrong-include.rb +26 -0
  209. data/smoke/wrong-rbs.rb +15 -0
  210. data/smoke/wrong-rbs.rbs +7 -0
  211. data/testbed/ao.rb +297 -0
  212. data/testbed/diff-lcs-entrypoint.rb +4 -0
  213. data/testbed/goodcheck-Gemfile.lock +51 -0
  214. data/tools/coverage.rb +14 -0
  215. data/tools/setup-insns-def.rb +30 -0
  216. data/tools/stackprof-wrapper.rb +10 -0
  217. data/typeprof.gemspec +24 -0
  218. metadata +262 -0
@@ -0,0 +1,554 @@
1
+ module TypeProf
2
+ module Builtin
3
+ module_function
4
+
5
+ def get_sym(target, ty, ep, scratch)
6
+ unless ty.is_a?(Type::Symbol)
7
+ scratch.warn(ep, "symbol expected")
8
+ return
9
+ end
10
+ sym = ty.sym
11
+ unless sym
12
+ scratch.warn(ep, "dynamic symbol is given to #{ target }; ignored")
13
+ return
14
+ end
15
+ sym
16
+ end
17
+
18
+ def vmcore_set_method_alias(recv, mid, aargs, ep, env, scratch, &ctn)
19
+ klass, new_mid, old_mid = aargs.lead_tys
20
+ new_sym = get_sym("alias", new_mid, ep, scratch) or return
21
+ old_sym = get_sym("alias", old_mid, ep, scratch) or return
22
+ scratch.alias_method(klass, ep.ctx.cref.singleton, new_sym, old_sym)
23
+ ctn[Type.nil, ep, env]
24
+ end
25
+
26
+ def vmcore_undef_method(recv, mid, aargs, ep, env, scratch, &ctn)
27
+ # no-op
28
+ ctn[Type.nil, ep, env]
29
+ end
30
+
31
+ def vmcore_hash_merge_kwd(recv, mid, aargs, ep, env, scratch, &ctn)
32
+ h1 = aargs.lead_tys[0]
33
+ h2 = aargs.lead_tys[1]
34
+ elems = nil
35
+ h1.each_child do |h1|
36
+ if h1.is_a?(Type::LocalHash)
37
+ h1_elems = scratch.get_container_elem_types(env, ep, h1.id)
38
+ h2.each_child do |h2|
39
+ if h2.is_a?(Type::LocalHash)
40
+ h2_elems = scratch.get_container_elem_types(env, ep, h2.id)
41
+ elems0 = h1_elems.union(h2_elems)
42
+ if elems
43
+ elems = elems.union(elems0)
44
+ else
45
+ elems = elems0
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ elems ||= Type::Hash::Elements.new({Type.any => Type.any})
52
+ base_ty = Type::Instance.new(Type::Builtin[:hash])
53
+ ret_ty = Type::Hash.new(elems, base_ty)
54
+ ctn[ret_ty, ep, env]
55
+ end
56
+
57
+ def lambda(recv, mid, aargs, ep, env, scratch, &ctn)
58
+ ctn[aargs.blk_ty, ep, env]
59
+ end
60
+
61
+ def proc_call(recv, mid, aargs, ep, env, scratch, &ctn)
62
+ given_block = env.static_env.blk_ty == recv
63
+ scratch.do_invoke_block(given_block, recv, aargs, ep, env, &ctn)
64
+ end
65
+
66
+ def object_s_new(recv, mid, aargs, ep, env, scratch, &ctn)
67
+ ty = Type::Instance.new(recv)
68
+ meths = scratch.get_method(recv, false, :initialize)
69
+ meths.flat_map do |meth|
70
+ meth.do_send(ty, :initialize, aargs, ep, env, scratch) do |ret_ty, ep, env|
71
+ ctn[Type::Instance.new(recv), ep, env]
72
+ end
73
+ end
74
+ end
75
+
76
+ def object_is_a?(recv, mid, aargs, ep, env, scratch, &ctn)
77
+ raise unless aargs.lead_tys.size != 0
78
+ if recv.is_a?(Type::Instance)
79
+ if recv.klass == aargs.lead_tys[0] # XXX: inheritance
80
+ true_val = Type::Instance.new(Type::Builtin[:true])
81
+ ctn[true_val, ep, env]
82
+ else
83
+ false_val = Type::Instance.new(Type::Builtin[:false])
84
+ ctn[false_val, ep, env]
85
+ end
86
+ else
87
+ ctn[Type.bool, ep, env]
88
+ end
89
+ end
90
+
91
+ def object_respond_to?(recv, mid, aargs, ep, env, scratch, &ctn)
92
+ raise unless aargs.lead_tys.size != 0
93
+ sym = get_sym("respond_to?", aargs.lead_tys[0], ep, scratch)
94
+ if sym
95
+ if recv.get_method(sym, scratch)
96
+ true_val = Type::Instance.new(Type::Builtin[:true])
97
+ ctn[true_val, ep, env]
98
+ else
99
+ false_val = Type::Instance.new(Type::Builtin[:false])
100
+ ctn[false_val, ep, env]
101
+ end
102
+ else
103
+ ctn[Type.bool, ep, env]
104
+ end
105
+ end
106
+
107
+ def object_class(recv, mid, aargs, ep, env, scratch, &ctn)
108
+ if recv.is_a?(Type::Instance)
109
+ ctn[recv.klass, ep, env]
110
+ else
111
+ ctn[Type.any, ep, env]
112
+ end
113
+ end
114
+
115
+ def object_send(recv, mid, aargs, ep, env, scratch, &ctn)
116
+ if aargs.lead_tys.size >= 1
117
+ mid_ty, = aargs.lead_tys
118
+ else
119
+ mid_ty = aargs.rest_ty
120
+ end
121
+ aargs = ActualArguments.new(aargs.lead_tys[1..-1], aargs.rest_ty, aargs.kw_ty, aargs.blk_ty)
122
+ found = false
123
+ mid_ty.each_child do |mid|
124
+ if mid.is_a?(Type::Symbol)
125
+ found = true
126
+ mid = mid.sym
127
+ scratch.do_send(recv, mid, aargs, ep, env, &ctn)
128
+ end
129
+ end
130
+ unless found
131
+ ctn[Type.any, ep, env]
132
+ end
133
+ end
134
+
135
+ def object_instance_eval(recv, mid, aargs, ep, env, scratch, &ctn)
136
+ if aargs.lead_tys.size >= 1
137
+ scratch.warn(ep, "instance_eval with arguments are ignored")
138
+ ctn[type.any, ep, env]
139
+ return
140
+ end
141
+ naargs = ActualArguments.new([recv], Type.nil, nil, Type.nil)
142
+ given_block = env.static_env.blk_ty == recv
143
+ scratch.do_invoke_block(given_block, aargs.blk_ty, naargs, ep, env, replace_recv_ty: recv) do |_ret_ty, ep|
144
+ ctn[recv, ep, scratch.return_envs[ep]]
145
+ end
146
+ end
147
+
148
+ def module_include(recv, mid, aargs, ep, env, scratch, &ctn)
149
+ arg = aargs.lead_tys[0]
150
+ scratch.include_module(recv, arg)
151
+ ctn[recv, ep, env]
152
+ end
153
+
154
+ def module_extend(recv, mid, aargs, ep, env, scratch, &ctn)
155
+ arg = aargs.lead_tys[0]
156
+ arg.each_child do |arg|
157
+ if arg.is_a?(Type::Class)
158
+ scratch.extend_module(recv, arg)
159
+ end
160
+ end
161
+ ctn[recv, ep, env]
162
+ end
163
+
164
+ def module_module_function(recv, mid, aargs, ep, env, scratch, &ctn)
165
+ if aargs.lead_tys.empty?
166
+ ctn[recv, ep, env.enable_module_function]
167
+ else
168
+ aargs.lead_tys.each do |aarg|
169
+ sym = get_sym("module_function", aarg, ep, scratch) or next
170
+ meths = Type::Instance.new(recv).get_method(sym, scratch)
171
+ meths.each do |mdef|
172
+ scratch.add_method(recv, sym, true, mdef)
173
+ end
174
+ end
175
+ ctn[recv, ep, env]
176
+ end
177
+ end
178
+
179
+ def module_attr_accessor(recv, mid, aargs, ep, env, scratch, &ctn)
180
+ aargs.lead_tys.each do |aarg|
181
+ sym = get_sym("attr_accessor", aarg, ep, scratch) or next
182
+ cref = ep.ctx.cref
183
+ scratch.add_attr_method(cref.klass, sym, :"@#{ sym }", :accessor)
184
+ end
185
+ ctn[Type.nil, ep, env]
186
+ end
187
+
188
+ def module_attr_reader(recv, mid, aargs, ep, env, scratch, &ctn)
189
+ aargs.lead_tys.each do |aarg|
190
+ sym = get_sym("attr_reader", aarg, ep, scratch) or next
191
+ cref = ep.ctx.cref
192
+ scratch.add_attr_method(cref.klass, sym, :"@#{ sym }", :reader)
193
+ end
194
+ ctn[Type.nil, ep, env]
195
+ end
196
+
197
+ def module_attr_writer(recv, mid, aargs, ep, env, scratch, &ctn)
198
+ aargs.lead_tys.each do |aarg|
199
+ sym = get_sym("attr_writer", aarg, ep, scratch) or next
200
+ cref = ep.ctx.cref
201
+ scratch.add_attr_method(cref.klass, sym, :"@#{ sym }", :writer)
202
+ end
203
+ ctn[Type.nil, ep, env]
204
+ end
205
+
206
+ def kernel_p(recv, mid, aargs, ep, env, scratch, &ctn)
207
+ aargs.lead_tys.each do |aarg|
208
+ scratch.reveal_type(ep, scratch.globalize_type(aarg, env, ep))
209
+ end
210
+ ctn[aargs.lead_tys.size == 1 ? aargs.lead_tys.first : Type.any, ep, env]
211
+ end
212
+
213
+ def array_aref(recv, mid, aargs, ep, env, scratch, &ctn)
214
+ return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalArray)
215
+
216
+ case aargs.lead_tys.size
217
+ when 1
218
+ idx = aargs.lead_tys.first
219
+ if idx.is_a?(Type::Literal)
220
+ idx = idx.lit
221
+ if idx.is_a?(Range)
222
+ ty = scratch.get_array_elem_type(env, ep, recv.id)
223
+ base_ty = Type::Instance.new(Type::Builtin[:ary])
224
+ ret_ty = Type::Array.new(Type::Array::Elements.new([], ty), base_ty)
225
+ ctn[ret_ty, ep, env]
226
+ return
227
+ end
228
+ idx = nil if !idx.is_a?(Integer)
229
+ else
230
+ idx = nil
231
+ end
232
+ ty = scratch.get_array_elem_type(env, ep, recv.id, idx)
233
+ ctn[ty, ep, env]
234
+ when 2
235
+ ty = scratch.get_array_elem_type(env, ep, recv.id)
236
+ base_ty = Type::Instance.new(Type::Builtin[:ary])
237
+ ret_ty = Type::Array.new(Type::Array::Elements.new([], ty), base_ty)
238
+ ctn[ret_ty, ep, env]
239
+ else
240
+ ctn[Type.any, ep, env]
241
+ end
242
+ end
243
+
244
+ def array_aset(recv, mid, aargs, ep, env, scratch, &ctn)
245
+ return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalArray)
246
+
247
+ raise NotImplementedError if aargs.lead_tys.size != 2
248
+
249
+ idx = aargs.lead_tys.first
250
+ if idx.is_a?(Type::Literal)
251
+ idx = idx.lit
252
+ raise NotImplementedError if !idx.is_a?(Integer)
253
+ else
254
+ idx = nil
255
+ end
256
+
257
+ ty = aargs.lead_tys.last
258
+
259
+ env = scratch.update_container_elem_types(env, ep, recv.id) do |elems|
260
+ elems.update(idx, ty)
261
+ end
262
+
263
+ ctn[ty, ep, env]
264
+ end
265
+
266
+ def array_pop(recv, mid, aargs, ep, env, scratch, &ctn)
267
+ return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalArray)
268
+
269
+ if aargs.lead_tys.size != 0
270
+ ctn[Type.any, ep, env]
271
+ return
272
+ end
273
+
274
+ ty = scratch.get_array_elem_type(env, ep, recv.id)
275
+ ctn[ty, ep, env]
276
+ end
277
+
278
+ def hash_aref(recv, mid, aargs, ep, env, scratch, &ctn)
279
+ return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalHash)
280
+
281
+ if aargs.lead_tys.size != 1
282
+ ctn[Type.any, ep, env]
283
+ return
284
+ end
285
+ idx = aargs.lead_tys.first
286
+ #idx = scratch.globalize_type(idx, env, ep)
287
+ # XXX: recv may be a union
288
+ recv.each_child do |recv|
289
+ if recv.is_a?(Type::LocalHash)
290
+ ty = scratch.get_hash_elem_type(env, ep, recv.id, idx)
291
+ else
292
+ ty = Type.any
293
+ end
294
+ ctn[ty, ep, env]
295
+ end
296
+ end
297
+
298
+ def hash_aset(recv, mid, aargs, ep, env, scratch, &ctn)
299
+ return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalHash)
300
+
301
+ raise NotImplementedError if aargs.lead_tys.size != 2
302
+
303
+ idx = aargs.lead_tys.first
304
+ idx = scratch.globalize_type(idx, env, ep)
305
+ ty = aargs.lead_tys.last
306
+
307
+ unless recv.is_a?(Type::LocalHash)
308
+ # to ignore: class OptionMap < Hash
309
+ return ctn[ty, ep, env]
310
+ end
311
+
312
+ env = scratch.update_container_elem_types(env, ep, recv.id) do |elems|
313
+ elems.update(idx, ty)
314
+ end
315
+
316
+ ctn[ty, ep, env]
317
+ end
318
+
319
+ def struct_initialize(recv, mid, aargs, ep, env, scratch, &ctn)
320
+ recv = Type::Instance.new(recv)
321
+ scratch.get_instance_variable(recv, :_members, ep, env) do |ty, nenv|
322
+ ty = scratch.globalize_type(ty, nenv, ep)
323
+ ty.elems.lead_tys.zip(aargs.lead_tys) do |sym, ty|
324
+ ty ||= Type.nil
325
+ scratch.set_instance_variable(recv, sym.sym, ty, ep, env)
326
+ end
327
+ end
328
+ #scratch.set_instance_variable(recv, , ty, ep, env)
329
+ ctn[recv, ep, env]
330
+ end
331
+
332
+ def struct_i_new(recv, mid, aargs, ep, env, scratch, &ctn)
333
+ struct_klass = recv
334
+ while struct_klass.superclass != Type::Builtin[:struct]
335
+ struct_klass = struct_klass.superclass
336
+ end
337
+ if struct_klass.superclass != Type::Builtin[:struct]
338
+ ctn[Type.any, ep, env]
339
+ return
340
+ end
341
+ if struct_klass != recv
342
+ scratch.get_instance_variable(Type::Instance.new(struct_klass), :_members, ep, env) do |ty, nenv|
343
+ ty = scratch.globalize_type(ty, nenv, ep)
344
+ scratch.set_instance_variable(Type::Instance.new(recv), :_members, ty, ep, env)
345
+ end
346
+ end
347
+ meths = scratch.get_method(recv, false, :initialize)
348
+ meths.flat_map do |meth|
349
+ meth.do_send(recv, :initialize, aargs, ep, env, scratch) do |ret_ty, ep, env|
350
+ ctn[Type::Instance.new(recv), ep, env]
351
+ end
352
+ end
353
+ end
354
+
355
+ def struct_s_new(recv, mid, aargs, ep, env, scratch, &ctn)
356
+ # TODO: keyword_init
357
+
358
+ fields = aargs.lead_tys.map {|ty| get_sym("Struct.new", ty, ep, scratch) }.compact
359
+ struct_klass = scratch.new_struct(ep)
360
+
361
+ scratch.add_singleton_custom_method(struct_klass, :new, Builtin.method(:struct_i_new))
362
+ scratch.add_singleton_custom_method(struct_klass, :[], Builtin.method(:struct_i_new))
363
+ fields.each do |field|
364
+ scratch.add_attr_method(struct_klass, field, field, :accessor)
365
+ end
366
+ fields = fields.map {|field| Type::Symbol.new(field, Type::Instance.new(Type::Builtin[:sym])) }
367
+ base_ty = Type::Instance.new(Type::Builtin[:ary])
368
+ fields = Type::Array.new(Type::Array::Elements.new(fields), base_ty)
369
+ scratch.set_instance_variable(Type::Instance.new(struct_klass), :_members, fields, ep, env)
370
+ #add_singleton_custom_method(struct_klass, :members, Builtin.method(:...))
371
+
372
+ ctn[struct_klass, ep, env]
373
+ end
374
+
375
+ def file_load(path, ep, env, scratch, &ctn)
376
+ iseq = ISeq.compile(path)
377
+ callee_ep, callee_env = CLI.starting_state(iseq)
378
+ scratch.merge_env(callee_ep, callee_env)
379
+
380
+ scratch.add_callsite!(callee_ep.ctx, nil, ep, env) do |_ret_ty, ep|
381
+ ret_ty = Type::Instance.new(Type::Builtin[:true])
382
+ ctn[ret_ty, ep, env]
383
+ end
384
+ end
385
+
386
+ def kernel_require(recv, mid, aargs, ep, env, scratch, &ctn)
387
+ raise NotImplementedError if aargs.lead_tys.size != 1
388
+ feature = aargs.lead_tys.first
389
+ if feature.is_a?(Type::Literal)
390
+ feature = feature.lit
391
+
392
+ begin
393
+ if scratch.loaded_features[feature]
394
+ result = Type::Instance.new(Type::Builtin[:false])
395
+ return ctn[result, ep, env]
396
+ end
397
+ scratch.loaded_features[feature] = true
398
+
399
+ # XXX: dynamic RBS load is really needed?? Another idea:
400
+ #
401
+ # * RBS should be loaded in advance of analysis
402
+ # * require "some_gem/foo" should be ignored
403
+ # * require "app/foo" should always load .rb file (in this case, app/foo.rb)
404
+ if RubySignatureImporter.import_library(scratch, feature)
405
+ result = Type::Instance.new(Type::Builtin[:true])
406
+ return ctn[result, ep, env]
407
+ end
408
+
409
+ begin
410
+ gem feature
411
+ rescue Gem::MissingSpecError, Gem::LoadError
412
+ end
413
+ filetype, path = $LOAD_PATH.resolve_feature_path(feature)
414
+ if filetype == :rb
415
+ # TODO: if there is RBS file for the library, do not read the source code
416
+ return file_load(path, ep, env, scratch, &ctn) if File.readable?(path)
417
+
418
+ scratch.warn(ep, "failed to load: #{ path }")
419
+ else
420
+ scratch.warn(ep, "cannot load a .so file: #{ path }")
421
+ end
422
+ rescue LoadError
423
+ scratch.warn(ep, "failed to require: #{ feature }")
424
+ end
425
+ else
426
+ scratch.warn(ep, "require target cannot be identified statically")
427
+ end
428
+
429
+ result = Type::Instance.new(Type::Builtin[:true])
430
+ ctn[result, ep, env]
431
+ end
432
+
433
+ def kernel_require_relative(recv, mid, aargs, ep, env, scratch, &ctn)
434
+ raise NotImplementedError if aargs.lead_tys.size != 1
435
+ feature = aargs.lead_tys.first
436
+ if feature.is_a?(Type::Literal)
437
+ feature = feature.lit
438
+
439
+ if scratch.loaded_features[feature]
440
+ result = Type::Instance.new(Type::Builtin[:false])
441
+ return ctn[result, ep, env]
442
+ end
443
+ scratch.loaded_features[feature] = true
444
+
445
+ path = File.join(File.dirname(ep.ctx.iseq.path), feature) + ".rb" # XXX
446
+ return file_load(path, ep, env, scratch, &ctn) if File.readable?(path)
447
+
448
+ scratch.warn(ep, "failed to load: #{ path }")
449
+ else
450
+ scratch.warn(ep, "require target cannot be identified statically")
451
+ feature = nil
452
+ end
453
+
454
+ result = Type::Instance.new(Type::Builtin[:true])
455
+ ctn[result, ep, env]
456
+ end
457
+
458
+ def kernel_Array(recv, mid, aargs, ep, env, scratch, &ctn)
459
+ raise NotImplementedError if aargs.lead_tys.size != 1
460
+ ty = aargs.lead_tys.first
461
+ ty = scratch.globalize_type(ty, env, ep)
462
+ all_ty = Type.bot
463
+ ty.each_child_global do |ty|
464
+ if ty.is_a?(Type::Array)
465
+ all_ty = all_ty.union(ty)
466
+ else
467
+ base_ty = Type::Instance.new(Type::Builtin[:ary])
468
+ ret_ty = Type::Array.new(Type::Array::Elements.new([ty]), base_ty)
469
+ all_ty = all_ty.union(ret_ty)
470
+ end
471
+ end
472
+ ctn[all_ty, ep, env]
473
+ end
474
+
475
+ def self.setup_initial_global_env(scratch)
476
+ klass_obj = scratch.new_class(nil, :Object, [], :__root__) # cbase, name, superclass
477
+ scratch.add_constant(klass_obj, "Object", klass_obj)
478
+ klass_true = scratch.new_class(klass_obj, :TrueClass, [], klass_obj) # ???
479
+ klass_false = scratch.new_class(klass_obj, :FalseClass, [], klass_obj) # ???
480
+ klass_nil = scratch.new_class(klass_obj, :NilClass, [], klass_obj) # ???
481
+
482
+ Type::Builtin[:obj] = klass_obj
483
+ Type::Builtin[:true] = klass_true
484
+ Type::Builtin[:false] = klass_false
485
+ Type::Builtin[:nil] = klass_nil
486
+
487
+ RubySignatureImporter.import_builtin(scratch)
488
+
489
+ Type::Builtin[:vmcore] = scratch.new_class(klass_obj, :VMCore, [], klass_obj)
490
+ Type::Builtin[:int] = scratch.get_constant(klass_obj, :Integer)
491
+ Type::Builtin[:float] = scratch.get_constant(klass_obj, :Float)
492
+ Type::Builtin[:rational] = scratch.get_constant(klass_obj, :Rational)
493
+ Type::Builtin[:sym] = scratch.get_constant(klass_obj, :Symbol)
494
+ Type::Builtin[:str] = scratch.get_constant(klass_obj, :String)
495
+ Type::Builtin[:struct] = scratch.get_constant(klass_obj, :Struct)
496
+ Type::Builtin[:ary] = scratch.get_constant(klass_obj, :Array)
497
+ Type::Builtin[:hash] = scratch.get_constant(klass_obj, :Hash)
498
+ Type::Builtin[:io] = scratch.get_constant(klass_obj, :IO)
499
+ Type::Builtin[:proc] = scratch.get_constant(klass_obj, :Proc)
500
+ Type::Builtin[:range] = scratch.get_constant(klass_obj, :Range)
501
+ Type::Builtin[:regexp] = scratch.get_constant(klass_obj, :Regexp)
502
+ Type::Builtin[:matchdata] = scratch.get_constant(klass_obj, :MatchData)
503
+ Type::Builtin[:class] = scratch.get_constant(klass_obj, :Class)
504
+ Type::Builtin[:module] = scratch.get_constant(klass_obj, :Module)
505
+ Type::Builtin[:exc] = scratch.get_constant(klass_obj, :Exception)
506
+
507
+ klass_vmcore = Type::Builtin[:vmcore]
508
+ klass_ary = Type::Builtin[:ary]
509
+ klass_hash = Type::Builtin[:hash]
510
+ klass_struct = Type::Builtin[:struct]
511
+ klass_proc = Type::Builtin[:proc]
512
+ klass_module = Type::Builtin[:module]
513
+
514
+ scratch.add_custom_method(klass_vmcore, :"core#set_method_alias", Builtin.method(:vmcore_set_method_alias))
515
+ scratch.add_custom_method(klass_vmcore, :"core#undef_method", Builtin.method(:vmcore_undef_method))
516
+ scratch.add_custom_method(klass_vmcore, :"core#hash_merge_kwd", Builtin.method(:vmcore_hash_merge_kwd))
517
+ scratch.add_custom_method(klass_vmcore, :lambda, Builtin.method(:lambda))
518
+ scratch.add_singleton_custom_method(klass_obj, :"new", Builtin.method(:object_s_new))
519
+ scratch.add_singleton_custom_method(klass_obj, :"attr_accessor", Builtin.method(:module_attr_accessor))
520
+ scratch.add_singleton_custom_method(klass_obj, :"attr_reader", Builtin.method(:module_attr_reader))
521
+ scratch.add_singleton_custom_method(klass_obj, :"attr_writer", Builtin.method(:module_attr_writer))
522
+ scratch.add_custom_method(klass_obj, :p, Builtin.method(:kernel_p))
523
+ scratch.add_custom_method(klass_obj, :is_a?, Builtin.method(:object_is_a?))
524
+ scratch.add_custom_method(klass_obj, :respond_to?, Builtin.method(:object_respond_to?))
525
+ scratch.add_custom_method(klass_obj, :class, Builtin.method(:object_class))
526
+ scratch.add_custom_method(klass_obj, :send, Builtin.method(:object_send))
527
+ scratch.add_custom_method(klass_obj, :instance_eval, Builtin.method(:object_instance_eval))
528
+
529
+ scratch.add_custom_method(klass_module, :include, Builtin.method(:module_include))
530
+ scratch.add_custom_method(klass_module, :extend, Builtin.method(:module_extend))
531
+ scratch.add_custom_method(klass_module, :module_function, Builtin.method(:module_module_function))
532
+
533
+ scratch.add_custom_method(klass_proc, :[], Builtin.method(:proc_call))
534
+ scratch.add_custom_method(klass_proc, :call, Builtin.method(:proc_call))
535
+
536
+ scratch.add_custom_method(klass_ary, :[], Builtin.method(:array_aref))
537
+ scratch.add_custom_method(klass_ary, :[]=, Builtin.method(:array_aset))
538
+ scratch.add_custom_method(klass_ary, :pop, Builtin.method(:array_pop))
539
+
540
+ scratch.add_custom_method(klass_hash, :[], Builtin.method(:hash_aref))
541
+ scratch.add_custom_method(klass_hash, :[]=, Builtin.method(:hash_aset))
542
+
543
+ scratch.add_custom_method(klass_struct, :initialize, Builtin.method(:struct_initialize))
544
+ scratch.add_singleton_custom_method(klass_struct, :new, Builtin.method(:struct_s_new))
545
+
546
+ scratch.add_custom_method(klass_obj, :require, Builtin.method(:kernel_require))
547
+ scratch.add_custom_method(klass_obj, :require_relative, Builtin.method(:kernel_require_relative))
548
+ scratch.add_custom_method(klass_obj, :Array, Builtin.method(:kernel_Array))
549
+
550
+ fargs, ret_ty = FormalArguments.new([], [], nil, [], nil, nil, Type.any), Type.any
551
+ scratch.add_method(klass_obj, :initialize, false, TypedMethodDef.new([[fargs, ret_ty]], nil))
552
+ end
553
+ end
554
+ end