typeprof 0.5.4 → 0.9.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 (289) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +7 -5
  3. data/doc/doc.ja.md +3 -4
  4. data/doc/doc.md +3 -4
  5. data/lib/typeprof/analyzer.rb +308 -171
  6. data/lib/typeprof/arguments.rb +14 -6
  7. data/lib/typeprof/block.rb +6 -2
  8. data/lib/typeprof/builtin.rb +230 -67
  9. data/lib/typeprof/cli.rb +33 -34
  10. data/lib/typeprof/config.rb +6 -4
  11. data/lib/typeprof/container-type.rb +159 -104
  12. data/lib/typeprof/export.rb +28 -22
  13. data/lib/typeprof/import.rb +70 -53
  14. data/lib/typeprof/iseq.rb +23 -7
  15. data/lib/typeprof/method.rb +71 -138
  16. data/lib/typeprof/type.rb +73 -15
  17. data/lib/typeprof/version.rb +1 -1
  18. data/smoke/alias.rb +5 -4
  19. data/smoke/alias2.rb +4 -4
  20. data/smoke/any1.rb +2 -1
  21. data/smoke/any2.rb +3 -2
  22. data/smoke/arguments.rb +3 -2
  23. data/smoke/arguments2.rb +11 -10
  24. data/smoke/array-each.rb +2 -1
  25. data/smoke/array-each2.rb +2 -1
  26. data/smoke/array-each3.rb +2 -1
  27. data/smoke/array-ltlt.rb +2 -1
  28. data/smoke/array-ltlt2.rb +2 -1
  29. data/smoke/array-map.rb +2 -1
  30. data/smoke/array-map2.rb +2 -1
  31. data/smoke/array-map3.rb +4 -3
  32. data/smoke/array-mul.rb +3 -2
  33. data/smoke/array-plus1.rb +2 -1
  34. data/smoke/array-plus2.rb +2 -2
  35. data/smoke/array-pop.rb +2 -1
  36. data/smoke/array-range-aref.rb +71 -0
  37. data/smoke/array-replace.rb +2 -1
  38. data/smoke/array-s-aref.rb +2 -1
  39. data/smoke/array1.rb +6 -5
  40. data/smoke/array10.rb +2 -1
  41. data/smoke/array11.rb +2 -1
  42. data/smoke/array12.rb +4 -3
  43. data/smoke/array13.rb +5 -4
  44. data/smoke/array14.rb +2 -1
  45. data/smoke/array15.rb +16 -0
  46. data/smoke/array2.rb +4 -3
  47. data/smoke/array3.rb +4 -4
  48. data/smoke/array4.rb +2 -1
  49. data/smoke/array5.rb +2 -1
  50. data/smoke/array6.rb +3 -2
  51. data/smoke/array7.rb +2 -1
  52. data/smoke/array8.rb +1 -1
  53. data/smoke/array9.rb +2 -1
  54. data/smoke/attr-module.rb +26 -0
  55. data/smoke/attr.rb +5 -5
  56. data/smoke/autoload.rb +14 -0
  57. data/smoke/backtrace.rb +4 -3
  58. data/smoke/block-ambiguous.rb +9 -8
  59. data/smoke/block-args1-rest.rb +12 -11
  60. data/smoke/block-args1.rb +11 -10
  61. data/smoke/block-args2-rest.rb +12 -11
  62. data/smoke/block-args2.rb +11 -10
  63. data/smoke/block-args3-rest.rb +14 -13
  64. data/smoke/block-args3.rb +13 -12
  65. data/smoke/block-blockarg.rb +5 -4
  66. data/smoke/block-kwarg.rb +11 -10
  67. data/smoke/block1.rb +2 -1
  68. data/smoke/block10.rb +2 -1
  69. data/smoke/block11.rb +6 -5
  70. data/smoke/block12.rb +3 -2
  71. data/smoke/block14.rb +3 -2
  72. data/smoke/block2.rb +2 -1
  73. data/smoke/block3.rb +3 -3
  74. data/smoke/block4.rb +3 -2
  75. data/smoke/block5.rb +3 -2
  76. data/smoke/block6.rb +3 -2
  77. data/smoke/block7.rb +2 -1
  78. data/smoke/block8.rb +4 -3
  79. data/smoke/block9.rb +2 -1
  80. data/smoke/blown.rb +2 -1
  81. data/smoke/break1.rb +3 -2
  82. data/smoke/break2.rb +2 -1
  83. data/smoke/break3.rb +13 -0
  84. data/smoke/case.rb +2 -1
  85. data/smoke/case2.rb +2 -1
  86. data/smoke/case3.rb +17 -0
  87. data/smoke/class-hierarchy.rb +5 -5
  88. data/smoke/class-hierarchy2.rb +3 -3
  89. data/smoke/class-new.rb +15 -0
  90. data/smoke/class_instance_var.rb +1 -1
  91. data/smoke/class_method.rb +2 -2
  92. data/smoke/class_method2.rb +2 -2
  93. data/smoke/class_method3.rb +4 -2
  94. data/smoke/constant1.rb +6 -6
  95. data/smoke/constant2.rb +5 -4
  96. data/smoke/constant3.rb +2 -1
  97. data/smoke/constant4.rb +2 -1
  98. data/smoke/context-sensitive1.rb +2 -1
  99. data/smoke/cvar.rb +6 -5
  100. data/smoke/cvar2.rb +2 -2
  101. data/smoke/define_method.rb +16 -0
  102. data/smoke/define_method2.rb +18 -0
  103. data/smoke/define_method3.rb +13 -0
  104. data/smoke/define_method3.rbs +3 -0
  105. data/smoke/define_method4.rb +15 -0
  106. data/smoke/define_method4.rbs +3 -0
  107. data/smoke/define_method5.rb +12 -0
  108. data/smoke/demo.rb +7 -6
  109. data/smoke/demo1.rb +2 -1
  110. data/smoke/demo10.rb +3 -2
  111. data/smoke/demo11.rb +2 -1
  112. data/smoke/demo2.rb +2 -1
  113. data/smoke/demo3.rb +2 -1
  114. data/smoke/demo4.rb +3 -3
  115. data/smoke/demo5.rb +1 -1
  116. data/smoke/demo6.rb +3 -3
  117. data/smoke/demo7.rb +2 -1
  118. data/smoke/demo8.rb +3 -2
  119. data/smoke/demo9.rb +3 -2
  120. data/smoke/dummy-execution1.rb +3 -2
  121. data/smoke/dummy-execution2.rb +2 -2
  122. data/smoke/dummy_element.rb +14 -0
  123. data/smoke/ensure1.rb +3 -2
  124. data/smoke/enumerator.rb +3 -2
  125. data/smoke/expandarray1.rb +2 -1
  126. data/smoke/expandarray2.rb +2 -1
  127. data/smoke/fib.rb +2 -2
  128. data/smoke/flip-flop.rb +28 -0
  129. data/smoke/flow1.rb +2 -1
  130. data/smoke/flow2.rb +2 -1
  131. data/smoke/flow3.rb +2 -1
  132. data/smoke/flow5.rb +2 -1
  133. data/smoke/flow6.rb +2 -1
  134. data/smoke/flow7.rb +2 -1
  135. data/smoke/flow8.rb +2 -1
  136. data/smoke/flow9.rb +12 -0
  137. data/smoke/freeze.rb +2 -1
  138. data/smoke/function.rb +3 -2
  139. data/smoke/gvar.rb +3 -2
  140. data/smoke/gvar2.rb +3 -2
  141. data/smoke/hash-bot.rb +12 -0
  142. data/smoke/hash-fetch.rb +4 -3
  143. data/smoke/hash-merge-bang.rb +2 -1
  144. data/smoke/hash1.rb +3 -2
  145. data/smoke/hash2.rb +2 -1
  146. data/smoke/hash3.rb +2 -1
  147. data/smoke/hash4.rb +2 -1
  148. data/smoke/hash5.rb +1 -1
  149. data/smoke/inheritance.rb +4 -4
  150. data/smoke/inheritance2.rb +2 -2
  151. data/smoke/initialize.rb +6 -5
  152. data/smoke/instance_eval.rb +2 -2
  153. data/smoke/instance_eval2.rb +10 -0
  154. data/smoke/instance_eval3.rb +25 -0
  155. data/smoke/int_times.rb +2 -1
  156. data/smoke/integer.rb +2 -1
  157. data/smoke/ivar.rb +5 -4
  158. data/smoke/ivar2.rb +4 -4
  159. data/smoke/ivar3.rb +2 -2
  160. data/smoke/kernel-class.rb +2 -1
  161. data/smoke/keyword1.rb +2 -1
  162. data/smoke/keyword2.rb +2 -1
  163. data/smoke/keyword3.rb +2 -1
  164. data/smoke/keyword4.rb +2 -1
  165. data/smoke/keyword5.rb +2 -1
  166. data/smoke/kwrest.rb +12 -0
  167. data/smoke/kwrest.rbs +3 -0
  168. data/smoke/kwsplat1.rb +5 -4
  169. data/smoke/kwsplat2.rb +2 -1
  170. data/smoke/lit-complex.rb +10 -0
  171. data/smoke/lit-encoding.rb +10 -0
  172. data/smoke/manual-rbs.rb +4 -3
  173. data/smoke/manual-rbs2.rb +2 -1
  174. data/smoke/manual-rbs3.rb +2 -2
  175. data/smoke/masgn1.rb +2 -1
  176. data/smoke/masgn2.rb +3 -2
  177. data/smoke/masgn3.rb +2 -1
  178. data/smoke/method_in_branch.rb +3 -2
  179. data/smoke/method_missing.rb +28 -0
  180. data/smoke/module1.rb +2 -2
  181. data/smoke/module2.rb +1 -1
  182. data/smoke/module3.rb +2 -2
  183. data/smoke/module4.rb +2 -2
  184. data/smoke/module5.rb +17 -0
  185. data/smoke/module6.rb +40 -0
  186. data/smoke/module_function1.rb +3 -3
  187. data/smoke/module_function2.rb +3 -3
  188. data/smoke/multiple-include.rb +1 -1
  189. data/smoke/multiple-superclass.rb +1 -1
  190. data/smoke/next1.rb +3 -2
  191. data/smoke/next2.rb +2 -1
  192. data/smoke/object-send1.rb +4 -3
  193. data/smoke/object-send2.rb +10 -0
  194. data/smoke/object-send3.rb +18 -0
  195. data/smoke/once.rb +2 -1
  196. data/smoke/optional1.rb +2 -1
  197. data/smoke/optional2.rb +2 -1
  198. data/smoke/optional3.rb +2 -1
  199. data/smoke/parameterizedd-self.rb +3 -2
  200. data/smoke/parameterizedd-self2.rb +15 -0
  201. data/smoke/pathname1.rb +2 -1
  202. data/smoke/pathname2.rb +2 -1
  203. data/smoke/pattern-match1.rb +2 -1
  204. data/smoke/pattern-match2.rb +2 -1
  205. data/smoke/printf.rb +2 -2
  206. data/smoke/proc.rb +3 -2
  207. data/smoke/proc2.rb +2 -1
  208. data/smoke/proc3.rb +2 -1
  209. data/smoke/proc4.rb +2 -1
  210. data/smoke/proc5.rb +19 -0
  211. data/smoke/public.rb +34 -0
  212. data/smoke/range.rb +2 -1
  213. data/smoke/rbs-alias.rb +2 -1
  214. data/smoke/rbs-attr.rb +6 -5
  215. data/smoke/rbs-attr2.rb +11 -0
  216. data/smoke/rbs-attr2.rbs +3 -0
  217. data/smoke/rbs-extend.rb +2 -1
  218. data/smoke/rbs-interface.rb +5 -4
  219. data/smoke/rbs-module.rb +26 -0
  220. data/smoke/rbs-module.rbs +4 -0
  221. data/smoke/rbs-opt-and-rest.rb +10 -0
  222. data/smoke/rbs-opt-and-rest.rbs +3 -0
  223. data/smoke/rbs-proc1.rb +2 -1
  224. data/smoke/rbs-proc2.rb +3 -2
  225. data/smoke/rbs-proc3.rb +2 -1
  226. data/smoke/rbs-record.rb +3 -2
  227. data/smoke/rbs-tyvar.rb +3 -2
  228. data/smoke/rbs-tyvar2.rb +3 -2
  229. data/smoke/rbs-tyvar3.rb +3 -2
  230. data/smoke/rbs-tyvar4.rb +3 -3
  231. data/smoke/rbs-tyvar5.rb +2 -1
  232. data/smoke/rbs-tyvar6.rb +18 -0
  233. data/smoke/rbs-tyvar6.rbs +12 -0
  234. data/smoke/rbs-tyvar7.rb +12 -0
  235. data/smoke/rbs-tyvar7.rbs +7 -0
  236. data/smoke/rbs-vars.rb +7 -8
  237. data/smoke/redo1.rb +3 -2
  238. data/smoke/redo2.rb +3 -2
  239. data/smoke/req-keyword.rb +2 -1
  240. data/smoke/rescue1.rb +3 -2
  241. data/smoke/rescue2.rb +3 -2
  242. data/smoke/rescue3.rb +19 -0
  243. data/smoke/rescue4.rb +17 -0
  244. data/smoke/respond_to.rb +2 -1
  245. data/smoke/rest-farg.rb +2 -1
  246. data/smoke/rest1.rb +3 -2
  247. data/smoke/rest2.rb +2 -1
  248. data/smoke/rest3.rb +7 -6
  249. data/smoke/rest4.rb +3 -2
  250. data/smoke/rest5.rb +2 -1
  251. data/smoke/rest6.rb +2 -1
  252. data/smoke/retry1.rb +3 -2
  253. data/smoke/return.rb +2 -1
  254. data/smoke/singleton_method.rb +1 -1
  255. data/smoke/step.rb +4 -3
  256. data/smoke/string-split.rb +2 -1
  257. data/smoke/struct-keyword_init.rb +20 -0
  258. data/smoke/struct.rb +1 -1
  259. data/smoke/struct2.rb +5 -4
  260. data/smoke/struct3.rb +2 -2
  261. data/smoke/struct4.rb +7 -0
  262. data/smoke/struct5.rb +16 -0
  263. data/smoke/struct6.rb +15 -0
  264. data/smoke/struct7.rb +17 -0
  265. data/smoke/stub-keyword.rb +10 -0
  266. data/smoke/super1.rb +5 -4
  267. data/smoke/super2.rb +1 -1
  268. data/smoke/super3.rb +3 -3
  269. data/smoke/super4.rb +43 -0
  270. data/smoke/super5.rb +36 -0
  271. data/smoke/svar1.rb +2 -1
  272. data/smoke/symbol-proc-attr.rb +22 -0
  273. data/smoke/symbol-proc-attr2.rb +15 -0
  274. data/smoke/symbol-proc-bot.rb +13 -0
  275. data/smoke/symbol-proc.rb +4 -3
  276. data/smoke/tap1.rb +3 -2
  277. data/smoke/toplevel.rb +2 -1
  278. data/smoke/two-map.rb +3 -2
  279. data/smoke/type_var.rb +2 -1
  280. data/smoke/typed_method.rb +2 -1
  281. data/smoke/uninitialize-var.rb +2 -1
  282. data/smoke/union-recv.rb +2 -2
  283. data/smoke/user-demo.rb +3 -3
  284. data/smoke/wrong-extend.rb +2 -2
  285. data/smoke/wrong-include.rb +2 -2
  286. data/smoke/wrong-include2.rb +17 -0
  287. data/typeprof.gemspec +1 -1
  288. metadata +61 -6
  289. data/tools/stackprof-wrapper.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d60066fe3965ec65f9885e311f856277d0e41330478489c026fdf6b387ba2ba
