typeprof 0.2.0 → 0.5.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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +1 -2
  3. data/.gitignore +1 -0
  4. data/Gemfile +2 -2
  5. data/Gemfile.lock +10 -21
  6. data/LICENSE +21 -0
  7. data/README.md +6 -0
  8. data/doc/demo.md +398 -0
  9. data/doc/doc.ja.md +6 -1
  10. data/doc/doc.md +7 -2
  11. data/exe/typeprof +2 -1
  12. data/lib/typeprof.rb +9 -0
  13. data/lib/typeprof/analyzer.rb +427 -325
  14. data/lib/typeprof/arguments.rb +405 -0
  15. data/lib/typeprof/block.rb +136 -0
  16. data/lib/typeprof/builtin.rb +36 -25
  17. data/lib/typeprof/cli.rb +51 -98
  18. data/lib/typeprof/config.rb +114 -0
  19. data/lib/typeprof/container-type.rb +280 -92
  20. data/lib/typeprof/export.rb +197 -108
  21. data/lib/typeprof/import.rb +134 -80
  22. data/lib/typeprof/iseq.rb +42 -1
  23. data/lib/typeprof/method.rb +178 -82
  24. data/lib/typeprof/type.rb +228 -369
  25. data/lib/typeprof/utils.rb +4 -18
  26. data/lib/typeprof/version.rb +3 -0
  27. data/smoke/arguments2.rb +55 -0
  28. data/smoke/array-each3.rb +1 -4
  29. data/smoke/array12.rb +1 -1
  30. data/smoke/array6.rb +1 -0
  31. data/smoke/block-ambiguous.rb +36 -0
  32. data/smoke/block-args1-rest.rb +62 -0
  33. data/smoke/block-args1.rb +59 -0
  34. data/smoke/block-args2-rest.rb +62 -0
  35. data/smoke/block-args2.rb +59 -0
  36. data/smoke/block-args3-rest.rb +73 -0
  37. data/smoke/block-args3.rb +70 -0
  38. data/smoke/block-blockarg.rb +27 -0
  39. data/smoke/block-kwarg.rb +52 -0
  40. data/smoke/block10.rb +1 -1
  41. data/smoke/block11.rb +1 -1
  42. data/smoke/block14.rb +17 -0
  43. data/smoke/block4.rb +2 -2
  44. data/smoke/block5.rb +1 -0
  45. data/smoke/block6.rb +1 -1
  46. data/smoke/block7.rb +0 -2
  47. data/smoke/block8.rb +2 -2
  48. data/smoke/block9.rb +1 -1
  49. data/smoke/blown.rb +1 -1
  50. data/smoke/class-hierarchy.rb +54 -0
  51. data/smoke/class-hierarchy2.rb +27 -0
  52. data/smoke/constant1.rb +11 -6
  53. data/smoke/constant2.rb +2 -0
  54. data/smoke/cvar.rb +1 -0
  55. data/smoke/demo10.rb +1 -1
  56. data/smoke/demo8.rb +2 -2
  57. data/smoke/demo9.rb +1 -3
  58. data/smoke/flow7.rb +1 -7
  59. data/smoke/flow8.rb +13 -0
  60. data/smoke/hash-fetch.rb +3 -3
  61. data/smoke/hash-merge-bang.rb +11 -0
  62. data/smoke/hash1.rb +1 -1
  63. data/smoke/hash3.rb +1 -1
  64. data/smoke/hash4.rb +1 -1
  65. data/smoke/instance_eval.rb +1 -1
  66. data/smoke/int_times.rb +1 -1
  67. data/smoke/ivar2.rb +1 -1
  68. data/smoke/keyword3.rb +1 -2
  69. data/smoke/keyword4.rb +1 -1
  70. data/smoke/kwsplat1.rb +1 -1
  71. data/smoke/kwsplat2.rb +1 -1
  72. data/smoke/module4.rb +2 -0
  73. data/smoke/multiple-superclass.rb +4 -0
  74. data/smoke/next2.rb +1 -1
  75. data/smoke/optional1.rb +1 -1
  76. data/smoke/optional2.rb +1 -1
  77. data/smoke/optional3.rb +10 -0
  78. data/smoke/pattern-match1.rb +23 -0
  79. data/smoke/pattern-match2.rb +15 -0
  80. data/smoke/proc4.rb +1 -1
  81. data/smoke/rbs-extend.rb +9 -0
  82. data/smoke/rbs-extend.rbs +7 -0
  83. data/smoke/rbs-interface.rb +24 -0
  84. data/smoke/rbs-interface.rbs +12 -0
  85. data/smoke/rbs-proc1.rb +9 -0
  86. data/smoke/rbs-proc1.rbs +3 -0
  87. data/smoke/rbs-proc2.rb +20 -0
  88. data/smoke/rbs-proc2.rbs +3 -0
  89. data/smoke/rbs-proc3.rb +13 -0
  90. data/smoke/rbs-proc3.rbs +4 -0
  91. data/smoke/rbs-record.rb +17 -0
  92. data/smoke/rbs-record.rbs +4 -0
  93. data/smoke/rbs-tyvar.rb +18 -0
  94. data/smoke/rbs-tyvar.rbs +5 -0
  95. data/smoke/rbs-tyvar2.rb +20 -0
  96. data/smoke/rbs-tyvar2.rbs +9 -0
  97. data/smoke/rbs-tyvar3.rb +17 -0
  98. data/smoke/rbs-tyvar3.rbs +5 -0
  99. data/smoke/rbs-tyvar4.rb +36 -0
  100. data/smoke/rbs-tyvar5.rb +12 -0
  101. data/smoke/rbs-tyvar5.rbs +8 -0
  102. data/smoke/rest1.rb +1 -1
  103. data/smoke/rest2.rb +1 -1
  104. data/smoke/rest3.rb +1 -1
  105. data/smoke/rest5.rb +1 -1
  106. data/smoke/rest6.rb +1 -1
  107. data/smoke/retry1.rb +1 -1
  108. data/smoke/return.rb +1 -1
  109. data/smoke/singleton_method.rb +3 -0
  110. data/smoke/step.rb +1 -1
  111. data/smoke/struct.rb +4 -3
  112. data/smoke/struct3.rb +14 -0
  113. data/smoke/symbol-proc.rb +24 -0
  114. data/smoke/uninitialize-var.rb +12 -0
  115. data/smoke/user-demo.rb +15 -0
  116. data/smoke/wrong-extend.rb +1 -0
  117. data/typeprof.gemspec +4 -2
  118. metadata +53 -6
  119. data/run.sh +0 -3
  120. data/smoke/variadic1.rb.notyet +0 -5
