typeprof 0.5.4 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -7,60 +7,59 @@ module TypeProf
7
7
  def parse(argv)
8
8
  opt = OptionParser.new
9
9
 
10
+ opt.banner = "Usage: #{ opt.program_name } [options] files..."
11
+
10
12
  output = nil
11
13
 
12
14
  # Verbose level:
13
- # * 0: no output
14
- # * 1: show indicator
15
- # * 2: debug print
15
+ # * 0: none
16
+ # * 1: default level
17
+ # * 2: debugging level
16
18
  verbose = 1
17
19
 
18
20
  options = {}
19
21
  dir_filter = nil
20
22
  gem_rbs_features = []
21
- version = false
23
+ show_version = false
22
24
  max_sec = max_iter = nil
23
25
 
24
- opt.on("-o OUTFILE") {|v| output = v }
25
- opt.on("-q", "--quiet") { verbose = 0 }
26
- opt.on("-v", "--verbose") { options[:show_errors] = true }
27
- opt.on("--version") { version = true }
28
- opt.on("-d", "--debug") { verbose = 2 }
29
- opt.on("-I DIR") {|v| $LOAD_PATH << v }
30
- opt.on("-r FEATURE") {|v| gem_rbs_features << v }
31
- opt.on("--max-second SECOND", Float) {|v| max_sec = v }
32
- opt.on("--max-iteration TIMES", Integer) {|v| max_iter = v }
26
+ opt.separator ""
27
+ opt.separator "Options:"
28
+ opt.on("-o OUTFILE", "Output to OUTFILE instead of stdout") {|v| output = v }
29
+ opt.on("-q", "--quiet", "Do not display progress indicator") { options[:show_indicator] = false }
30
+ opt.on("-v", "--verbose", "Alias to --show-errors") { options[:show_errors] = true }
31
+ opt.on("--version", "Display typeprof version") { show_version = true }
32
+ opt.on("-I DIR", "Add DIR to the load/require path") {|v| $LOAD_PATH << v }
33
+ opt.on("-r FEATURE", "Require RBS of the FEATURE gem") {|v| gem_rbs_features << v }
33
34
 
34
- opt.on("--include-dir DIR") do |dir|
35
+ opt.separator ""
36
+ opt.separator "Analysis output options:"
37
+ opt.on("--include-dir DIR", "Include the analysis result of .rb file in DIR") do |dir|
35
38
  # When `--include-dir` option is specified as the first directory option,
36
39
  # typeprof will exclude any files by default unless a file path matches the explicit option
37
40
  dir_filter ||= [[:exclude]]
38
41
  dir_filter << [:include, File.expand_path(dir)]
39
42
  end
40
- opt.on("--exclude-dir DIR") do |dir|
43
+ opt.on("--exclude-dir DIR", "Exclude the analysis result of .rb file in DIR") do |dir|
41
44
  # When `--exclude-dir` option is specified as the first directory option,
42
45
  # typeprof will include any files by default, except Ruby's install directory and Gem directories
43
46
  dir_filter ||= ConfigData::DEFAULT_DIR_FILTER
44
47
  dir_filter << [:exclude, File.expand_path(dir)]
45
48
  end
49
+ opt.on("--[no-]show-errors", "Display possible errors found during the analysis") {|v| options[:show_errors] = v }
50
+ opt.on("--[no-]show-untyped", "Display \"Foo | untyped\" instead of \"Foo\"") {|v| options[:show_untyped] = v }
46
51
 