4
- data.tar.gz: 963b66fe97d98207d72645011bcd012368937ded76278d92a4b677b961c92cdc
3
+ metadata.gz: 1c3bf54ec6fee3b06397893d2f10f1fae8e7af82b8f1640a4ddd305c33922ff7
4
+ data.tar.gz: 944d40a75789b4805e53ca70e169fe68fcd4dbca7f24bc4ccc779964085e980d
5
5
  SHA512:
6
- metadata.gz: a40e89e05c1680480eb66798863ab99a4b38b3faaacdc471a6cdd45dfc1f897efcc8f613800ef28e5bc722c3504dec510ca943435873b6cb765a27f1bb073425
7
- data.tar.gz: 94dddf2c3e465ee19093ce571d50440293118b07ab7c90203aa5ccb40c4f9eb9afe1059eff045c965006affa8f0d66d141be2064feddf9a2b1f8384f8cadae64
6
+ metadata.gz: 726cdbfcda694f189a96f3f35088cbcbd9a3064e79e3838f7758d7bc393bf8591c0559db1c17993f971f9ae2ee4ca3b4c09f5c0ef6d6675752b00b6948cdfe62
7
+ data.tar.gz: b2b7353855183df391d8bc78c247eb7de09c1b65b2753789eb1e1fb0208275d10fec6d2d95745f36771de30af5e32281476100a0654db6f7cf87c8e442b36a65
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- typeprof (0.5.4)
5
- rbs (>= 0.17.0)
4
+ typeprof (0.9.0)
5
+ rbs (>= 0.20.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
@@ -11,13 +11,15 @@ GEM
11
11
  docile (1.3.2)
12
12
  power_assert (1.2.0)
13
13
  rake (13.0.1)
14
- rbs (0.17.0)
15
- simplecov (0.19.1)
14
+ rbs (0.20.1)
15
+ simplecov (0.20.0)
16
16
  docile (~> 1.1)
17
17
  simplecov-html (~> 0.11)
18
+ simplecov_json_formatter (~> 0.1)
18
19
  simplecov-html (0.12.3)
20
+ simplecov_json_formatter (0.1.2)
19
21
  stackprof (0.2.16)
20
- test-unit (3.3.6)
22
+ test-unit (3.3.7)
21
23
  power_assert
22
24
 
23
25
  PLATFORMS
@@ -35,10 +35,9 @@ $ typeprof sig/app.rbs app.rb -o sig/app.gen.rbs
35
35
  * `--exclude-dir DIR`: `DIR`以下のファイルの解析結果を出力から省略する。後に指定されているほうが優先される(`--include-dir foo --exclude-dir foo/bar`の場合う、foo/bar/baz.rbの結果は出力されず、foo/baz.rbの結果は出力される)。
36
36
  * `--include-dir DIR`: `DIR`以下のファイルの解析結果を出力に含める。後に指定されているほうが優先される(`--exclude-dir foo --include-dir foo/bar`の場合、
37
37
  foo/bar/baz.rbの結果は出力されるが、foo/baz.rbの結果は出力されない)。
38
- * `-fshow-errors`: 実行中に見つけたバグの可能性を出力します(多くの場合、大量のfalse positiveが出ます)。
39
- * `-fpedantic-output`: デフォルトでは`A | untyped`と推定されたところを単に`A`と出力しますが、より生の出力、つまり`A | untyped`と出力します。
40
- * `-fshow-container-raw-elements`: (後で書く)
41
- * `-ftype-depth-limit=NUM`: (後で書く)
38
+ * `--show-errors`: 実行中に見つけたバグの可能性を出力します(多くの場合、大量のfalse positiveが出ます)。
39
+ * `--show-untyped`: デフォルトでは`A | untyped`と推定されたところを単に`A`と出力しますが、より生の出力、つまり`A | untyped`と出力します。
40
+ * `--type-depth-limit=NUM`: (後で書く)
42
41
 
43
42
  ## TypeProfとは
44
43
 
data/doc/doc.md CHANGED
@@ -34,10 +34,9 @@ Here is a list of currently avaiable options:
34
34
  * `-r GEMNAME`: Load the RBS files of `GEMNAME`
35
35
  * `--exclude-dir DIR`: Omit the result of files that are placed under the directory `DIR`. If there are some directory specifications, the latter one is stronger. (Assuming that `--include-dir foo --exclude-dir foo/bar` is specified, the analysis result of foo/bar/baz.rb is omitted, but foo/baz.rb is shown.)
36
36
  * `--include-dir DIR`: Show the result of files that are placed under the directory `DIR`. If there are some directory specifications, the latter one is stronger. (Assuming that `--exclude-dir foo --include-dir foo/bar` is specified, the analysis result of foo/bar/baz.rb is shown, but foo/baz.rb is omitted.)
37
- * `-fshow-errors`: Prints out possible bugs found during execution (often a lot of false positives).
38
- * `-fpedantic-output`: When TypeProf inferred a type `A | untyped`, it simply outputs `A` by default. But this option forces it to output `A | untyped`.
39
- * `-fshow-container-raw-elements`: (undocumented yet)
40
- * `-ftype-depth-limit=NUM`: (undocumented yet)
37
+ * `--show-errors`: Prints out possible bugs found during execution (often a lot of false positives).
38
+ * `--show-untyped`: When TypeProf infers a type `A | untyped`, it simply outputs `A` by default. But this option forces to output `A | untyped`.
39
+ * `--type-depth-limit=NUM`: (undocumented yet)
41
40
 
42
41
  ## What is a TypeProf?
43
42
 
@@ -34,6 +34,14 @@ module TypeProf
34
34
  end
35
35
 
36
36
  attr_reader :iseq, :cref, :mid
37
+
38
+ def source_location(pc)
39
+ if @iseq
40
+ @iseq.source_location(pc)
41
+ else
42
+ "<builtin>"
43
+ end
44
+ end
37
45
  end
38
46
 
39
47
  class TypedContext
@@ -45,6 +53,14 @@ module TypeProf
45
53
  end
46
54
 
47
55
  attr_reader :caller_ep, :mid
56
+
57
+ def source_location(_pc)
58
+ if @caller_ep
59
+ @caller_ep.source_location
60
+ else
61
+ "<typed-context:#{ @mid }>"
62
+ end
63
+ end
48
64
  end
49
65
 
50
66
  class ExecutionPoint
@@ -71,36 +87,33 @@ module TypeProf
71
87
  end
72
88
 
73
89
  def source_location
74
- iseq = @ctx.iseq
75
- if iseq
76
- iseq.source_location(@pc)
77
- else
78
- "<builtin>"
79
- end
90
+ @ctx.source_location(@pc)
80
91
  end
81
92
  end
82
93
 
83
94
  class StaticEnv
84
95
  include Utils::StructuralEquality
85
96
 
86
- def initialize(recv_ty, blk_ty, mod_func)
97
+ def initialize(recv_ty, blk_ty, mod_func, pub_meth)
87
98
  @recv_ty = recv_ty
88
99
  @blk_ty = blk_ty
89
100
  @mod_func = mod_func
101
+ @pub_meth = pub_meth
90
102
 
91
103
  return if recv_ty == :top #OK
92
104
  recv_ty.each_child_global do |ty|
93
- raise ty.inspect if !ty.is_a?(Type::Instance) && !ty.is_a?(Type::Class) && ty != Type.any
105
+ raise ty.inspect if !ty.is_a?(Type::Instance) && !ty.is_a?(Type::Class) && !ty.is_a?(Type::Symbol) && ty != Type.any
94
106
  end
95
107
  end
96
108
 
97
- attr_reader :recv_ty, :blk_ty, :mod_func
109
+ attr_reader :recv_ty, :blk_ty, :mod_func, :pub_meth
98
110
 
99
111
  def merge(other)
100
112
  recv_ty = @recv_ty.union(other.recv_ty)
101
113
  blk_ty = @blk_ty.union(other.blk_ty)
102
114
  mod_func = @mod_func & other.mod_func # ??
103
- StaticEnv.new(recv_ty, blk_ty, mod_func)
115
+ pub_meth = @pub_meth & other.pub_meth # ??
116
+ StaticEnv.new(recv_ty, blk_ty, mod_func, pub_meth)
104
117
  end
105
118
  end
106
119
 
@@ -185,29 +198,27 @@ module TypeProf
185
198
  Env.new(@static_env, Utils.array_update(@locals, idx, ty), @stack, @type_params)
186
199
  end
187
200
 
188
- def deploy_type(klass, alloc_site, elems, base_ty)
189
- local_ty = klass.new(alloc_site, base_ty)
190
- type_params = Utils::HashWrapper.new(@type_params.internal_hash.merge({ alloc_site => elems }))
191
- nenv = Env.new(@static_env, @locals, @stack, type_params)
192
- return nenv, local_ty
193
- end
194
-
195
201
  def get_container_elem_types(id)
196
202
  @type_params.internal_hash[id]
197
203
  end
198
204
 
199
- def update_container_elem_types(id, elems)
205
+ def deploy_type(id, elems)
200
206
  type_params = Utils::HashWrapper.new(@type_params.internal_hash.merge({ id => elems }))
201
207
  Env.new(@static_env, @locals, @stack, type_params)
202
208
  end
203
209
 
204
210
  def enable_module_function
205
- senv = StaticEnv.new(@static_env.recv_ty, @static_env.blk_ty, true)
211
+ senv = StaticEnv.new(@static_env.recv_ty, @static_env.blk_ty, true, @static_env.pub_meth)
212
+ Env.new(senv, @locals, @stack, @type_params)
213
+ end
214
+
215
+ def method_public_set(flag)
216
+ senv = StaticEnv.new(@static_env.recv_ty, @static_env.blk_ty, @static_env.mod_func, flag)
206
217
  Env.new(senv, @locals, @stack, @type_params)
207
218
  end
208
219
 
209
220
  def replace_recv_ty(ty)
210
- senv = StaticEnv.new(ty, @static_env.blk_ty, @static_env.mod_func)
221
+ senv = StaticEnv.new(ty, @static_env.blk_ty, @static_env.mod_func, @static_env.pub_meth)
211
222
  Env.new(senv, @locals, @stack, @type_params)
212
223
  end
213
224
 
@@ -281,11 +292,10 @@ module TypeProf
281
292
  attr_reader :class_defs
282
293
 
283
294
  class ClassDef # or ModuleDef
284
- def initialize(kind, name, superclass, absolute_path)
295
+ def initialize(kind, name, absolute_path)
285
296
  raise unless name.is_a?(Array)
286
297
  @kind = kind
287
- @superclass = superclass
288
- @modules = { true => {}, false => {} }
298
+ @modules = { true => [], false => [] }
289
299
  @name = name
290
300
  @consts = {}
291
301
  @methods = {}
@@ -295,14 +305,16 @@ module TypeProf
295
305
  @namespace = nil
296
306
  end
297
307
 
298
- attr_reader :kind, :superclass, :modules, :consts, :methods, :ivars, :cvars, :absolute_path
308
+ attr_reader :kind, :modules, :consts, :methods, :ivars, :cvars, :absolute_path
299
309
  attr_accessor :name, :klass_obj
300
310
 
301
- def include_module(mod, singleton, absolute_path)
302
- # XXX: need to check if mod is already included by the ancestors?
303
- absolute_paths = @modules[singleton][mod]
304
- unless absolute_paths
305
- @modules[singleton][mod] = absolute_paths = Utils::MutableSet.new
311
+ def include_module(mod, type_args, singleton, absolute_path)
312
+ mod_, module_type_args, absolute_paths = @modules[singleton].find {|m,| m == mod }
313
+ if mod_
314
+ raise "inconsistent include/extend type args in RBS?" if module_type_args != type_args && type_args != [] && type_args != nil
315
+ else
316
+ absolute_paths = Utils::MutableSet.new
317
+ @modules[singleton].unshift([mod, type_args, absolute_paths])
306
318
  end
307
319
  absolute_paths << absolute_path
308
320
  end
@@ -319,13 +331,29 @@ module TypeProf
319
331
  @consts[name] = [ty, absolute_path]
320
332
  end
321
333
 
322
- def get_method(mid, singleton)
323
- @methods[[singleton, mid]] || begin
324
- @modules[singleton].each_key do |mod|
325
- meth = mod.get_method(mid, false)
326
- return meth if meth
334
+ def adjust_substitution(singleton, mid, mthd, subst, direct, &blk)
335
+ mthds = @methods[[singleton, mid]]
336
+ yield subst, direct if mthds&.include?(mthd)
337
+ @modules[singleton].each do |mod_def, type_args,|
338
+ if mod_def.klass_obj.type_params && type_args
339
+ subst2 = {}
340
+ mod_def.klass_obj.type_params.zip(type_args) do |(tyvar, *), tyarg|
341
+ tyvar = Type::Var.new(tyvar)
342
+ subst2[tyvar] = tyarg.substitute(subst, Config.options[:type_depth_limit])
343
+ end
344
+ mod_def.adjust_substitution(false, mid, mthd, subst2, false, &blk)
327
345
  end
328
- nil
346
+ end
347
+ end
348
+
349
+ def search_method(singleton, mid, visited, &blk)
350
+ # Currently, circular inclusion of modules is allowed
351
+ return if visited[self]
352
+ visited[self] = true
353
+ mthds = @methods[[singleton, mid]]
354
+ yield mthds, @klass_obj, singleton if mthds
355
+ @modules[singleton].each do |mod_def,|
356
+ mod_def.search_method(false, mid, visited, &blk)
329
357
  end
330
358
  end
331
359
 
@@ -344,12 +372,16 @@ module TypeProf
344
372
  end
345
373
 
346
374
  def set_method(mid, singleton, mdef)
347
- @methods[[singleton, mid]] = Utils::MutableSet.new
348
- @methods[[singleton, mid]] << mdef
375
+ if mdef
376
+ @methods[[singleton, mid]] = Utils::MutableSet.new
377
+ @methods[[singleton, mid]] << mdef
378
+ else
379
+ @methods.delete([singleton, mid])
380
+ end
349
381
  end
350
382
  end
351
383
 
352
- def include_module(including_mod, included_mod, singleton, absolute_path)
384
+ def include_module(including_mod, included_mod, type_args, singleton, caller_ep)
353
385
  return if included_mod == Type.any
354
386
 
355
387
  including_mod = @class_defs[including_mod.idx]
@@ -357,9 +389,9 @@ module TypeProf
357
389
  if included_mod.is_a?(Type::Class)
358
390
  included_mod = @class_defs[included_mod.idx]
359
391
  if included_mod && included_mod.kind == :module
360
- including_mod.include_module(included_mod, singleton, absolute_path)
392
+ including_mod.include_module(included_mod, type_args, singleton, caller_ep ? caller_ep.ctx.iseq.absolute_path : nil)
361
393
  else
362
- warn "including something that is not a module"
394
+ warn(caller_ep, "including something that is not a module")
363
395
  end
364
396
  end
365
397
  end
@@ -373,12 +405,7 @@ module TypeProf
373
405
  show_name = cbase_path(cbase) + [name]
374
406
  idx = @class_defs.size
375
407
  if superclass
376
- if superclass == :__root__
377
- superclass_idx = superclass = nil
378
- else
379
- superclass_idx = superclass.idx
380
- end
381
- @class_defs[idx] = ClassDef.new(:class, show_name, superclass_idx, absolute_path)
408
+ @class_defs[idx] = ClassDef.new(:class, show_name, absolute_path)
382
409
  klass = Type::Class.new(:class, idx, type_params, superclass, show_name)
383
410
  @class_defs[idx].klass_obj = klass
384
411
  cbase ||= klass # for bootstrap
@@ -386,7 +413,7 @@ module TypeProf
386
413
  return klass
387
414
  else
388
415
  # module
389
- @class_defs[idx] = ClassDef.new(:module, show_name, nil, absolute_path)
416
+ @class_defs[idx] = ClassDef.new(:module, show_name, absolute_path)
390
417
  mod = Type::Class.new(:module, idx, type_params, nil, show_name)
391
418
  @class_defs[idx].klass_obj = mod
392
419
  add_constant(cbase, name, mod, absolute_path)
@@ -394,14 +421,19 @@ module TypeProf
394
421
  end
395
422
  end
396
423
 
424
+ def add_superclass_type_args!(klass, tyargs)
425
+ klass.superclass_type_args = tyargs
426
+ end
427
+
397
428
  def new_struct(ep)
398
429
  return @struct_defs[ep] if @struct_defs[ep]
399
430
 
400
431
  idx = @class_defs.size
401
432
  superclass = Type::Builtin[:struct]
402
433
  name = "AnonymousStruct_generated_#{ @anonymous_struct_gen_id += 1 }"
403
- @class_defs[idx] = ClassDef.new(:class, [name], superclass.idx, ep.ctx.iseq.absolute_path)
434
+ @class_defs[idx] = ClassDef.new(:class, [name], ep.ctx.iseq.absolute_path)
404
435
  klass = Type::Class.new(:class, idx, [], superclass, name)
436
+ add_superclass_type_args!(klass, [Type.any])
405
437
  @class_defs[idx].klass_obj = klass
406
438
 
407
439
  @struct_defs[ep] = klass
@@ -431,28 +463,77 @@ module TypeProf
431
463
  end
432
464
  end
433
465
 
466
+ def adjust_substitution(klass, singleton, mid, mthd, subst, &blk)
467
+ direct = true
468
+ if klass.kind == :class
469
+ while klass != :__root__
470
+ class_def = @class_defs[klass.idx]
471
+ class_def.adjust_substitution(singleton, mid, mthd, subst, direct, &blk)
472
+ direct = false
473
+ if klass.superclass && klass.superclass_type_args
474
+ subst2 = {}
475
+ klass.superclass.type_params.zip(klass.superclass_type_args) do |(tyvar, *), tyarg|
476
+ tyvar = Type::Var.new(tyvar)
477
+ subst2[tyvar] = tyarg.substitute(subst, Config.options[:type_depth_limit])
478
+ end
479
+ subst = subst2
480
+ end
481
+ klass = klass.superclass
482
+ end
483
+ else
484
+ # module
485
+ class_def = @class_defs[klass.idx]
486
+ class_def.adjust_substitution(singleton, mid, mthd, subst, direct, &blk)
487
+ end
488
+ end
489
+
490
+ def search_method(klass, singleton, mid, &blk)
491
+ # XXX: support method alias correctly
492
+ klass_orig = klass
493
+ if klass.kind == :class
494
+ while klass != :__root__
495
+ class_def = @class_defs[klass.idx]
496
+ class_def.search_method(singleton, mid, {}, &blk)
497
+ klass = klass.superclass
498
+ end
499
+ else
500
+ # module
501
+ class_def = @class_defs[klass.idx]
502
+ class_def.search_method(singleton, mid, {}, &blk)
503
+ end
504
+ if singleton
505
+ search_method(Type::Builtin[klass_orig.kind], false, mid, &blk)
506
+ end
507
+ end
508
+
434
509
  def get_method(klass, singleton, mid)
435
- idx = klass.idx
436
- while idx
437
- class_def = @class_defs[idx]
438
- mthd = class_def.get_method(mid, singleton)
439
- # Need to be conservative to include all super candidates...?
440
- return mthd if mthd
441
- idx = class_def.superclass
510
+ search_method(klass, singleton, mid) {|mthds,| return mthds }
511
+ end
512
+
513
+ def get_all_super_methods(klass, singleton, current_klass, mid)
514
+ hit = false
515
+ search_method(klass, singleton, mid) do |mthds, klass0, singleton0|
516
+ yield mthds, klass0, singleton0 if hit
517
+ hit = klass0 == current_klass
442
518
  end
443
- return get_method(Type::Builtin[:class], false, mid) if singleton
444
- nil
445
519
  end
446
520
 
447
521
  def get_super_method(ctx, singleton)
448
- idx = ctx.cref.klass.idx
522
+ klass = ctx.cref.klass
449
523
  mid = ctx.mid
450
- idx = @class_defs[idx].superclass
451
- while idx
452
- class_def = @class_defs[idx]
524
+ if klass.kind == :class
525
+ klass = klass.superclass
526
+ while klass != :__root__
527
+ class_def = @class_defs[klass.idx]
528
+ mthd = class_def.get_method(mid, singleton)
529
+ return mthd if mthd
530
+ klass = klass.superclass
531
+ end
532
+ else
533
+ # module
534
+ class_def = @class_defs[klass.idx]
453
535
  mthd = class_def.get_method(mid, singleton)
454
536
  return mthd if mthd
455
- idx = class_def.superclass
456
537
  end
457
538
  nil
458
539
  end
@@ -478,9 +559,7 @@ module TypeProf
478
559
  end
479
560
 
480
561
  def add_constant(klass, name, value, user_defined)
481
- if klass == Type.any
482
- self
483
- else
562
+ if klass.is_a?(Type::Class)
484
563
  @class_defs[klass.idx].add_constant(name, value, user_defined)
485
564
  end
486
565
  end
@@ -508,12 +587,12 @@ module TypeProf
508
587
  end
509
588
  end
510
589
 
511
- def add_iseq_method(klass, mid, iseq, cref)
512
- add_method(klass, mid, false, ISeqMethodDef.new(iseq, cref))
590
+ def add_iseq_method(klass, mid, iseq, cref, outer_ep, pub_meth)
591
+ add_method(klass, mid, false, ISeqMethodDef.new(iseq, cref, outer_ep, pub_meth))
513
592
  end
514
593
 
515
- def add_singleton_iseq_method(klass, mid, iseq, cref)
516
- add_method(klass, mid, true, ISeqMethodDef.new(iseq, cref))
594
+ def add_singleton_iseq_method(klass, mid, iseq, cref, outer_ep, pub_meth)
595
+ add_method(klass, mid, true, ISeqMethodDef.new(iseq, cref, outer_ep, pub_meth))
517
596
  end
518
597
 
519
598
  def set_custom_method(klass, mid, impl)
@@ -546,6 +625,10 @@ module TypeProf
546
625
  @iseq_method_to_ctxs[iseq_mdef] << ctx
547
626
  end
548
627
 
628
+ def add_executed_iseq(iseq)
629
+ @executed_iseqs << iseq
630
+ end
631
+
549
632
  def add_callsite!(callee_ctx, caller_ep, caller_env, &ctn)
550
633
  @executed_iseqs << callee_ctx.iseq if callee_ctx.is_a?(Context)
551
634
 
@@ -605,7 +688,7 @@ module TypeProf
605
688
  def add_read!(site, ep, &ctn)
606
689
  entry = @tbl[site] ||= Entry.new(false, {}, Type.bot, Utils::MutableSet.new)
607
690
  entry.read_continuations[ep] = ctn
608
- entry.absolute_paths << ep.ctx.iseq.absolute_path
691
+ entry.absolute_paths << ep.ctx.iseq.absolute_path if ep.ctx.is_a?(Context)
609
692
  ctn[entry.type, ep]
610
693
  end
611
694
 
@@ -664,6 +747,7 @@ module TypeProf
664
747
 
665
748
  def add_cvar_read!(klass, var, ep, &ctn)
666
749
  klass.each_child do |klass|
750
+ next unless klass.is_a?(Type::Class)
667
751
  class_def = @class_defs[klass.idx]
668
752
  next unless class_def
669
753
  class_def.cvars.add_read!(var, ep, &ctn)
@@ -672,6 +756,7 @@ module TypeProf
672
756
 
673
757
  def add_cvar_write!(klass, var, ty, ep)
674
758
  klass.each_child do |klass|
759
+ next unless klass.is_a?(Type::Class)
675
760
  class_def = @class_defs[klass.idx]
676
761
  next unless class_def
677
762
  class_def.cvars.add_write!(var, ty, ep, self)
@@ -722,7 +807,7 @@ module TypeProf
722
807
  merge_return_env(tmp_ep) do |menv|
723
808
  elems = menv.get_container_elem_types(id)
724
809
  elems = yield elems
725
- menv = menv.update_container_elem_types(id, elems)
810
+ menv = menv.deploy_type(id, elems)
726
811
  gid = @alloc_site_to_global_id[id]
727
812
  if gid
728
813
  ty = globalize_type(elems.to_local_type(id, base_type), env, ep)
@@ -734,7 +819,7 @@ module TypeProf
734
819
  else
735
820
  elems = env.get_container_elem_types(id)
736
821
  elems = yield elems
737
- env = env.update_container_elem_types(id, elems)
822
+ env = env.deploy_type(id, elems)
738
823
  gid = @alloc_site_to_global_id[id]
739
824
  if gid
740
825
  ty = globalize_type(elems.to_local_type(id, base_type), env, ep)
@@ -775,11 +860,11 @@ module TypeProf
775
860
  ep = @worklist.deletemin
776
861
 
777
862
  iter_counter += 1
778
- if Config.verbose >= 1
863
+ if Config.options[:show_indicator]
779
864
  tick2 = Time.now
780
865
  if tick2 - tick >= 1
781
866
  tick = tick2
782
- $stderr << "\rType Profiling... (%d steps @ %s)\e[K" % [iter_counter, ep.source_location]
867
+ $stderr << "\rType Profiling... (%d instructions @ %s)\e[K" % [iter_counter, ep.source_location]
783
868
  $stderr.flush
784
869
  end
785
870
  end
@@ -795,9 +880,7 @@ module TypeProf
795
880
 
796
881
  break if @terminated
797
882
 
798
- # XXX: it would be good to provide no-dummy-execution mode.
799
- # It should work as a bit smarter "rbs prototype rb";
800
- # show all method definitions as "untyped" arguments and return values
883
+ break unless Config.options[:stub_execution]
801
884
 
802
885
  begin
803
886
  iseq, (kind, dummy_continuation) = @pending_execution.first
@@ -805,7 +888,7 @@ module TypeProf
805
888
  @pending_execution.delete(iseq)
806
889
  end while @executed_iseqs.include?(iseq)
807
890
 
808
- puts "DEBUG: trigger dummy execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.verbose >= 2
891
+ puts "DEBUG: trigger stub execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.verbose >= 2
809
892
 
810
893
  break if !iseq
811
894
  case kind
@@ -822,7 +905,7 @@ module TypeProf
822
905
  end
823
906
  end
824
907
  end
825
- $stderr.print "\r\e[K" if Config.verbose >= 1
908
+ $stderr.print "\r\e[K" if Config.options[:show_indicator]
826
909
 
827
910
  stat_eps
828
911
  end
@@ -863,9 +946,9 @@ module TypeProf
863
946
  end
864
947
  end
865
948
 
866
- def pend_method_execution(iseq, meth, recv, mid, cref)
949
+ def pend_method_execution(iseq, meth, recv, mid, cref, ep)
867
950
  ctx = Context.new(iseq, cref, mid)
868
- ep = ExecutionPoint.new(ctx, 0, nil)
951
+ ep = ExecutionPoint.new(ctx, 0, ep)
869
952
  locals = [Type.nil] * iseq.locals.size
870
953
 
871
954
  fargs_format = iseq.fargs_format
@@ -900,17 +983,23 @@ module TypeProf
900
983
  locals[kwrest_index] = Type.any if kwrest_index
901
984
  locals[block_index] = Type.nil if block_index
902
985
 
903
- env = Env.new(StaticEnv.new(recv, Type.nil, false), locals, [], Utils::HashWrapper.new({}))
986
+ env = Env.new(StaticEnv.new(recv, Type.nil, false, true), locals, [], Utils::HashWrapper.new({}))
904
987
 
905
- @pending_execution[iseq] ||= [:method, [meth, ep, env]]
988
+ if !@pending_execution[iseq] || @pending_execution[iseq][0] == :block
989
+ @pending_execution[iseq] = [:method, [meth, ep, env]]
990
+ end
906
991
  end
907
992
 
908
993
  def pend_block_dummy_execution(blk, iseq, nep, nenv)
909
994
  @pending_execution[iseq] ||= [:block, [blk, {}]]
910
- if @pending_execution[iseq][1][1][nep]
911
- @pending_execution[iseq][1][1][nep] = @pending_execution[iseq][1][1][nep].merge(nenv)
995
+ if @pending_execution[iseq][0] == :block
996
+ if @pending_execution[iseq][1][1][nep]
997
+ @pending_execution[iseq][1][1][nep] = @pending_execution[iseq][1][1][nep].merge(nenv)
998
+ else
999
+ @pending_execution[iseq][1][1][nep] = nenv
1000
+ end
912
1001
  else
913
- @pending_execution[iseq][1][1][nep] = nenv
1002
+ # XXX: what to do?
914
1003
  end
915
1004
  end
916
1005
 
@@ -919,7 +1008,7 @@ module TypeProf
919
1008
  alloc_site = AllocationSite.new(ep)
920
1009
  nenv, ty = localize_type(ty, env, ep, alloc_site)
921
1010
  case ty
922
- when Type::LocalCell, Type::LocalArray, Type::LocalHash
1011
+ when Type::Local
923
1012
  @alloc_site_to_global_id[ty.id] = [recv, var] # need overwrite check??
924
1013
  end
925
1014
  yield ty, nenv
@@ -959,7 +1048,7 @@ module TypeProf
959
1048
  block_start = iseq.fargs_format[:block_start]
960
1049
 
961
1050
  lead_tys = env.locals[0, lead_num].map {|ty| globalize_type(ty, env, ep) }
962
- opt_tys = opt.size > 1 ? env.locals[lead_num, opt.size - 1].map {|ty| globalize_type(ty, env, ep) } : nil
1051
+ opt_tys = opt.size > 1 ? env.locals[lead_num, opt.size - 1].map {|ty| globalize_type(ty, env, ep) } : []
963
1052
  if rest_start # XXX:squash
964
1053
  ty = globalize_type(env.locals[lead_num + opt.size - 1], env, ep)
965
1054
  rest_ty = Type.bot
@@ -1085,31 +1174,7 @@ module TypeProf
1085
1174
 
1086
1175
  when :definemethod
1087
1176
  mid, iseq = operands
1088
- cref = ep.ctx.cref
1089
- recv = env.static_env.recv_ty
1090
- if cref.klass.is_a?(Type::Class)
1091
- typed_mdef = check_typed_method(cref.klass, mid, ep.ctx.cref.singleton)
1092
- recv = Type::Instance.new(recv) if recv.is_a?(Type::Class)
1093
- if typed_mdef
1094
- mdef = ISeqMethodDef.new(iseq, cref)
1095
- typed_mdef.each do |typed_mdef|
1096
- typed_mdef.do_match_iseq_mdef(mdef, recv, mid, env, ep, self)
1097
- end
1098
- else
1099
- if ep.ctx.cref.singleton
1100
- meth = add_singleton_iseq_method(cref.klass, mid, iseq, cref)
1101
- else
1102
- meth = add_iseq_method(cref.klass, mid, iseq, cref)
1103
- if env.static_env.mod_func
1104
- add_singleton_iseq_method(cref.klass, mid, iseq, cref)
1105
- end
1106
- end
1107
-
1108
- pend_method_execution(iseq, meth, recv, mid, ep.ctx.cref)
1109
- end
1110
- else
1111
- # XXX: what to do?
1112
- end
1177
+ do_define_iseq_method(ep, env, mid, iseq, nil)
1113
1178
 
1114
1179
  when :definesmethod
1115
1180
  mid, iseq = operands
@@ -1117,8 +1182,8 @@ module TypeProf
1117
1182
  cref = ep.ctx.cref
1118
1183
  recv.each_child do |recv|
1119
1184
  if recv.is_a?(Type::Class)
1120
- meth = add_singleton_iseq_method(recv, mid, iseq, cref)
1121
- pend_method_execution(iseq, meth, recv, mid, ep.ctx.cref)
1185
+ meth = add_singleton_iseq_method(recv, mid, iseq, cref, nil, env.static_env.pub_meth)
1186
+ pend_method_execution(iseq, meth, recv, mid, ep.ctx.cref, nil)
1122
1187
  else
1123
1188
  recv = Type.any # XXX: what to do?
1124
1189
  end
@@ -1154,10 +1219,11 @@ module TypeProf
1154
1219
  else # module
1155
1220
  superclass = nil
1156
1221
  end
1157
- if cbase == Type.any
1158
- klass = Type.any
1159
- else
1222
+ if cbase.is_a?(Type::Class)
1160
1223
  klass = new_class(cbase, id, [], superclass, ep.ctx.iseq.absolute_path)
1224
+ add_superclass_type_args!(klass, superclass.type_params.map { Type.any }) if superclass
1225
+ else
1226
+ klass = Type.any
1161
1227
  end
1162
1228
  end
1163
1229
  singleton = false
@@ -1179,7 +1245,7 @@ module TypeProf
1179
1245
  nctx = Context.new(iseq, ncref, nil)
1180
1246
  nep = ExecutionPoint.new(nctx, 0, nil)
1181
1247
  locals = [Type.nil] * iseq.locals.size
1182
- nenv = Env.new(StaticEnv.new(recv, blk, false), locals, [], Utils::HashWrapper.new({}))
1248
+ nenv = Env.new(StaticEnv.new(recv, blk, false, true), locals, [], Utils::HashWrapper.new({}))
1183
1249
  merge_env(nep, nenv)
1184
1250
  add_callsite!(nep.ctx, ep, env) do |ret_ty, ep, env|
1185
1251
  nenv, ret_ty = localize_type(ret_ty, env, ep)
@@ -1245,30 +1311,30 @@ module TypeProf
1245
1311
  end
1246
1312
  when :invokesuper
1247
1313
  env, recv, _, aargs = setup_actual_arguments(:method, operands, ep, env)
1248
-
1249
- env, recv = localize_type(env.static_env.recv_ty, env, ep)
1250
- mid = ep.ctx.mid
1251
- singleton = !recv.is_a?(Type::Instance) # TODO: any?
1252
- # XXX: need to support included module...
1253
- meths = get_super_method(ep.ctx, singleton) # TODO: multiple return values
1254
- if meths
1255
- meths.each do |meth|
1256
- # XXX: this decomposition is really needed??
1257
- # It calls `Object.new` with union receiver which causes an error, but
1258
- # it may be a fault of builtin Object.new implementation.
1259
- recv.each_child do |recv|
1260
- meth.do_send(recv, mid, aargs, ep, env, self) do |ret_ty, ep, env|
1261
- nenv, ret_ty, = localize_type(ret_ty, env, ep)
1262
- nenv = nenv.push(ret_ty)
1263
- merge_env(ep.next, nenv)
1314
+ mid = ep.ctx.mid
1315
+ found = false
1316
+ recv.each_child_global do |recv|
1317
+ klass, singleton = recv.method_dispatch_info
1318
+ next unless klass
1319
+ get_all_super_methods(klass, singleton, ep.ctx.cref.klass, ep.ctx.mid) do |meths, klass|
1320
+ found = true
1321
+ meths.each do |meth|
1322
+ # XXX: this decomposition is really needed??
1323
+ # It calls `Object.new` with union receiver which causes an error, but
1324
+ # it may be a fault of builtin Object.new implementation.
1325
+ recv.each_child do |recv|
1326
+ meth.do_send(recv, mid, aargs, ep, env, self) do |ret_ty, ep, env|
1327
+ nenv, ret_ty, = localize_type(ret_ty, env, ep)
1328
+ nenv = nenv.push(ret_ty)
1329
+ merge_env(ep.next, nenv)
1330
+ end
1264
1331
  end
1265
1332
  end
1266
1333
  end
1267
- return
1268
- else
1269
- error(ep, "no superclass method: #{ env.static_env.recv_ty.screen_name(self) }##{ mid }")
1270
- env = env.push(Type.any)
1271
1334
  end
1335
+ return if found
1336
+ error(ep, "no superclass method: #{ env.static_env.recv_ty.screen_name(self) }##{ mid }")
1337
+ env = env.push(Type.any)
1272
1338
  when :invokebuiltin
1273
1339
  raise NotImplementedError
1274
1340
  when :leave
@@ -1295,11 +1361,24 @@ module TypeProf
1295
1361
  return
1296
1362
  when :break
1297
1363
  tmp_ep = ep
1298
- tmp_ep = tmp_ep.outer while tmp_ep.ctx.iseq.type != :block
1299
- tmp_ep = tmp_ep.outer
1300
- nenv = @return_envs[tmp_ep].push(ty)
1301
- merge_env(tmp_ep.next, nenv)
1302
- # TODO: jump to ensure?
1364
+ while true
1365
+ if tmp_ep.ctx.iseq.type == :block
1366
+ tmp_ep = tmp_ep.outer
1367
+ nenv = @return_envs[tmp_ep].push(ty)
1368
+ merge_env(tmp_ep.next, nenv)
1369
+ break
1370
+ end
1371
+ _type, _iseq, cont, stack_depth = tmp_ep.ctx.iseq.catch_table[tmp_ep.pc]&.find {|type,| type == :break }
1372
+ if cont
1373
+ nenv = @return_envs[tmp_ep]
1374
+ nenv, = nenv.pop(nenv.stack.size - stack_depth)
1375
+ nenv = nenv.push(ty)
1376
+ tmp_ep = tmp_ep.jump(cont)
1377
+ merge_env(tmp_ep, nenv)
1378
+ break
1379
+ end
1380
+ tmp_ep = tmp_ep.outer
1381
+ end
1303
1382
  when :next, :redo
1304
1383
  # begin; rescue; next; end
1305
1384
  tmp_ep = ep.outer
@@ -1492,9 +1571,7 @@ module TypeProf
1492
1571
  ret_ty.each_child do |ret_ty|
1493
1572
  flow_env = env.local_update(-var_idx+2, ret_ty)
1494
1573
  ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::Symbol)