@@ -25,6 +25,13 @@ module TypeProf
25
25
  ntrace
26
26
  end
27
27
 
28
+ def show_message(terminated, output)
29
+ if terminated
30
+ output.puts "# CAUTION: Type profiling was terminated prematurely because of the limitation"
31
+ output.puts
32
+ end
33
+ end
34
+
28
35
  def show_error(errors, backward_edge, output)
29
36
  return if errors.empty?
30
37
  return unless Config.options[:show_errors]
@@ -74,136 +81,148 @@ module TypeProf
74
81
  class RubySignatureExporter
75
82
  def initialize(
76
83
  scratch,
77
- class_defs, iseq_method_to_ctxs, sig_fargs, sig_ret, yields
84
+ class_defs, iseq_method_to_ctxs
78
85
  )
79
86
  @scratch = scratch
80
87
  @class_defs = class_defs
81
88
  @iseq_method_to_ctxs = iseq_method_to_ctxs
82
- @sig_fargs = sig_fargs
83
- @sig_ret = sig_ret
84
- @yields = yields
85
89
  end
86
90
 
87
- def show(stat_eps, output)
88
- output.puts "# Classes" # and Modules
91
+ def conv_class(namespace, class_def, inner_classes)
92
+ @scratch.namespace = namespace
89
93
 
90
- stat_classes = {}
91
- stat_methods = {}
92
- first = true
94
+ if class_def.superclass
95
+ omit = @class_defs[class_def.superclass].klass_obj == Type::Builtin[:obj] || class_def.klass_obj == Type::Builtin[:obj]
96
+ superclass = omit ? nil : @scratch.get_class_name(@class_defs[class_def.superclass].klass_obj)
97
+ end
93
98
 
94
- @class_defs.each_value do |class_def|
95
- included_mods = class_def.modules[false].filter_map do |mod_def, absolute_paths|
96
- next if absolute_paths.all? {|path| !path || Config.check_dir_filter(path) == :exclude }
97
- mod_def.name
98
- end
99
+ @scratch.namespace = class_def.name
99
100
 
