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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -2
- data/.gitignore +1 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +10 -21
- data/LICENSE +21 -0
- data/README.md +6 -0
- data/doc/demo.md +398 -0
- data/doc/doc.ja.md +6 -1
- data/doc/doc.md +7 -2
- data/exe/typeprof +2 -1
- data/lib/typeprof.rb +9 -0
- data/lib/typeprof/analyzer.rb +427 -325
- data/lib/typeprof/arguments.rb +405 -0
- data/lib/typeprof/block.rb +136 -0
- data/lib/typeprof/builtin.rb +36 -25
- data/lib/typeprof/cli.rb +51 -98
- data/lib/typeprof/config.rb +114 -0
- data/lib/typeprof/container-type.rb +280 -92
- data/lib/typeprof/export.rb +197 -108
- data/lib/typeprof/import.rb +134 -80
- data/lib/typeprof/iseq.rb +42 -1
- data/lib/typeprof/method.rb +178 -82
- data/lib/typeprof/type.rb +228 -369
- data/lib/typeprof/utils.rb +4 -18
- data/lib/typeprof/version.rb +3 -0
- data/smoke/arguments2.rb +55 -0
- data/smoke/array-each3.rb +1 -4
- data/smoke/array12.rb +1 -1
- data/smoke/array6.rb +1 -0
- data/smoke/block-ambiguous.rb +36 -0
- data/smoke/block-args1-rest.rb +62 -0
- data/smoke/block-args1.rb +59 -0
- data/smoke/block-args2-rest.rb +62 -0
- data/smoke/block-args2.rb +59 -0
- data/smoke/block-args3-rest.rb +73 -0
- data/smoke/block-args3.rb +70 -0
- data/smoke/block-blockarg.rb +27 -0
- data/smoke/block-kwarg.rb +52 -0
- data/smoke/block10.rb +1 -1
- data/smoke/block11.rb +1 -1
- data/smoke/block14.rb +17 -0
- data/smoke/block4.rb +2 -2
- data/smoke/block5.rb +1 -0
- data/smoke/block6.rb +1 -1
- data/smoke/block7.rb +0 -2
- data/smoke/block8.rb +2 -2
- data/smoke/block9.rb +1 -1
- data/smoke/blown.rb +1 -1
- data/smoke/class-hierarchy.rb +54 -0
- data/smoke/class-hierarchy2.rb +27 -0
- data/smoke/constant1.rb +11 -6
- data/smoke/constant2.rb +2 -0
- data/smoke/cvar.rb +1 -0
- data/smoke/demo10.rb +1 -1
- data/smoke/demo8.rb +2 -2
- data/smoke/demo9.rb +1 -3
- data/smoke/flow7.rb +1 -7
- data/smoke/flow8.rb +13 -0
- data/smoke/hash-fetch.rb +3 -3
- data/smoke/hash-merge-bang.rb +11 -0
- data/smoke/hash1.rb +1 -1
- data/smoke/hash3.rb +1 -1
- data/smoke/hash4.rb +1 -1
- data/smoke/instance_eval.rb +1 -1
- data/smoke/int_times.rb +1 -1
- data/smoke/ivar2.rb +1 -1
- data/smoke/keyword3.rb +1 -2
- data/smoke/keyword4.rb +1 -1
- data/smoke/kwsplat1.rb +1 -1
- data/smoke/kwsplat2.rb +1 -1
- data/smoke/module4.rb +2 -0
- data/smoke/multiple-superclass.rb +4 -0
- data/smoke/next2.rb +1 -1
- data/smoke/optional1.rb +1 -1
- data/smoke/optional2.rb +1 -1
- data/smoke/optional3.rb +10 -0
- data/smoke/pattern-match1.rb +23 -0
- data/smoke/pattern-match2.rb +15 -0
- data/smoke/proc4.rb +1 -1
- data/smoke/rbs-extend.rb +9 -0
- data/smoke/rbs-extend.rbs +7 -0
- data/smoke/rbs-interface.rb +24 -0
- data/smoke/rbs-interface.rbs +12 -0
- data/smoke/rbs-proc1.rb +9 -0
- data/smoke/rbs-proc1.rbs +3 -0
- data/smoke/rbs-proc2.rb +20 -0
- data/smoke/rbs-proc2.rbs +3 -0
- data/smoke/rbs-proc3.rb +13 -0
- data/smoke/rbs-proc3.rbs +4 -0
- data/smoke/rbs-record.rb +17 -0
- data/smoke/rbs-record.rbs +4 -0
- data/smoke/rbs-tyvar.rb +18 -0
- data/smoke/rbs-tyvar.rbs +5 -0
- data/smoke/rbs-tyvar2.rb +20 -0
- data/smoke/rbs-tyvar2.rbs +9 -0
- data/smoke/rbs-tyvar3.rb +17 -0
- data/smoke/rbs-tyvar3.rbs +5 -0
- data/smoke/rbs-tyvar4.rb +36 -0
- data/smoke/rbs-tyvar5.rb +12 -0
- data/smoke/rbs-tyvar5.rbs +8 -0
- data/smoke/rest1.rb +1 -1
- data/smoke/rest2.rb +1 -1
- data/smoke/rest3.rb +1 -1
- data/smoke/rest5.rb +1 -1
- data/smoke/rest6.rb +1 -1
- data/smoke/retry1.rb +1 -1
- data/smoke/return.rb +1 -1
- data/smoke/singleton_method.rb +3 -0
- data/smoke/step.rb +1 -1
- data/smoke/struct.rb +4 -3
- data/smoke/struct3.rb +14 -0
- data/smoke/symbol-proc.rb +24 -0
- data/smoke/uninitialize-var.rb +12 -0
- data/smoke/user-demo.rb +15 -0
- data/smoke/wrong-extend.rb +1 -0
- data/typeprof.gemspec +4 -2
- metadata +53 -6
- data/run.sh +0 -3
- data/smoke/variadic1.rb.notyet +0 -5
data/lib/typeprof/export.rb
CHANGED
|
@@ -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
|
|
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
|
|
88
|
-
|
|
91
|
+
def conv_class(namespace, class_def, inner_classes)
|
|
92
|
+
@scratch.namespace = namespace
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
@
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
168
|
-
|
|
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
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
cvars
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
|
|
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 "
|
|
203
|
-
output.puts "
|
|
204
|
-
output.puts "
|
|
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
|
data/lib/typeprof/import.rb
CHANGED
|
@@ -29,9 +29,10 @@ module TypeProf
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def self.load_rbs(env, builtin: false, **opt)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 |
|
|
259
|
-
|
|
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
|
-
|
|
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::
|
|
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
|
-
[:
|
|
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
|
|
394
|
-
|
|
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::
|
|
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
|
-
|
|
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,
|
|
495
|
-
|
|
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.
|
|
503
|
-
|
|
504
|
-
|
|
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
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
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
|
-
|
|
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
|
-
|
|
526
|
-
end.compact
|
|
558
|
+
blks = conv_block(blk)
|
|
527
559
|
|
|
528
|
-
|
|
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
|
-
|
|
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
|
-
|
|
572
|
+
msig = MethodSignature.new(lead_tys, opt_tys, nil, nil, nil, nil, nil)
|
|
536
573
|
ret_ty = conv_type(ret_ty)
|
|
537
|
-
Type::
|
|
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
|