1495
- ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::LocalCell)
1496
- ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::LocalArray)
1497
- ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::LocalHash)
1574
+ ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::Local)
1498
1575
  if ret_ty.is_a?(Type::Instance)
1499
1576
  if ret_ty.klass == pattern_ty # XXX: inheritance
1500
1577
  merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
@@ -1543,7 +1620,7 @@ module TypeProf
1543
1620
  warn(ep, "already initialized constant #{ Type::Instance.new(cbase).screen_name(self) }::#{ name }")
1544
1621
  end
1545
1622
  ty.each_child do |ty|
1546
- if ty.is_a?(Type::Class) && ty.superclass == Type::Builtin[:struct]
1623
+ if ty.is_a?(Type::Class) && cbase.is_a?(Type::Class) && ty.superclass == Type::Builtin[:struct]
1547
1624
  @class_defs[ty.idx].name = cbase_path(cbase) + [name]
1548
1625
  end
1549
1626
  end
@@ -1552,7 +1629,6 @@ module TypeProf
1552
1629
  when :getspecial
1553
1630
  key, type = operands
1554
1631
  if type == 0
1555
- raise NotImplementedError
1556
1632
  case key
1557
1633
  when 0 # VM_SVAR_LASTLINE
1558
1634
  env = env.push(Type.any) # or String | NilClass only?