100
- explicit_methods = {}
101
- iseq_methods = {}
102
- attr_methods = {}
103
- ivars = class_def.ivars.dump
104
- cvars = class_def.cvars.dump
105
- class_def.methods.each do |(singleton, mid), mdefs|
106
- mdefs.each do |mdef|
107
- case mdef
108
- when ISeqMethodDef
109
- ctxs = @iseq_method_to_ctxs[mdef]
110
- next unless ctxs
111
-
112
- ctxs.each do |ctx|
113
- next if mid != ctx.mid
114
- next if Config.check_dir_filter(ctx.iseq.absolute_path) == :exclude
115
-
116
- method_name = ctx.mid
117
- method_name = "self.#{ method_name }" if singleton
118
-
119
- fargs = @sig_fargs[ctx]
120
- ret_tys = @sig_ret[ctx]
121
-
122
- iseq_methods[method_name] ||= []
123
- iseq_methods[method_name] << @scratch.show_signature(fargs, @yields[ctx], ret_tys)
124
- end
125
- when AttrMethodDef
126
- next if Config.check_dir_filter(mdef.absolute_path) == :exclude
127
- mid = mid.to_s[0..-2].to_sym if mid.to_s.end_with?("=")
128
- method_name = mid
129
- method_name = "self.#{ mid }" if singleton
130
- method_name = [method_name, :"@#{ mid }" != mdef.ivar]
131
- if attr_methods[method_name]
132
- if attr_methods[method_name][0] != mdef.kind
133
- attr_methods[method_name][0] = :accessor
134
- end
135
- else
136
- entry = ivars[[singleton, mdef.ivar]]
137
- ty = entry ? entry.type : Type.any
138
- attr_methods[method_name] = [mdef.kind, ty.screen_name(@scratch)]
139
- end
140
- when TypedMethodDef
141
- if mdef.rbs_source
142
- method_name, sigs = mdef.rbs_source
143
- explicit_methods[method_name] = sigs
101
+ consts = {}
102
+ class_def.consts.each do |name, (ty, absolute_path)|
103
+ next if ty.is_a?(Type::Class)
104
+ next if !absolute_path || Config.check_dir_filter(absolute_path) == :exclude
105
+ consts[name] = ty.screen_name(@scratch)
106
+ end
107
+
108
+ included_mods = class_def.modules[false].filter_map do |mod_def, absolute_paths|
109
+ next if absolute_paths.all? {|path| !path || Config.check_dir_filter(path) == :exclude }
110
+ Type::Instance.new(mod_def.klass_obj).screen_name(@scratch)
111
+ end
112
+
113
+ extended_mods = class_def.modules[true].filter_map do |mod_def, absolute_paths|
114
+ next if absolute_paths.all? {|path| !path || Config.check_dir_filter(path) == :exclude }
115
+ Type::Instance.new(mod_def.klass_obj).screen_name(@scratch)
116
+ end
117
+
118
+ explicit_methods = {}
119
+ iseq_methods = {}
120
+ attr_methods = {}
121
+ ivars = class_def.ivars.dump
122
+ cvars = class_def.cvars.dump
123
+
124
+ class_def.methods.each do |(singleton, mid), mdefs|
125
+ mdefs.each do |mdef|
126
+ case mdef
127
+ when ISeqMethodDef
128
+ ctxs = @iseq_method_to_ctxs[mdef]
129
+ next unless ctxs
130
+
131
+ ctxs.each do |ctx|
132
+ next if mid != ctx.mid
133
+ next if Config.check_dir_filter(ctx.iseq.absolute_path) == :exclude
134
+
135
+ method_name = ctx.mid
136
+ method_name = "self.#{ method_name }" if singleton
137
+
138
+ iseq_methods[method_name] ||= []
139
+ iseq_methods[method_name] << @scratch.show_method_signature(ctx)
140
+ end
141
+ when AttrMethodDef
142
+ next if Config.check_dir_filter(mdef.absolute_path) == :exclude
143
+ mid = mid.to_s[0..-2].to_sym if mid.to_s.end_with?("=")
144
+ method_name = mid
145
+ method_name = "self.#{ mid }" if singleton
146
+ method_name = [method_name, :"@#{ mid }" != mdef.ivar]
147
+ if attr_methods[method_name]
148
+ if attr_methods[method_name][0] != mdef.kind
149
+ attr_methods[method_name][0] = :accessor
144
150
  end
151
+ else
152
+ entry = ivars[[singleton, mdef.ivar]]
153
+ ty = entry ? entry.type : Type.any
154
+ attr_methods[method_name] = [mdef.kind, ty.screen_name(@scratch)]
155
+ end
156
+ when TypedMethodDef
157
+ if mdef.rbs_source
158
+ method_name, sigs = mdef.rbs_source
159
+ explicit_methods[method_name] = sigs
145
160
  end
146
161
  end
147
162
  end
163
+ end
148
164
 
149
- ivars = ivars.map do |(singleton, var), entry|
150
- next if entry.absolute_paths.all? {|path| Config.check_dir_filter(path) == :exclude }
151
- ty = entry.type
152
- next unless var.to_s.start_with?("@")
153
- var = "self.#{ var }" if singleton
154
- next if attr_methods[[singleton ? "self.#{ var.to_s[1..] }" : var.to_s[1..].to_sym, false]]
155
- [var, ty.screen_name(@scratch), entry.rbs_declared]
156
- end.compact
157
-
158
- cvars = cvars.map do |var, entry|
159
- next if entry.absolute_paths.all? {|path| Config.check_dir_filter(path) == :exclude }
160
- [var, entry.type.screen_name(@scratch), entry.rbs_declared]
161
- end
165
+ ivars = ivars.map do |(singleton, var), entry|
166
+ next if entry.absolute_paths.all? {|path| Config.check_dir_filter(path) == :exclude }
167
+ ty = entry.type
168
+ next unless var.to_s.start_with?("@")
169
+ var = "self.#{ var }" if singleton
170
+ next if attr_methods[[singleton ? "self.#{ var.to_s[1..] }" : var.to_s[1..].to_sym, false]]
171
+ [var, ty.screen_name(@scratch), entry.rbs_declared]
172
+ end.compact
162
173
 
163
- if !class_def.absolute_path || Config.check_dir_filter(class_def.absolute_path) == :exclude
164
- next if included_mods.empty? && ivars.empty? && cvars.empty? && iseq_methods.empty? && attr_methods.empty?
165
- end
174
+ cvars = cvars.map do |var, entry|
175
+ next if entry.absolute_paths.all? {|path| Config.check_dir_filter(path) == :exclude }
176
+ [var, entry.type.screen_name(@scratch), entry.rbs_declared]
177
+ end
166
178
 
167
- output.puts unless first
168
- first = false
179
+ if !class_def.absolute_path || Config.check_dir_filter(class_def.absolute_path) == :exclude
180
+ return nil if consts.empty? && included_mods.empty? && extended_mods.empty? && ivars.empty? && cvars.empty? && iseq_methods.empty? && attr_methods.empty? && inner_classes.empty?
181
+ end
169
182
 