47
- opt.on("-f OPTION") do |v|
48
- key, args = v.split("=", 2)
49
- case key
50
- when "type-depth-limit"
51
- options[:type_depth_limit] = Integer(args)
52
- when "pedantic-output"
53
- options[:pedantic_output] = true
54
- when "show-errors"
55
- options[:show_errors] = true
56
- when "show-container-raw-elements"
57
- options[:show_container_raw_elements] = true
58
- when "stackprof"
59
- options[:stackprof] = args ? args.to_sym : :cpu
60
- else
61
- raise OptionParser::InvalidOption.new("unknown option: #{ key }")
62
- end
63
- end
52
+ opt.separator ""
53
+ opt.separator "Analysis limit options:"
54
+ opt.on("--max-second SECOND", Float, "Limit the maxium time of analysis (in second)") {|v| max_sec = v }
55
+ opt.on("--max-iteration TIMES", Integer, "Limit the maxium instruction count of analysis") {|v| max_iter = v }
56
+
57
+ opt.separator ""
58
+ opt.separator "Advanced options:"
59
+ opt.on("--[no-]stub-execution", "Force to call all unreachable methods with \"untyped\" arguments") {|v| options[:stub_execution] = v }
60
+ opt.on("--type-depth-limit DEPTH", Integer, "Limit the maximum depth of nested types") {|v| options[:type_depth_limit] = v }
61
+ opt.on("--debug", "Display analysis log (for debugging purpose)") { verbose = 2 }
62
+ opt.on("--[no-]stackprof MODE", /\Acpu|wall|object\z/, "Enable stackprof (for debugging purpose)") {|v| options[:stackprof] = v.to_sym }
64
63
 
65
64
  opt.parse!(argv)
66
65
 
@@ -75,9 +74,9 @@ module TypeProf
75
74
  end
76
75
  end
77
76
 
78
- puts "typeprof #{ VERSION }" if version
77
+ puts "typeprof #{ VERSION }" if show_version
79
78
  if rb_files.empty?
80
- exit if version
79
+ exit if show_version
81
80
  raise OptionParser::InvalidOption.new("no input files")
82
81
  end
83
82
 
@@ -22,9 +22,11 @@ module TypeProf
22
22
  opt[:verbose] ||= 0
23
23
  opt[:options] ||= {}
24
24
  opt[:options] = {
25
- type_depth_limit: 5,
26
- pedantic_output: false,
25
+ show_indicator: true,
26
+ show_untyped: false,
27
27
  show_errors: false,
28
+ stub_execution: true,
29
+ type_depth_limit: 5,
28
30
  stackprof: nil,
29
31
  }.merge(opt[:options])
30
32
  super(**opt)
@@ -67,7 +69,7 @@ module TypeProf
67
69
 
68
70
  prologue_ctx = Context.new(nil, nil, nil)
69
71
  prologue_ep = ExecutionPoint.new(prologue_ctx, -1, nil)
70
- prologue_env = Env.new(StaticEnv.new(:top, Type.nil, false), [], [], Utils::HashWrapper.new({}))
72
+ prologue_env = Env.new(StaticEnv.new(:top, Type.nil, false, true), [], [], Utils::HashWrapper.new({}))
71
73
 
72
74
  Config.rb_files.each do |rb|
73
75
  if rb.is_a?(Array) # [String name, String content]
@@ -111,7 +113,7 @@ module TypeProf
111
113
  ctx = Context.new(iseq, cref, nil)
112
114
  ep = ExecutionPoint.new(ctx, 0, nil)
113
115
  locals = [Type.nil] * iseq.locals.size
114
- env = Env.new(StaticEnv.new(recv, Type.nil, false), locals, [], Utils::HashWrapper.new({}))
116
+ env = Env.new(StaticEnv.new(recv, Type.nil, false, false), locals, [], Utils::HashWrapper.new({}))
115
117
 
116
118
  return ep, env
117
119
  end
@@ -77,7 +77,9 @@ module TypeProf
77
77
  return env, Type.any if depth <= 0
78
78
  alloc_site = alloc_site.add_id(:cell).add_id(@base_type)
79
79
  env, elems = @elems.localize(env, alloc_site, depth)