@@ -1570,8 +1646,12 @@ module TypeProf
1570
1646
  return
1571
1647
  end
1572
1648
  when :setspecial
1573
- # flip-flop
1574
- raise NotImplementedError, "setspecial"
1649
+ key, = operands
1650
+ if key >= 2 # flip-flop
1651
+ env, = env.pop(1)
1652
+ else
1653
+ raise "unknown setspecial key: #{ key }"
1654
+ end
1575
1655
 
1576
1656
  when :dup
1577
1657
  env, (ty,) = env.pop(1)
@@ -1622,10 +1702,16 @@ module TypeProf
1622
1702
  env = env.push(Type.optional(sym_ty))
1623
1703
  when :checkmatch
1624
1704
  flag, = operands
1705
+
1706
+ # This flag means that the stack top is an array, and the check needs to be applied to find all elements
1707
+ # However, currently TypeProf uses very conservative interpretation (all check returns both true and false),
1708
+ # so we just ignore the flag now
1625
1709
  _array = flag & 4 != 0
1710
+
1626
1711
  case flag & 3
1627
- when 1
1628
- raise NotImplementedError
1712
+ when 1 # VM_CHECKMATCH_TYPE_WHEN
1713
+ env, = env.pop(2)
1714
+ env = env.push(Type.bool)
1629
1715
  when 2 # VM_CHECKMATCH_TYPE_CASE