170
- if class_def.superclass
171
- omit = @class_defs[class_def.superclass].klass_obj == Type::Builtin[:obj] || class_def.klass_obj == Type::Builtin[:obj]
172
- superclass = omit ? "" : " < #{ @class_defs[class_def.superclass].name }"
173
- end
183
+ @scratch.namespace = nil
174
184
 
175
- output.puts "#{ class_def.kind } #{ class_def.name }#{ superclass }"
176
- included_mods.sort.each do |ty|
177
- output.puts " include #{ ty }"
178
- end
179
- ivars.each do |var, ty, rbs_declared|
180
- s = rbs_declared ? "# " : " "
181
- output.puts s + "#{ var } : #{ ty }" unless var.start_with?("_")
182
- end
183
- cvars.each do |var, ty, rbs_declared|
184
- s = rbs_declared ? "# " : " "
185
- output.puts s + "#{ var } : #{ ty }"
186
- end
187
- attr_methods.each do |(method_name, hidden), (kind, ty)|
188
- output.puts " attr_#{ kind } #{ method_name }#{ hidden ? "()" : "" } : #{ ty }"
189
- end
190
- explicit_methods.each do |method_name, sigs|
191
- sigs = sigs.sort.join("\n" + "#" + " " * (method_name.size + 6) + "| ")
192
- output.puts "# def #{ method_name } : #{ sigs }"
193
- end
194
- iseq_methods.each do |method_name, sigs|
195
- sigs = sigs.sort.join("\n" + " " * (method_name.size + 7) + "| ")
196
- output.puts " def #{ method_name } : #{ sigs }"
185
+ ClassData.new(
186
+ kind: class_def.kind,
187
+ name: class_def.name,
188
+ superclass: superclass,
189
+ consts: consts,
190
+ included_mods: included_mods,
191
+ extended_mods: extended_mods,
192
+ ivars: ivars,
193
+ cvars: cvars,
194
+ attr_methods: attr_methods,
195
+ explicit_methods: explicit_methods,
196
+ iseq_methods: iseq_methods,
197
+ inner_classes: inner_classes,
198
+ )
199
+ end
200
+
201
+ ClassData = Struct.new(:kind, :name, :superclass, :consts, :included_mods, :extended_mods, :ivars, :cvars, :attr_methods, :explicit_methods, :iseq_methods, :inner_classes, keyword_init: true)
202
+
203
+ def show(stat_eps, output)
204
+ # make the class hierarchy
205
+ root = {}
206
+ @class_defs.each_value do |class_def|
207
+ h = root
208
+ class_def.name.each do |name|
209
+ h = h[name] ||= {}
197
210
  end
198
- output.puts "end"
211
+ h[:class_def] = class_def
199
212
  end
200
213
 
214
+ hierarchy = build_class_hierarchy([], root)
215
+
216
+ output.puts "# Classes" # and Modules
217
+
218
+ show_class_hierarchy(0, hierarchy, output, true)
219
+
201
220
  if ENV["TP_STAT"]
202
- output.puts "statistics:"
203
- output.puts " %d execution points" % stat_eps.size
204
- output.puts " %d classes" % stat_classes.size
205
- output.puts " %d methods (in total)" % stat_methods.size
221
+ output.puts ""
222
+ output.puts "# TypeProf statistics:"
223
+ output.puts "# %d execution points" % stat_eps.size
206
224
  end
225
+
207
226
  if ENV["TP_COVERAGE"]
208
227
  coverage = {}
209
228
  stat_eps.each do |ep|
@@ -212,8 +231,78 @@ module TypeProf
212
231
  (coverage[path] ||= [])[lineno] ||= 0
213
232
  (coverage[path] ||= [])[lineno] += 1
214
233
  end
215
- File.binwrite("coverage.dump", Marshal.dump(coverage))
234
+ File.binwrite("typeprof-analysis-coverage.dump", Marshal.dump(coverage))
235
+ end
236
+ end
237
+
238
+ def build_class_hierarchy(namespace, hierarchy)
239
+ hierarchy.map do |name, h|
240
+ class_def = h.delete(:class_def)
241
+ class_data = conv_class(namespace, class_def, build_class_hierarchy(namespace + [name], h))
242
+ class_data
243
+ end.compact
244
+ end
245
+
246
+ def show_class_hierarchy(depth, hierarchy, output, first)
247
+ hierarchy.each do |class_data|
248
+ output.puts unless first
249
+ first = false
250
+
251
+ show_class_data(depth, class_data, output)
252
+ end
253
+ end
254
+
255
+ def show_const(namespace, path)
256
+ return path.last.to_s if namespace == path
257
+ i = 0
258
+ i += 1 while namespace[i] && namespace[i] == path[i]
259
+ path[i..].join("::")
260
+ end
261
+
262
+ def show_class_data(depth, class_data, output)
263
+ indent = " " * depth
264
+ name = class_data.name.last
265
+ superclass = " < " + class_data.superclass if class_data.superclass
266
+ output.puts indent + "#{ class_data.kind } #{ name }#{ superclass }"
267
+ first = true
268
+ class_data.consts.each do |name, ty|
269
+ output.puts indent + " #{ name } : #{ ty }"
270
+ first = false
271
+ end
272
+ class_data.included_mods.sort.each do |mod|
273
+ output.puts indent + " include #{ mod }"
274
+ first = false
275
+ end
276
+ class_data.extended_mods.sort.each do |mod|
277
+ output.puts indent + " extend #{ mod }"
278
+ first = false
279
+ end
280
+ class_data.ivars.each do |var, ty, rbs_declared|
281
+ s = rbs_declared ? "# " : " "
282
+ output.puts indent + s + "#{ var } : #{ ty }" unless var.start_with?("_")
283
+ first = false
284
+ end
285
+ class_data.cvars.each do |var, ty, rbs_declared|
286
+ s = rbs_declared ? "# " : " "
287
+ output.puts indent + s + "#{ var } : #{ ty }"
288
+ first = false
289
+ end
290
+ class_data.attr_methods.each do |(method_name, hidden), (kind, ty)|
291
+ output.puts indent + " attr_#{ kind } #{ method_name }#{ hidden ? "()" : "" } : #{ ty }"
292
+ first = false
293
+ end
294
+ class_data.explicit_methods.each do |method_name, sigs|
295
+ sigs = sigs.sort.join("\n" + indent + "#" + " " * (method_name.size + 6) + "| ")
296
+ output.puts indent + "# def #{ method_name } : #{ sigs }"
297
+ first = false
298
+ end
299
+ class_data.iseq_methods.each do |method_name, sigs|
300
+ sigs = sigs.sort.join("\n" + indent + " " * (method_name.size + 7) + "| ")
301
+ output.puts indent + " def #{ method_name } : #{ sigs }"
302
+ first = false
216
303
  end