80
- env.deploy_type(LocalCell, alloc_site, elems, @base_type)
80
+ ty = Local.new(Cell, alloc_site, @base_type)
81
+ env = env.deploy_type(alloc_site, elems)
82
+ return env, ty
81
83
  end
82
84
 
83
85
  def limit_size(limit)
@@ -85,7 +87,7 @@ module TypeProf
85
87
  Cell.new(@elems.limit_size(limit - 1), @base_type)
86
88
  end
87
89
 
88
- def get_method(mid, scratch)
90
+ def method_dispatch_info
89
91
  raise
90
92
  end
91
93
 
@@ -95,6 +97,19 @@ module TypeProf
95
97
  Cell.new(elems, @base_type)
96
98
  end
97
99
 
100
+ def generate_substitution
101
+ subst = {}
102
+ tyvars = @base_type.klass.type_params.map {|name,| Type::Var.new(name) }
103
+ tyvars.zip(@elems.elems) do |tyvar, elem|
104
+ if subst[tyvar]
105
+ subst[tyvar] = subst[tyvar].union(elem)
106
+ else
107
+ subst[tyvar] = elem
108
+ end
109
+ end
110
+ subst
111
+ end
112
+
98
113
  class Elements # Cell
99
114
  include Utils::StructuralEquality
100
115
 
@@ -102,10 +117,14 @@ module TypeProf
102
117
  @elems = elems
103
118
  end
104
119
 
120
+ def self.dummy_elements
121
+ Elements.new([]) # XXX
122
+ end
123
+
105
124
  attr_reader :elems
106
125
 
107
126
  def to_local_type(id, base_ty)
108
- Type::LocalCell.new(id, base_ty)
127
+ Type::Local.new(Cell, id, base_ty)
109
128
  end
110
129
 
111
130
  def globalize(env, visited, depth)
@@ -180,45 +199,6 @@ module TypeProf
180
199
  end
181
200
  end
182
201
 
183
- class LocalCell < ContainerType
184
- def initialize(id, base_type)
185
- @id = id
186
- raise unless base_type
187
- @base_type = base_type
188
- end
189
-
190
- attr_reader :id, :base_type
191
-
192
- def inspect
193
- "Type::LocalCell[#{ @id }, base_type: #{ @base_type.inspect }]"
194
- end
195
-
196
- def screen_name(scratch)
197
- #raise "LocalArray must not be included in signature"
198
- "LocalCell!"
199
- end
200
-
201
- def globalize(env, visited, depth)
202
- if visited[self] || depth <= 0
203
- Type.any
204
- else
205
- visited[self] = true
206
- elems = env.get_container_elem_types(@id)
207
- if elems
208
- elems = elems.globalize(env, visited, depth - 1)
209
- else
210
- elems = Cell::Elements.new([]) # XXX
211
- end
212
- visited.delete(self)
213
- Cell.new(elems, @base_type)
214
- end
215
- end
216
-
217
- def get_method(mid, scratch)
218
- @base_type.get_method(mid, scratch)
219
- end
220
- end
221
-
222
202
  # Do not insert Array type to local environment, stack, etc.
223
203
  class Array < ContainerType
224
204
  def initialize(elems, base_type)
@@ -247,7 +227,9 @@ module TypeProf
247
227
  return env, Type.any if depth <= 0
248
228
  alloc_site = alloc_site.add_id(:ary).add_id(@base_type)
249
229
  env, elems = @elems.localize(env, alloc_site, depth - 1)
250
- env.deploy_type(LocalArray, alloc_site, elems, @base_type)
230
+ ty = Local.new(Array, alloc_site, @base_type)
231
+ env = env.deploy_type(alloc_site, elems)
232
+ return env, ty
251
233
  end
252
234
 
253
235
  def limit_size(limit)
@@ -255,7 +237,7 @@ module TypeProf
255
237
  Array.new(@elems.limit_size(limit - 1), @base_type)
256
238
  end
257
239
 