1630
1716
  env, = env.pop(2)
1631
1717
  env = env.push(Type.bool)
@@ -1660,9 +1746,13 @@ module TypeProf
1660
1746
  from_head = flag & 2 == 0
1661
1747
  ary.each_child do |ary|
1662
1748
  case ary
1663
- when Type::LocalArray
1664
- elems = get_container_elem_types(env, ep, ary.id)
1665
- elems ||= Type::Array::Elements.new([], Type.any) # XXX
1749
+ when Type::Local
1750
+ if ary.kind == Type::Array
1751
+ elems = get_container_elem_types(env, ep, ary.id)
1752
+ elems ||= Type::Array::Elements.new([], Type.any) # XXX
1753
+ else
1754
+ elems = Type::Array::Elements.new([], Type.any) # XXX
1755
+ end
1666
1756
  do_expand_array(ep, env, elems, num, splat, from_head)
1667
1757
  when Type::Any
1668
1758
  nnum = num
@@ -1682,9 +1772,9 @@ module TypeProf
1682
1772
  return
1683
1773
  when :concatarray
1684
1774
  env, (ary1, ary2) = env.pop(2)
1685
- if ary1.is_a?(Type::LocalArray)
1775
+ if ary1.is_a?(Type::Local) && ary1.kind == Type::Array
1686
1776
  elems1 = get_container_elem_types(env, ep, ary1.id)