304
+ show_class_hierarchy(depth + 1, class_data.inner_classes, output, first)
305
+ output.puts indent + "end"
217
306
  end
218
307
  end
219
308
  end
@@ -29,9 +29,10 @@ module TypeProf
29
29
  end
30
30
 
31
31
  def self.load_rbs(env, builtin: false, **opt)
32
- loader = RBS::EnvironmentLoader.new
33
- unless builtin
34
- loader.no_builtin!
32
+ if builtin
33
+ loader = RBS::EnvironmentLoader.new
34
+ else
35
+ loader = RBS::EnvironmentLoader.new(core_root: nil)
35
36
  loader.add(**opt)
36
37
  end
37
38
  new_decls = loader.load(env: env)
@@ -89,12 +90,13 @@ module TypeProf
89
90
  json = {}
90
91
 
91
92
  each_class_decl do |name, decls|
92
- super_class_name = get_super_class_name(name)
93
+ super_class_name = get_super_class_name(name, decls)
93
94
  klass = conv_type_name(name)
94
95
  superclass = super_class_name ? conv_type_name(super_class_name) : nil
95
96
 
96
97
  type_params = nil
97
98
  included_modules = []
99
+ extended_modules = []
98
100
  methods = {}
99
101
  ivars = {}
100
102
  cvars = {}
@@ -103,8 +105,6 @@ module TypeProf
103
105
  decls.each do |decl|
104
106
  decl = decl.decl
105
107
 
106
- raise NotImplementedError if decl.is_a?(RBS::AST::Declarations::Interface) # XXX
107
-
108
108
  type_params2 = decl.type_params.params.map {|param| [param.name, param.variance] }
109
109
  raise "inconsistent type parameter declaration" if type_params && type_params != type_params2
110
110
  type_params = type_params2
@@ -160,6 +160,15 @@ module TypeProf
160
160
  # including an interface is not supported yet
161
161
  end
162
162
 
163
+ when RBS::AST::Members::Extend
164
+ name = member.name
165
+ if name.kind == :class
166
+ mod = conv_type_name(name)
167
+ extended_modules << mod
168
+ else
169
+ # extending a module with an interface is not supported yet
170
+ end
171
+
163
172
  when RBS::AST::Members::InstanceVariable
164
173
  ivars[member.name] = conv_type(member.type)
165
174
  when RBS::AST::Members::ClassVariable
@@ -184,6 +193,7 @@ module TypeProf
184
193
  superclass: superclass,