258
- def get_method(mid, scratch)
240
+ def method_dispatch_info
259
241
  raise
260
242
  end
261
243
 
@@ -265,6 +247,10 @@ module TypeProf
265
247
  Array.new(elems, @base_type)
266
248
  end
267
249
 
250
+ def generate_substitution
251
+ { Type::Var.new(:Elem) => @elems.squash }
252
+ end
253
+
268
254
  class Elements # Array
269
255
  include Utils::StructuralEquality
270
256
 
@@ -274,10 +260,14 @@ module TypeProf
274
260
  @lead_tys, @rest_ty = lead_tys, rest_ty
275
261
  end
276
262
 
263
+ def self.dummy_elements
264
+ Elements.new([], Type.any)
265
+ end
266
+
277
267
  attr_reader :lead_tys, :rest_ty
278
268
 
279
269
  def to_local_type(id, base_ty)
280
- Type::LocalArray.new(id, base_ty)
270
+ Type::Local.new(Array, id, base_ty)
281
271
  end
282
272
 
283
273
  def globalize(env, visited, depth)
@@ -305,7 +295,7 @@ module TypeProf
305
295
  end
306
296
 
307
297
  def screen_name(scratch)
308
- if Config.options[:show_container_raw_elements] || @rest_ty == Type.bot
298
+ if @rest_ty == Type.bot
309
299
  if @lead_tys.empty?
310
300
  return "Array[bot]" # RBS does not allow an empty tuple "[]"
311
301
  end
@@ -363,7 +353,57 @@ module TypeProf
363
353
  end
364
354
 
365
355
  def [](idx)
366
- if idx >= 0
356
+ if idx.is_a?(Range)
357
+ if @rest_ty == Type.bot
358
+ lead_tys = @lead_tys[idx]
359
+ if lead_tys
360
+ rest_ty = Type.bot
361
+ else
362
+ return Type.nil
363
+ end
364
+ else
365
+ b, e = idx.begin, idx.end
366
+ b = 0 if !b
367
+ if !e
368
+ lead_tys = @lead_tys[idx] || []
369
+ rest_ty = @rest_ty
370
+ elsif b >= 0
371
+ if e >= 0
372
+ if b <= e
373
+ if e < @lead_tys.size
374
+ lead_tys = @lead_tys[idx]
375
+ rest_ty = Type.bot
376
+ else
377
+ lead_tys = @lead_tys[idx] || []
378
+ rest_ty = @rest_ty
379
+ end
380
+ else
381
+ return Type.nil
382
+ end
383
+ else
384
+ lead_tys = @lead_tys[idx] || []
385
+ e = idx.exclude_end? ? e : e == -1 ? @lead_tys.size : e + 1
386
+ rest_ty = (@lead_tys[e + 1..] || []).inject(@rest_ty) {|ty0, ty1| ty0.union(ty1) }
387
+ end
388
+ else
389
+ lead_tys = []
390
+ if e >= 0
391
+ rest_ty = e < @lead_tys.size ? Type.bot : @rest_ty
392
+ range = [0, @lead_tys.size + b].max .. (idx.exclude_end? ? e - 1 : e)
393
+ rest_ty = @lead_tys[range].inject(rest_ty) {|ty0, ty1| ty0.union(ty1) }
394
+ else
395
+ if b <= e
396
+ range = [0, @lead_tys.size + b].max .. (idx.exclude_end? ? e - 1 : e)
397
+ rest_ty = @lead_tys[range].inject(@rest_ty) {|ty0, ty1| ty0.union(ty1) }
398
+ else
399
+ return Type.nil
400
+ end
401
+ end
402
+ end
403
+ end
404
+ base_ty = Type::Instance.new(Type::Builtin[:ary])
405
+ Array.new(Elements.new(lead_tys, rest_ty), base_ty)
406
+ elsif idx >= 0
367
407
  if idx < @lead_tys.size
368
408
  @lead_tys[idx]