1687
- if ary2.is_a?(Type::LocalArray)
1777
+ if ary2.is_a?(Type::Local) && ary2.kind == Type::Array
1688
1778
  elems2 = get_container_elem_types(env, ep, ary2.id)
1689
1779
  elems = Type::Array::Elements.new([], elems1.squash.union(elems2.squash))
1690
1780
  env = update_container_elem_types(env, ep, ary1.id, ary1.base_type) { elems }
@@ -1831,6 +1921,10 @@ module TypeProf
1831
1921
  rest_ty = aargs.last
1832
1922
  aargs = aargs[0..-2]
1833
1923
  if flag_args_kw_splat
1924
+ # XXX: The types contained in ActualArguments are expected to be all local types.
1925
+ # This "globalize_type" breaks the invariant, and violates the assertion of Union#globalize that asserts @elems be nil.
1926
+ # To fix this issue fundamentally, ActualArguments should keep all arguments as-is (as like the VM does),
1927
+ # and globalize some types on the on-demand bases.
1834
1928
  ty = globalize_type(rest_ty, env, ep)
1835
1929
  if ty.is_a?(Type::Array)
1836
1930
  _, (ty,) = ty.elems.take_last(1)
@@ -1863,6 +1957,10 @@ module TypeProf
1863
1957
  aargs = ActualArguments.new(aargs, rest_ty, kw_tys, blk_ty)