185
194
  members: {
186
195
  included_modules: included_modules,
196
+ extended_modules: extended_modules,
187
197
  methods: methods,
188
198
  ivars: ivars,
189
199
  cvars: cvars,
@@ -196,13 +206,11 @@ module TypeProf
196
206
  end
197
207
 
198
208
  def each_class_decl
199
- classes = []
200
-
201
209
  # topological sort
202
210
  # * superclasses and modules appear earlier than their subclasses (Object is earlier than String)
203
211
  # * namespace module appers earlier than its children (Process is earlier than Process::Status)
204
212
  visited = {}
205
- queue = @cur_env.class_decls.keys.map {|name| [:visit, name] }
213
+ queue = @cur_env.class_decls.keys.map {|name| [:visit, name] }.reverse
206
214
  until queue.empty?
207
215
  event, name = queue.pop
208
216
  case event
@@ -223,7 +231,9 @@ module TypeProf
223
231
  end
224
232
  end
225
233
 
226
- classes
234
+ @cur_env.interface_decls.each do |name, decl|
235
+ yield name, [decl]
236
+ end
227
237
  end
228
238
 
229
239
  def each_ancestor(decl, &blk)
@@ -236,15 +246,15 @@ module TypeProf
236
246
  end
237
247
  end
238
248
 
239
- def get_super_class_name(name)
249
+ def get_super_class_name(name, decls)
240
250
  return nil if name == RBS::BuiltinNames::BasicObject.name
241
251
 
242
- @all_env.class_decls[name].decls.each do |decl|
252
+ decls.each do |decl|
243
253
  decl = decl.decl
244
254
  case decl
245
255
  when RBS::AST::Declarations::Class
246
256
  return decl.super_class.name if decl.super_class
247
- when RBS::AST::Declarations::Module
257
+ when RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface
248
258
  return nil
249
259
  else
250
260
  raise "unknown declaration: %p" % decl.class
@@ -255,35 +265,38 @@ module TypeProf
255
265
  end
256
266
 
257
267
  def conv_method_def(rbs_method_types)
258
- rbs_method_types.map do |type|
259
- blk = type.block ? conv_block(type.block) : nil
260
- type_params = type.type_params
261
-
262
- lead_tys = type.type.required_positionals.map {|type| conv_type(type.type) }
263
- opt_tys = type.type.optional_positionals.map {|type| conv_type(type.type) }
264
- rest_ty = type.type.rest_positionals
265
- rest_ty = conv_type(rest_ty.type) if rest_ty
266
- opt_kw_tys = type.type.optional_keywords.to_h {|key, type| [key, conv_type(type.type)] }
267
- req_kw_tys = type.type.required_keywords.to_h {|key, type| [key, conv_type(type.type)] }
268
- rest_kw_ty = type.type.rest_keywords
269
- raise NotImplementedError if rest_kw_ty # XXX
270
-
271
- ret_ty = conv_type(type.type.return_type)
272
-
273
- {
274
- type_params: type_params,
275
- lead_tys: lead_tys,
276
- opt_tys: opt_tys,
277
- rest_ty: rest_ty,
278
- req_kw_tys: req_kw_tys,
279
- opt_kw_tys: opt_kw_tys,
280
- rest_kw_ty: rest_kw_ty,
281
- blk: blk,
282
- ret_ty: ret_ty,
283
- }
268
+ rbs_method_types.map do |method_type|
269
+ conv_func(method_type.type_params, method_type.type, method_type.block)
284
270
  end
285
271
  end
286
272
 
273
+ def conv_func(type_params, func, block)
274
+ blk = block ? conv_block(block) : nil
275
+
276
+ lead_tys = func.required_positionals.map {|type| conv_type(type.type) }
277
+ opt_tys = func.optional_positionals.map {|type| conv_type(type.type) }
278
+ rest_ty = func.rest_positionals
279
+ rest_ty = conv_type(rest_ty.type) if rest_ty
280
+ opt_kw_tys = func.optional_keywords.to_h {|key, type| [key, conv_type(type.type)] }
281
+ req_kw_tys = func.required_keywords.to_h {|key, type| [key, conv_type(type.type)] }
282
+ rest_kw_ty = func.rest_keywords
283
+ raise NotImplementedError if rest_kw_ty # XXX
284
+
285
+ ret_ty = conv_type(func.return_type)
286
+
287
+ {
288
+ type_params: type_params,
289
+ lead_tys: lead_tys,
290
+ opt_tys: opt_tys,
291
+ rest_ty: rest_ty,
292
+ req_kw_tys: req_kw_tys,
293
+ opt_kw_tys: opt_kw_tys,
294
+ rest_kw_ty: rest_kw_ty,
295
+ blk: blk,
296
+ ret_ty: ret_ty,
297
+ }
298
+ end
299
+
287
300
  def attr_reader_def(ty)
288
301
  [{
289
302
  type_params: [],
@@ -320,6 +333,8 @@ module TypeProf
320
333
  raise NotImplementedError unless type.required_keywords.empty?
321
334
  raise NotImplementedError if type.rest_keywords
322
335
 
336
+ req = rbs_block.required
337
+
323
338
  lead_tys = type.required_positionals.map do |type|
324
339
  conv_type(type.type)
325
340
  end
@@ -329,7 +344,7 @@ module TypeProf
329
344
 
330
345
  ret_ty = conv_type(type.return_type)
331
346
 
332
- [lead_tys, opt_tys, ret_ty]
347
+ [req, lead_tys, opt_tys, ret_ty]
333
348
  end
334
349
 
335
350
  def conv_type(ty)
@@ -350,11 +365,16 @@ module TypeProf
350
365
  raise if ty.args.size != 2
351
366
  [:array, [:Enumerator], [], conv_type(ty.args.first)]
352
367
  else
353
- [:instance, klass]
368
+ if ty.args.empty?
369
+ [:instance, klass]
370
+ else
371
+ [:cell, [:instance, klass], ty.args.map {|ty| conv_type(ty) }]
372
+ end
354
373
  end
355
374
  when RBS::Types::Bases::Bool then [:bool]
356
375
  when RBS::Types::Bases::Any then [:any]
357
- when RBS::Types::Bases::Void then [:any]
376
+ when RBS::Types::Bases::Top then [:any]
377
+ when RBS::Types::Bases::Void then [:void]
358
378
  when RBS::Types::Bases::Self then [:self]
359
379
  when RBS::Types::Bases::Nil then [:nil]
360
380
  when RBS::Types::Bases::Bottom then [:union, []]
@@ -387,11 +407,13 @@ module TypeProf
387
407
  when "::_ToInt" then [:int]
388
408
  when "::_ToAry[U]" then [:array, [:Array], [], [:var, :U]]
389
409
  else
390
- [:any]
410
+ [:instance, conv_type_name(ty.name)]
391
411
  end
392
412
  when RBS::Types::Bases::Instance then [:any] # XXX: not implemented yet
393
- when RBS::Types::Record then [:any] # XXX: not implemented yet
394
- when RBS::Types::Proc then [:any] # XXX: not implemented yet
413
+ when RBS::Types::Record
414
+ [:hash_record, [:Hash], ty.fields.map {|key, ty| [key, conv_type(ty)] }]
415
+ when RBS::Types::Proc
416
+ [:proc, conv_func(nil, ty.type, nil)]
395
417
  else
396
418
  warn "unknown RBS type: %p" % ty.class
397
419
  [:any]
@@ -411,7 +433,7 @@ module TypeProf
411
433
  def self.import_library(scratch, feature)
412
434
  begin
413
435
  json = scratch.rbs_reader.load_library(feature)
414
- rescue RBS::EnvironmentLoader::UnknownLibraryNameError
436
+ rescue RBS::EnvironmentLoader::UnknownLibraryError
415
437
  return nil
416
438
  end
417
439
  # need cache?
@@ -419,7 +441,8 @@ module TypeProf
419
441
  end
420
442
 
421
443
  def self.import_rbs_file(scratch, rbs_path)
422
- Import.new(scratch, scratch.rbs_reader.load_path(Pathname(rbs_path))).import(true)
444
+ rbs_path = Pathname(rbs_path) unless rbs_path.is_a?(Pathname)
445
+ Import.new(scratch, scratch.rbs_reader.load_path(rbs_path)).import(true)
423
446
  end
424
447
 
425
448
  def initialize(scratch, json)
@@ -451,6 +474,7 @@ module TypeProf
451
474
  when [:Symbol] then Type::Builtin[:sym] = klass
452
475
  when [:Array] then Type::Builtin[:ary] = klass
453
476
  when [:Hash] then Type::Builtin[:hash] = klass
477
+ when [:Proc] then Type::Builtin[:proc] = klass
454
478
  end
455
479
  end
456
480
 
@@ -459,6 +483,7 @@ module TypeProf
459
483
 
460
484
  classes.each do |klass, members|
461
485
  included_modules = members[:included_modules]
486
+ extended_modules = members[:extended_modules]
462
487
  methods = members[:methods]
463
488
  ivars = members[:ivars]
464
489
  cvars = members[:cvars]
@@ -468,6 +493,10 @@ module TypeProf
468
493
  @scratch.include_module(klass, path_to_klass(mod), nil)
469
494
  end
470
495
 
496
+ extended_modules.each do |mod|
497
+ @scratch.extend_module(klass, path_to_klass(mod), nil)
498
+ end
499
+
471
500
  methods.each do |(singleton, method_name), mdef|
472
501
  rbs_source = explicit ? rbs_sources[[singleton, method_name]] : nil
473
502
  mdef = conv_method_def(method_name, mdef, rbs_source)
@@ -475,73 +504,86 @@ module TypeProf
475
504
  end
476
505
 
477
506
  ivars.each do |ivar_name, ty|
478
- ty = conv_type(ty)
507
+ ty = conv_type(ty).remove_type_vars
479
508
  @scratch.add_ivar_write!(Type::Instance.new(klass), ivar_name, ty, nil)
480
509
  end
481
510
 
482
511
  cvars.each do |ivar_name, ty|
483
- ty = conv_type(ty)
512
+ ty = conv_type(ty).remove_type_vars
484
513
  @scratch.add_cvar_write!(klass, ivar_name, ty, nil)
485
514
  end
486
515
  end
487
516
 
488
517
  @json[:constants].each do |classpath, value|
489
518
  base_klass = path_to_klass(classpath[0..-2])
490
- value = conv_type(value)
491
- @scratch.add_constant(base_klass, classpath[-1], value)
519
+ value = conv_type(value).remove_type_vars
520
+ @scratch.add_constant(base_klass, classpath[-1], value, nil)
492
521
  end
493
522
 
494
- @json[:globals].each do |name, value|
495
- @scratch.add_gvar_write!(name, conv_type(value), nil)
523
+ @json[:globals].each do |name, ty|
524
+ ty = conv_type(ty).remove_type_vars
525
+ @scratch.add_gvar_write!(name, ty, nil)
496
526
  end
497
527
 
498
528
  true
499
529
  end
500
530
 
501
531
  def conv_method_def(method_name, mdef, rbs_source)
502
- sig_rets = mdef.map do |sig_ret|
503
- #type_params = sig_ret[:type_params] # XXX
504
- lead_tys = sig_ret[:lead_tys]
505
- opt_tys = sig_ret[:opt_tys]
506
- rest_ty = sig_ret[:rest_ty]
507
- req_kw_tys = sig_ret[:req_kw_tys]
508
- opt_kw_tys = sig_ret[:opt_kw_tys]
509
- rest_kw_ty = sig_ret[:rest_kw_ty]
510
- blk = sig_ret[:blk]
511
- ret_ty = sig_ret[:ret_ty]
532
+ sig_rets = mdef.flat_map do |sig_ret|
533
+ conv_func(sig_ret)
534
+ end
512
535
 
513
- lead_tys = lead_tys.map {|ty| conv_type(ty) }
514
- opt_tys = opt_tys.map {|ty| conv_type(ty) }
515
- rest_ty = conv_type(rest_ty) if rest_ty
516
- kw_tys = []
517
- req_kw_tys.each {|key, ty| kw_tys << [true, key, conv_type(ty)] }
518
- opt_kw_tys.each {|key, ty| kw_tys << [false, key, conv_type(ty)] }
519
- kw_rest_ty = conv_type(rest_kw_ty) if rest_kw_ty
520
- blk = blk ? conv_block(blk) : Type.nil
521
- fargs = FormalArguments.new(lead_tys, opt_tys, rest_ty, [], kw_tys, kw_rest_ty, blk)
536
+ TypedMethodDef.new(sig_rets, rbs_source)
537
+ end
538
+
539
+ def conv_func(sig_ret)
540
+ #type_params = sig_ret[:type_params] # XXX
541
+ lead_tys = sig_ret[:lead_tys]
542
+ opt_tys = sig_ret[:opt_tys]
543
+ rest_ty = sig_ret[:rest_ty]
544
+ req_kw_tys = sig_ret[:req_kw_tys]
545
+ opt_kw_tys = sig_ret[:opt_kw_tys]
546
+ rest_kw_ty = sig_ret[:rest_kw_ty]
547
+ blk = sig_ret[:blk]
548
+ ret_ty = sig_ret[:ret_ty]
522
549
 
523
- ret_ty = conv_type(ret_ty)
550
+ lead_tys = lead_tys.map {|ty| conv_type(ty) }
551
+ opt_tys = opt_tys.map {|ty| conv_type(ty) }
552
+ rest_ty = conv_type(rest_ty) if rest_ty
553
+ kw_tys = []
554
+ req_kw_tys.each {|key, ty| kw_tys << [true, key, conv_type(ty)] }
555
+ opt_kw_tys.each {|key, ty| kw_tys << [false, key, conv_type(ty)] }
556
+ kw_rest_ty = conv_type(rest_kw_ty) if rest_kw_ty
524
557
 
525
- [fargs, ret_ty]
526
- end.compact
558
+ blks = conv_block(blk)
527
559
 
528
- TypedMethodDef.new(sig_rets, rbs_source)
560
+ ret_ty = conv_type(ret_ty)
561
+
562
+ blks.map do |blk|
563
+ [MethodSignature.new(lead_tys, opt_tys, rest_ty, [], kw_tys, kw_rest_ty, blk), ret_ty]
564
+ end
529
565
  end
530
566
 
531
567
  def conv_block(blk)
532
- lead_tys, opt_tys, ret_ty = blk
568
+ return [Type.nil] unless blk
569
+ req, lead_tys, opt_tys, ret_ty = blk
533
570
  lead_tys = lead_tys.map {|ty| conv_type(ty) }
534
571
  opt_tys = opt_tys.map {|ty| conv_type(ty) }
535
- fargs = FormalArguments.new(lead_tys, opt_tys, nil, nil, nil, nil, nil)
572
+ msig = MethodSignature.new(lead_tys, opt_tys, nil, nil, nil, nil, nil)
536
573
  ret_ty = conv_type(ret_ty)
537
- Type::TypedProc.new(fargs, ret_ty, Type::Builtin[:proc])
574
+ ret = [Type::Proc.new(TypedBlock.new(msig, ret_ty), Type::Builtin[:proc])]
575
+ ret << Type.nil unless req
576
+ ret
538
577
  end
539
578
 
540
579
  def conv_type(ty)
541
580
  case ty.first
542
581
  when :class then path_to_klass(ty[1])
543
582
  when :instance then Type::Instance.new(path_to_klass(ty[1]))
583
+ when :cell
584
+ Type::Cell.new(Type::Cell::Elements.new(ty[2].map {|ty| conv_type(ty) }), conv_type(ty[1]))
544
585
  when :any then Type.any
586
+ when :void then Type::Void.new
545
587
  when :nil then Type.nil
546
588
  when :optional then Type.optional(conv_type(ty[1]))
547
589
  when :bool then Type.bool
@@ -564,11 +606,23 @@ module TypeProf
564
606
  v_ty = conv_type(v)
565
607
  h[k_ty] = v_ty
566
608
  end
609
+ when :hash_record
610
+ _, path, key_tys = ty
611
+ Type.gen_hash(Type::Instance.new(path_to_klass(path))) do |h|
612
+ key_tys.each do |key, ty|
613
+ k_ty = Type::Symbol.new(key, Type::Instance.new(Type::Builtin[:sym]))
614
+ v_ty = conv_type(ty)
615
+ h[k_ty] = v_ty
616
+ end
617
+ end
567
618
  when :union
568
619
  tys = ty[1]
569
- Type::Union.new(Utils::Set[*tys.map {|ty2| conv_type(ty2) }], nil) # XXX: Array and Hash support
620
+ Type::Union.new(Utils::Set[*tys.map {|ty2| conv_type(ty2) }], nil).normalize # XXX: Array and Hash support
570
621
  when :var
571
622
  Type::Var.new(ty[1])
623
+ when :proc
624
+ msig, ret_ty = conv_func(ty[1]).first # Currently, RBS Proc does not accept a block, so the size should be always one
625
+ Type::Proc.new(TypedBlock.new(msig, ret_ty), Type::Instance.new(Type::Builtin[:proc]))
572
626
  else
573
627
  pp ty
574
628
  raise NotImplementedError