369
409
  elsif @rest_ty == Type.bot
@@ -494,48 +534,6 @@ module TypeProf
494
534
  end
495
535
  end
496
536
 
497
- # Do not insert Array type to local environment, stack, etc.
498
- class LocalArray < ContainerType
499
- def initialize(id, base_type)
500
- @id = id
501
- raise unless base_type
502
- @base_type = base_type
503
- end
504
-
505
- attr_reader :id, :base_type
506
-
507
- def inspect
508
- "Type::LocalArray[#{ @id }, base_type: #{ @base_type.inspect }]"
509
- end
510
-
511
- def screen_name(scratch)
512
- #raise "LocalArray must not be included in signature"
513
- "LocalArray!"
514
- end
515
-
516
- def globalize(env, visited, depth)
517
- if visited[self] || depth <= 0
518
- Type.any
519
- else
520
- visited[self] = true
521
- elems = env.get_container_elem_types(@id)
522
- if elems
523
- elems = elems.globalize(env, visited, depth - 1)
524
- else
525
- # TODO: currently out-of-scope array cannot be accessed
526
- elems = Array::Elements.new([], Type.any)
527
- end
528
- visited.delete(self)
529
- Array.new(elems, @base_type)
530
- end
531
- end
532
-
533
- def get_method(mid, scratch)
534
- @base_type.get_method(mid, scratch)
535
- end
536
- end
537
-
538
-
539
537
  class Hash < ContainerType
540
538
  def initialize(elems, base_type)
541
539
  @elems = elems
@@ -557,7 +555,9 @@ module TypeProf
557
555
  return env, Type.any if depth <= 0
558
556
  alloc_site = alloc_site.add_id(:hash).add_id(@base_type)
559
557
  env, elems = @elems.localize(env, alloc_site, depth - 1)
560
- env.deploy_type(LocalHash, alloc_site, elems, @base_type)
558
+ ty = Local.new(Hash, alloc_site, @base_type)
559
+ env = env.deploy_type(alloc_site, elems)
560
+ return env, ty
561
561
  end
562
562
 
563
563
  def limit_size(limit)
@@ -565,7 +565,7 @@ module TypeProf
565
565
  Hash.new(@elems.limit_size(limit - 1), @base_type)
566
566
  end
567
567
 
568
- def get_method(mid, scratch)
568
+ def method_dispatch_info
569
569
  raise
570
570
  end
571
571
 
@@ -575,6 +575,14 @@ module TypeProf
575
575
  Hash.new(elems, @base_type)
576
576
  end
577
577
 
578
+ def generate_substitution
579
+ tyvar_k = Type::Var.new(:K)
580
+ tyvar_v = Type::Var.new(:V)
581
+ k_ty0, v_ty0 = @elems.squash
582
+ # XXX: need to heuristically replace ret type Hash[K, V] with self, instead of conversative type?
583
+ { tyvar_k => k_ty0, tyvar_v => v_ty0 }
584
+ end
585
+
578
586
  class Elements # Hash
579
587
  include Utils::StructuralEquality
580
588
 
@@ -583,18 +591,21 @@ module TypeProf
583
591
  raise unless k_ty.is_a?(Type)
584
592
  raise unless v_ty.is_a?(Type)
585
593
  raise if k_ty.is_a?(Type::Union)
586
- raise if k_ty.is_a?(Type::LocalArray)
587
- raise if k_ty.is_a?(Type::LocalHash)
594
+ raise if k_ty.is_a?(Type::Local)
588
595
  raise if k_ty.is_a?(Type::Array)
589
596
  raise if k_ty.is_a?(Type::Hash)
590
597
  end
591
598
  @map_tys = map_tys
592
599
  end
593
600
 
601
+ def self.dummy_elements
602
+ Elements.new({Type.any => Type.any})
603
+ end
604
+
594
605
  attr_reader :map_tys
595
606
 