1864
1958
  elsif flag_args_kw_splat
1865
1959
  last = aargs.last
1960
+ # XXX: The types contained in ActualArguments are expected to be all local types.
1961
+ # This "globalize_type" breaks the invariant, and violates the assertion of Union#globalize that asserts @elems be nil.
1962
+ # To fix this issue fundamentally, ActualArguments should keep all arguments as-is (as like the VM does),
1963
+ # and globalize some types on the on-demand bases.
1866
1964
  ty = globalize_type(last, env, ep)
1867
1965
  case ty
1868
1966
  when Type::Hash
@@ -1906,7 +2004,7 @@ module TypeProf
1906
2004
  nctx = Context.new(blk_iseq, ep.ctx.cref, ep.ctx.mid)
1907
2005
  nep = ExecutionPoint.new(nctx, 0, ep)
1908
2006
  nlocals = [Type.any] * blk_iseq.locals.size
1909
- nsenv = StaticEnv.new(env.static_env.recv_ty, Type.any, env.static_env.mod_func)
2007
+ nsenv = StaticEnv.new(env.static_env.recv_ty, Type.any, env.static_env.mod_func, env.static_env.pub_meth)
1910
2008
  nenv = Env.new(nsenv, nlocals, [], nil)
1911
2009
  pend_block_dummy_execution(blk_ty, blk_iseq, nep, nenv)
1912
2010
  merge_return_env(ep) {|tenv| tenv ? tenv.merge(env) : env }
@@ -1916,20 +2014,31 @@ module TypeProf
1916
2014
  end
1917
2015
 
1918
2016
  def do_send(recv, mid, aargs, ep, env, &ctn)
1919
- meths = recv.get_method(mid, self)
1920
- if meths
1921
- meths.each do |meth|
1922
- meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
1923
- end
2017
+ case recv
2018
+ when Type::Void
2019
+ error(ep, "void's method is called: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2020
+ ctn[Type.any, ep, env]
2021
+ when Type::Any
2022
+ ctn[Type.any, ep, env]
1924
2023
  else
1925
- case recv
1926
- when Type::Void
1927
- error(ep, "void's method is called: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
1928
- when Type::Any
2024
+ klass, singleton = recv.method_dispatch_info
2025
+ meths = get_method(klass, singleton, mid) if klass
2026
+ if meths
2027
+ meths.each do |meth|
2028
+ meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
2029
+ end
1929
2030
  else
1930
- error(ep, "undefined method: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2031
+ meths = get_method(klass, singleton, :method_missing) if klass
2032
+ if meths
2033
+ aargs = aargs.for_method_missing(Type::Symbol.new(mid, Type::Instance.new(Type::Builtin[:sym])))
2034
+ meths.each do |meth|
2035
+ meth.do_send(recv, :method_missing, aargs, ep, env, self, &ctn)
2036
+ end
2037
+ else
2038
+ error(ep, "undefined method: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2039
+ ctn[Type.any, ep, env]
2040
+ end
1931
2041
  end
1932
- ctn[Type.any, ep, env]
1933
2042
  end
1934
2043
  end
1935
2044
 
@@ -1944,6 +2053,34 @@ module TypeProf
1944
2053
  end
1945
2054
  end
1946
2055
 
2056
+ def do_define_iseq_method(ep, env, mid, iseq, outer_ep)
2057
+ cref = ep.ctx.cref
2058
+ if cref.klass.is_a?(Type::Class)
2059
+ typed_mdef = check_typed_method(cref.klass, mid, ep.ctx.cref.singleton)
2060
+ recv = cref.klass
2061
+ recv = Type::Instance.new(recv) unless ep.ctx.cref.singleton
2062
+ if typed_mdef
2063
+ mdef = ISeqMethodDef.new(iseq, cref, outer_ep, env.static_env.pub_meth)
2064
+ typed_mdef.each do |typed_mdef|
2065
+ typed_mdef.do_match_iseq_mdef(mdef, recv, mid, env, ep, self)
2066
+ end
2067
+ else
2068
+ if ep.ctx.cref.singleton
2069
+ meth = add_singleton_iseq_method(cref.klass, mid, iseq, cref, outer_ep, true)
2070
+ else
2071
+ meth = add_iseq_method(cref.klass, mid, iseq, cref, outer_ep, env.static_env.pub_meth)
2072
+ if env.static_env.mod_func
2073
+ add_singleton_iseq_method(cref.klass, mid, iseq, cref, outer_ep, true)
2074
+ end
2075
+ end
2076
+ end
2077
+
2078
+ pend_method_execution(iseq, meth, recv, mid, ep.ctx.cref, outer_ep)
2079
+ else
2080
+ # XXX: what to do?
2081
+ end
2082
+ end
2083
+
1947
2084
  def show_block_signature(blks)
1948
2085
  bsig = nil
1949
2086
  ret_ty = Type.bot
@@ -1984,7 +2121,7 @@ module TypeProf
1984
2121
  next unless @block_to_ctx[blk.block_body] # this occurs when screen_name is called before type-profiling finished (e.g., error message)
1985
2122
  @block_to_ctx[blk.block_body].each do |blk_ctx|
1986
2123
  if farg_tys
1987
- farg_tys = farg_tys.merge(@method_signatures[blk_ctx])
2124
+ farg_tys = farg_tys.merge_as_block_arguments(@method_signatures[blk_ctx])
1988
2125
  else
1989
2126
  farg_tys = @method_signatures[blk_ctx]
1990
2127
  end