596
607
  def to_local_type(id, base_ty)
597
- Type::LocalHash.new(id, base_ty)
608
+ Type::Local.new(Hash, id, base_ty)
598
609
  end
599
610
 
600
611
  def globalize(env, visited, depth)
@@ -782,21 +793,24 @@ module TypeProf
782
793
  end
783
794
  end
784
795
 
785
- class LocalHash < ContainerType
786
- def initialize(id, base_type)
796
+ class Local < ContainerType
797
+ def initialize(kind, id, base_type)
798
+ @kind = kind
799
+ raise if @kind != Cell && @kind != Array && @kind != Hash
787
800
  @id = id
801
+ raise unless base_type
788
802
  @base_type = base_type
789
803
  end
790
804
 
791
- attr_reader :id, :base_type
805
+ attr_reader :kind, :id, :base_type
792
806
 
793
807
  def inspect
794
- "Type::LocalHash[#{ @id }]"
808
+ "Type::Local[#{ @kind }, #{ @id }, base_type: #{ @base_type.inspect }]"
795
809
  end
796
810
 
797
811
  def screen_name(scratch)
798
- #raise "LocalHash must not be included in signature"
799
- "LocalHash!"
812
+ #raise "Local type must not be included in signature"
813
+ "Local[#{ @kind }]"
800
814
  end
801
815
 
802
816
  def globalize(env, visited, depth)
@@ -808,15 +822,56 @@ module TypeProf
808
822
  if elems
809
823
  elems = elems.globalize(env, visited, depth - 1)
810
824
  else
811
- elems = Hash::Elements.new({Type.any => Type.any})
825
+ # TODO: currently out-of-scope array cannot be accessed
826
+ elems = @kind::Elements.dummy_elements
812
827
  end
813
828
  visited.delete(self)
814
- Hash.new(elems, @base_type)
829
+ @kind.new(elems, @base_type)
815
830
  end
816
831
  end
817
832
 
818
- def get_method(mid, scratch)
819
- @base_type.get_method(mid, scratch)
833
+ def method_dispatch_info
834
+ @base_type.method_dispatch_info
835
+ end
836
+
837
+ def update_container_elem_type(subst, env, caller_ep, scratch)
838
+ case
839
+ when @kind == Cell
840
+ tyvars = @base_type.klass.type_params.map {|name,| Type::Var.new(name) }
841
+ # XXX: This should be skipped when the called methods belongs to superclass
842
+ tyvars.each_with_index do |tyvar, idx|
843
+ ty = subst[tyvar]
844
+ if ty
845
+ env, ty = scratch.localize_type(ty, env, caller_ep)
846
+ env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
847
+ elems.update(idx, ty)
848
+ end
849
+ end
850
+ end
851
+ when @kind == Array
852
+ tyvar_elem = Type::Var.new(:Elem)
853
+ if subst[tyvar_elem]
854
+ ty = subst[tyvar_elem]
855
+ env, ty = scratch.localize_type(ty, env, caller_ep)
856
+ env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
857
+ elems.update(nil, ty)
858
+ end
859
+ end
860
+ when @kind == Hash
861
+ tyvar_k = Type::Var.new(:K)
862
+ tyvar_v = Type::Var.new(:V)
863
+ if subst[tyvar_k] && subst[tyvar_v]
864
+ k_ty = subst[tyvar_k]
865
+ v_ty = subst[tyvar_v]
866
+ alloc_site = AllocationSite.new(caller_ep)
867
+ env, k_ty = scratch.localize_type(k_ty, env, caller_ep, alloc_site.add_id(:k))
868
+ env, v_ty = scratch.localize_type(v_ty, env, caller_ep, alloc_site.add_id(:v))
869
+ env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
870
+ elems.update(k_ty, v_ty)
871
+ end
872
+ end
873
+ end
874
+ env
820
875
  end
821
876
  end
822
877
  end