typeprof 0.1.2 → 0.4.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/.gitignore +3 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +10 -21
- data/LICENSE +21 -0
- data/README.md +1 -1
- data/doc/demo.md +398 -0
- data/doc/doc.ja.md +11 -1
- data/doc/doc.md +16 -7
- data/exe/typeprof +2 -1
- data/lib/typeprof.rb +9 -0
- data/lib/typeprof/analyzer.rb +455 -364
- data/lib/typeprof/arguments.rb +397 -0
- data/lib/typeprof/block.rb +133 -0
- data/lib/typeprof/builtin.rb +125 -116
- data/lib/typeprof/cli.rb +62 -71
- data/lib/typeprof/config.rb +114 -0
- data/lib/typeprof/container-type.rb +208 -27
- data/lib/typeprof/export.rb +201 -96
- data/lib/typeprof/import.rb +451 -365
- data/lib/typeprof/iseq.rb +43 -2
- data/lib/typeprof/method.rb +139 -100
- data/lib/typeprof/type.rb +138 -297
- 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/block11.rb +1 -1
- data/smoke/block13.rb +9 -0
- data/smoke/block13.rbs +3 -0
- 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/class.rb +2 -0
- data/smoke/constant1.rb +13 -5
- data/smoke/constant2.rb +2 -0
- data/smoke/cvar.rb +1 -0
- data/smoke/demo10.rb +1 -1
- data/smoke/demo5.rb +3 -0
- 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/gvar.rb +1 -1
- data/smoke/gvar2.rb +17 -0
- data/smoke/gvar2.rbs +1 -0
- data/smoke/hash4.rb +1 -1
- data/smoke/inheritance2.rb +6 -0
- data/smoke/instance_eval.rb +1 -1
- data/smoke/int_times.rb +1 -1
- data/smoke/ivar3.rb +16 -0
- data/smoke/ivar3.rbs +3 -0
- data/smoke/keyword3.rb +1 -2
- data/smoke/keyword4.rb +1 -1
- data/smoke/manual-rbs2.rb +1 -1
- data/smoke/manual-rbs3.rb +12 -0
- data/smoke/manual-rbs3.rbs +3 -0
- data/smoke/module4.rb +5 -0
- data/smoke/multiple-superclass.rb +12 -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/proc4.rb +1 -1
- data/smoke/rbs-alias.rb +9 -0
- data/smoke/rbs-alias.rbs +4 -0
- data/smoke/rbs-attr.rb +26 -0
- data/smoke/rbs-attr.rbs +5 -0
- 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 +25 -0
- data/smoke/rbs-tyvar3.rbs +4 -0
- data/smoke/rbs-vars.rb +39 -0
- data/smoke/rbs-vars.rbs +7 -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 +6 -2
- data/smoke/struct3.rb +14 -0
- data/smoke/super1.rb +18 -0
- data/smoke/symbol-proc.rb +24 -0
- data/smoke/union-recv.rb +6 -0
- data/smoke/user-demo.rb +15 -0
- data/smoke/wrong-extend.rb +1 -0
- data/tools/setup-insns-def.rb +1 -1
- data/tools/stackprof-wrapper.rb +1 -1
- data/typeprof.gemspec +12 -4
- metadata +68 -10
- data/.gitmodules +0 -6
- data/run.sh +0 -3
- data/smoke/variadic1.rb.notyet +0 -5
data/lib/typeprof/builtin.rb
CHANGED
|
@@ -59,16 +59,19 @@ module TypeProf
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def proc_call(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
62
|
-
|
|
63
|
-
scratch.do_invoke_block(given_block, recv, aargs, ep, env, &ctn)
|
|
62
|
+
scratch.do_invoke_block(recv, aargs, ep, env, &ctn)
|
|
64
63
|
end
|
|
65
64
|
|
|
66
65
|
def object_s_new(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
67
66
|
ty = Type::Instance.new(recv)
|
|
67
|
+
if recv.type_params.size >= 1
|
|
68
|
+
ty = Type::Cell.new(Type::Cell::Elements.new([Type.bot] * recv.type_params.size), ty)
|
|
69
|
+
env, ty = scratch.localize_type(ty, env, ep, AllocationSite.new(ep).add_id(:object_s_new))
|
|
70
|
+
end
|
|
68
71
|
meths = scratch.get_method(recv, false, :initialize)
|
|
69
72
|
meths.flat_map do |meth|
|
|
70
73
|
meth.do_send(ty, :initialize, aargs, ep, env, scratch) do |ret_ty, ep, env|
|
|
71
|
-
ctn[
|
|
74
|
+
ctn[ty, ep, env]
|
|
72
75
|
end
|
|
73
76
|
end
|
|
74
77
|
end
|
|
@@ -118,7 +121,7 @@ module TypeProf
|
|
|
118
121
|
else
|
|
119
122
|
mid_ty = aargs.rest_ty
|
|
120
123
|
end
|
|
121
|
-
aargs = ActualArguments.new(aargs.lead_tys[1..-1], aargs.rest_ty, aargs.
|
|
124
|
+
aargs = ActualArguments.new(aargs.lead_tys[1..-1], aargs.rest_ty, aargs.kw_tys, aargs.blk_ty)
|
|
122
125
|
found = false
|
|
123
126
|
mid_ty.each_child do |mid|
|
|
124
127
|
if mid.is_a?(Type::Symbol)
|
|
@@ -138,16 +141,15 @@ module TypeProf
|
|
|
138
141
|
ctn[type.any, ep, env]
|
|
139
142
|
return
|
|
140
143
|
end
|
|
141
|
-
naargs = ActualArguments.new([recv],
|
|
142
|
-
|
|
143
|
-
scratch.do_invoke_block(given_block, aargs.blk_ty, naargs, ep, env, replace_recv_ty: recv) do |_ret_ty, ep|
|
|
144
|
+
naargs = ActualArguments.new([recv], nil, {}, Type.nil)
|
|
145
|
+
scratch.do_invoke_block(aargs.blk_ty, naargs, ep, env, replace_recv_ty: recv) do |_ret_ty, ep|
|
|
144
146
|
ctn[recv, ep, scratch.return_envs[ep]]
|
|
145
147
|
end
|
|
146
148
|
end
|
|
147
149
|
|
|
148
150
|
def module_include(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
149
151
|
arg = aargs.lead_tys[0]
|
|
150
|
-
scratch.include_module(recv, arg)
|
|
152
|
+
scratch.include_module(recv, arg, ep.ctx.iseq.absolute_path)
|
|
151
153
|
ctn[recv, ep, env]
|
|
152
154
|
end
|
|
153
155
|
|
|
@@ -155,7 +157,7 @@ module TypeProf
|
|
|
155
157
|
arg = aargs.lead_tys[0]
|
|
156
158
|
arg.each_child do |arg|
|
|
157
159
|
if arg.is_a?(Type::Class)
|
|
158
|
-
scratch.extend_module(recv, arg)
|
|
160
|
+
scratch.extend_module(recv, arg, ep.ctx.iseq.absolute_path)
|
|
159
161
|
end
|
|
160
162
|
end
|
|
161
163
|
ctn[recv, ep, env]
|
|
@@ -180,7 +182,7 @@ module TypeProf
|
|
|
180
182
|
aargs.lead_tys.each do |aarg|
|
|
181
183
|
sym = get_sym("attr_accessor", aarg, ep, scratch) or next
|
|
182
184
|
cref = ep.ctx.cref
|
|
183
|
-
scratch.add_attr_method(cref.klass, sym, :"@#{ sym }", :accessor)
|
|
185
|
+
scratch.add_attr_method(cref.klass, ep.ctx.iseq.absolute_path, sym, :"@#{ sym }", :accessor)
|
|
184
186
|
end
|
|
185
187
|
ctn[Type.nil, ep, env]
|
|
186
188
|
end
|
|
@@ -189,7 +191,7 @@ module TypeProf
|
|
|
189
191
|
aargs.lead_tys.each do |aarg|
|
|
190
192
|
sym = get_sym("attr_reader", aarg, ep, scratch) or next
|
|
191
193
|
cref = ep.ctx.cref
|
|
192
|
-
scratch.add_attr_method(cref.klass, sym, :"@#{ sym }", :reader)
|
|
194
|
+
scratch.add_attr_method(cref.klass, ep.ctx.iseq.absolute_path, sym, :"@#{ sym }", :reader)
|
|
193
195
|
end
|
|
194
196
|
ctn[Type.nil, ep, env]
|
|
195
197
|
end
|
|
@@ -198,7 +200,7 @@ module TypeProf
|
|
|
198
200
|
aargs.lead_tys.each do |aarg|
|
|
199
201
|
sym = get_sym("attr_writer", aarg, ep, scratch) or next
|
|
200
202
|
cref = ep.ctx.cref
|
|
201
|
-
scratch.add_attr_method(cref.klass, sym, :"@#{ sym }", :writer)
|
|
203
|
+
scratch.add_attr_method(cref.klass, ep.ctx.iseq.absolute_path, sym, :"@#{ sym }", :writer)
|
|
202
204
|
end
|
|
203
205
|
ctn[Type.nil, ep, env]
|
|
204
206
|
end
|
|
@@ -244,7 +246,10 @@ module TypeProf
|
|
|
244
246
|
def array_aset(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
245
247
|
return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalArray)
|
|
246
248
|
|
|
247
|
-
|
|
249
|
+
if aargs.lead_tys.size != 2
|
|
250
|
+
#raise NotImplementedError # XXX
|
|
251
|
+
ctn[Type.any, ep, env]
|
|
252
|
+
end
|
|
248
253
|
|
|
249
254
|
idx = aargs.lead_tys.first
|
|
250
255
|
if idx.is_a?(Type::Literal)
|
|
@@ -256,7 +261,7 @@ module TypeProf
|
|
|
256
261
|
|
|
257
262
|
ty = aargs.lead_tys.last
|
|
258
263
|
|
|
259
|
-
env = scratch.update_container_elem_types(env, ep, recv.id) do |elems|
|
|
264
|
+
env = scratch.update_container_elem_types(env, ep, recv.id, recv.base_type) do |elems|
|
|
260
265
|
elems.update(idx, ty)
|
|
261
266
|
end
|
|
262
267
|
|
|
@@ -283,8 +288,6 @@ module TypeProf
|
|
|
283
288
|
return
|
|
284
289
|
end
|
|
285
290
|
idx = aargs.lead_tys.first
|
|
286
|
-
#idx = scratch.globalize_type(idx, env, ep)
|
|
287
|
-
# XXX: recv may be a union
|
|
288
291
|
recv.each_child do |recv|
|
|
289
292
|
if recv.is_a?(Type::LocalHash)
|
|
290
293
|
ty = scratch.get_hash_elem_type(env, ep, recv.id, idx)
|
|
@@ -309,7 +312,7 @@ module TypeProf
|
|
|
309
312
|
return ctn[ty, ep, env]
|
|
310
313
|
end
|
|
311
314
|
|
|
312
|
-
env = scratch.update_container_elem_types(env, ep, recv.id) do |elems|
|
|
315
|
+
env = scratch.update_container_elem_types(env, ep, recv.id, recv.base_type) do |elems|
|
|
313
316
|
elems.update(idx, ty)
|
|
314
317
|
end
|
|
315
318
|
|
|
@@ -318,14 +321,12 @@ module TypeProf
|
|
|
318
321
|
|
|
319
322
|
def struct_initialize(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
320
323
|
recv = Type::Instance.new(recv)
|
|
321
|
-
scratch.
|
|
322
|
-
|
|
323
|
-
ty.elems.lead_tys.zip(aargs.lead_tys) do |sym, ty|
|
|
324
|
+
scratch.add_ivar_read!(recv, :_members, ep) do |member_ary_ty, ep|
|
|
325
|
+
member_ary_ty.elems.lead_tys.zip(aargs.lead_tys) do |sym, ty|
|
|
324
326
|
ty ||= Type.nil
|
|
325
327
|
scratch.set_instance_variable(recv, sym.sym, ty, ep, env)
|
|
326
328
|
end
|
|
327
329
|
end
|
|
328
|
-
#scratch.set_instance_variable(recv, , ty, ep, env)
|
|
329
330
|
ctn[recv, ep, env]
|
|
330
331
|
end
|
|
331
332
|
|
|
@@ -339,9 +340,8 @@ module TypeProf
|
|
|
339
340
|
return
|
|
340
341
|
end
|
|
341
342
|
if struct_klass != recv
|
|
342
|
-
scratch.
|
|
343
|
-
|
|
344
|
-
scratch.set_instance_variable(Type::Instance.new(recv), :_members, ty, ep, env)
|
|
343
|
+
scratch.add_ivar_read!(Type::Instance.new(struct_klass), :_members, ep) do |ty, ep|
|
|
344
|
+
scratch.add_ivar_write!(Type::Instance.new(recv), :_members, ty, ep)
|
|
345
345
|
end
|
|
346
346
|
end
|
|
347
347
|
meths = scratch.get_method(recv, false, :initialize)
|
|
@@ -358,76 +358,85 @@ module TypeProf
|
|
|
358
358
|
fields = aargs.lead_tys.map {|ty| get_sym("Struct.new", ty, ep, scratch) }.compact
|
|
359
359
|
struct_klass = scratch.new_struct(ep)
|
|
360
360
|
|
|
361
|
-
scratch.
|
|
362
|
-
scratch.
|
|
361
|
+
scratch.set_singleton_custom_method(struct_klass, :new, Builtin.method(:struct_i_new))
|
|
362
|
+
scratch.set_singleton_custom_method(struct_klass, :[], Builtin.method(:struct_i_new))
|
|
363
363
|
fields.each do |field|
|
|
364
|
-
scratch.add_attr_method(struct_klass, field, field, :accessor)
|
|
364
|
+
scratch.add_attr_method(struct_klass, ep.ctx.iseq.absolute_path, field, field, :accessor)
|
|
365
365
|
end
|
|
366
366
|
fields = fields.map {|field| Type::Symbol.new(field, Type::Instance.new(Type::Builtin[:sym])) }
|
|
367
367
|
base_ty = Type::Instance.new(Type::Builtin[:ary])
|
|
368
368
|
fields = Type::Array.new(Type::Array::Elements.new(fields), base_ty)
|
|
369
|
-
scratch.
|
|
370
|
-
#
|
|
369
|
+
scratch.add_ivar_write!(Type::Instance.new(struct_klass), :_members, fields, ep)
|
|
370
|
+
#set_singleton_custom_method(struct_klass, :members, Builtin.method(:...))
|
|
371
371
|
|
|
372
372
|
ctn[struct_klass, ep, env]
|
|
373
373
|
end
|
|
374
374
|
|
|
375
|
-
def file_load(path, ep, env, scratch, &ctn)
|
|
375
|
+
def self.file_load(path, ep, env, scratch, &ctn)
|
|
376
376
|
iseq = ISeq.compile(path)
|
|
377
|
-
callee_ep, callee_env =
|
|
377
|
+
callee_ep, callee_env = TypeProf.starting_state(iseq)
|
|
378
378
|
scratch.merge_env(callee_ep, callee_env)
|
|
379
379
|
|
|
380
|
-
scratch.add_callsite!(callee_ep.ctx,
|
|
380
|
+
scratch.add_callsite!(callee_ep.ctx, ep, env) do |_ret_ty, ep|
|
|
381
381
|
ret_ty = Type::Instance.new(Type::Builtin[:true])
|
|
382
382
|
ctn[ret_ty, ep, env]
|
|
383
383
|
end
|
|
384
384
|
end
|
|
385
385
|
|
|
386
|
+
def self.file_require(feature, scratch)
|
|
387
|
+
return :done, :false if scratch.loaded_features[feature]
|
|
388
|
+
scratch.loaded_features[feature] = true
|
|
389
|
+
|
|
390
|
+
# XXX: dynamic RBS load is really needed?? Another idea:
|
|
391
|
+
#
|
|
392
|
+
# * RBS should be loaded in advance of analysis
|
|
393
|
+
# * require "some_gem/foo" should be ignored
|
|
394
|
+
# * require "app/foo" should always load .rb file (in this case, app/foo.rb)
|
|
395
|
+
return :done, :true if Import.import_library(scratch, feature)
|
|
396
|
+
|
|
397
|
+
# Try to analyze the source code of the gem
|
|
398
|
+
begin
|
|
399
|
+
gem feature
|
|
400
|
+
rescue Gem::MissingSpecError, Gem::LoadError
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
begin
|
|
404
|
+
filetype, path = $LOAD_PATH.resolve_feature_path(feature)
|
|
405
|
+
if filetype == :rb
|
|
406
|
+
return :do, path if File.readable?(path)
|
|
407
|
+
|
|
408
|
+
return :error, "failed to load: #{ path }"
|
|
409
|
+
else
|
|
410
|
+
return :error, "cannot load a .so file: #{ path }"
|
|
411
|
+
end
|
|
412
|
+
rescue LoadError
|
|
413
|
+
return :error, "failed to require: #{ feature }"
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
|
|
386
417
|
def kernel_require(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
387
418
|
raise NotImplementedError if aargs.lead_tys.size != 1
|
|
388
419
|
feature = aargs.lead_tys.first
|
|
389
420
|
if feature.is_a?(Type::Literal)
|
|
390
421
|
feature = feature.lit
|
|
391
422
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
# * require "app/foo" should always load .rb file (in this case, app/foo.rb)
|
|
404
|
-
if RubySignatureImporter.import_library(scratch, feature)
|
|
405
|
-
result = Type::Instance.new(Type::Builtin[:true])
|
|
406
|
-
return ctn[result, ep, env]
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
begin
|
|
410
|
-
gem feature
|
|
411
|
-
rescue Gem::MissingSpecError, Gem::LoadError
|
|
412
|
-
end
|
|
413
|
-
filetype, path = $LOAD_PATH.resolve_feature_path(feature)
|
|
414
|
-
if filetype == :rb
|
|
415
|
-
# TODO: if there is RBS file for the library, do not read the source code
|
|
416
|
-
return file_load(path, ep, env, scratch, &ctn) if File.readable?(path)
|
|
417
|
-
|
|
418
|
-
scratch.warn(ep, "failed to load: #{ path }")
|
|
419
|
-
else
|
|
420
|
-
scratch.warn(ep, "cannot load a .so file: #{ path }")
|
|
421
|
-
end
|
|
422
|
-
rescue LoadError
|
|
423
|
-
scratch.warn(ep, "failed to require: #{ feature }")
|
|
423
|
+
action, arg = Builtin.file_require(feature, scratch)
|
|
424
|
+
case action
|
|
425
|
+
when :do
|
|
426
|
+
Builtin.file_load(arg, ep, env, scratch, &ctn)
|
|
427
|
+
when :done
|
|
428
|
+
result = Type::Instance.new(Type::Builtin[arg])
|
|
429
|
+
ctn[result, ep, env]
|
|
430
|
+
when :error
|
|
431
|
+
scratch.warn(ep, arg)
|
|
432
|
+
result = Type::Instance.new(Type.bool)
|
|
433
|
+
ctn[result, ep, env]
|
|
424
434
|
end
|
|
425
435
|
else
|
|
426
436
|
scratch.warn(ep, "require target cannot be identified statically")
|
|
437
|
+
result = Type::Instance.new(Type.bool)
|
|
438
|
+
ctn[result, ep, env]
|
|
427
439
|
end
|
|
428
|
-
|
|
429
|
-
result = Type::Instance.new(Type::Builtin[:true])
|
|
430
|
-
ctn[result, ep, env]
|
|
431
440
|
end
|
|
432
441
|
|
|
433
442
|
def kernel_require_relative(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
@@ -443,7 +452,7 @@ module TypeProf
|
|
|
443
452
|
scratch.loaded_features[feature] = true
|
|
444
453
|
|
|
445
454
|
path = File.join(File.dirname(ep.ctx.iseq.path), feature) + ".rb" # XXX
|
|
446
|
-
return file_load(path, ep, env, scratch, &ctn) if File.readable?(path)
|
|
455
|
+
return Builtin.file_load(path, ep, env, scratch, &ctn) if File.readable?(path)
|
|
447
456
|
|
|
448
457
|
scratch.warn(ep, "failed to load: #{ path }")
|
|
449
458
|
else
|
|
@@ -473,20 +482,17 @@ module TypeProf
|
|
|
473
482
|
end
|
|
474
483
|
|
|
475
484
|
def self.setup_initial_global_env(scratch)
|
|
476
|
-
|
|
477
|
-
scratch.
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
klass_nil = scratch.new_class(klass_obj, :NilClass, [], klass_obj) # ???
|
|
485
|
+
klass_basic_obj = scratch.new_class(nil, :BasicObject, [], :__root__, nil) # cbase, name, superclass
|
|
486
|
+
klass_obj = scratch.new_class(nil, :Object, [], klass_basic_obj, nil)
|
|
487
|
+
scratch.add_constant(klass_obj, :Object, klass_obj, nil)
|
|
488
|
+
scratch.add_constant(klass_obj, :BasicObject, klass_basic_obj, nil)
|
|
481
489
|
|
|
490
|
+
Type::Builtin[:basic_obj] = klass_basic_obj
|
|
482
491
|
Type::Builtin[:obj] = klass_obj
|
|
483
|
-
Type::Builtin[:true] = klass_true
|
|
484
|
-
Type::Builtin[:false] = klass_false
|
|
485
|
-
Type::Builtin[:nil] = klass_nil
|
|
486
492
|
|
|
487
|
-
|
|
493
|
+
Import.import_builtin(scratch)
|
|
488
494
|
|
|
489
|
-
Type::Builtin[:vmcore] = scratch.new_class(klass_obj, :VMCore, [], klass_obj)
|
|
495
|
+
Type::Builtin[:vmcore] = scratch.new_class(klass_obj, :VMCore, [], klass_obj, nil)
|
|
490
496
|
Type::Builtin[:int] = scratch.get_constant(klass_obj, :Integer)
|
|
491
497
|
Type::Builtin[:float] = scratch.get_constant(klass_obj, :Float)
|
|
492
498
|
Type::Builtin[:rational] = scratch.get_constant(klass_obj, :Rational)
|
|
@@ -511,44 +517,47 @@ module TypeProf
|
|
|
511
517
|
klass_proc = Type::Builtin[:proc]
|
|
512
518
|
klass_module = Type::Builtin[:module]
|
|
513
519
|
|
|
514
|
-
scratch.
|
|
515
|
-
scratch.
|
|
516
|
-
scratch.
|
|
517
|
-
scratch.
|
|
518
|
-
scratch.
|
|
519
|
-
scratch.
|
|
520
|
-
scratch.
|
|
521
|
-
scratch.
|
|
522
|
-
scratch.
|
|
523
|
-
scratch.
|
|
524
|
-
scratch.
|
|
525
|
-
scratch.
|
|
526
|
-
scratch.
|
|
527
|
-
scratch.
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
scratch.
|
|
531
|
-
scratch.
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
scratch.
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
scratch.
|
|
538
|
-
scratch.
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
scratch.
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
scratch.
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
scratch.
|
|
548
|
-
scratch.
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
520
|
+
scratch.set_custom_method(klass_vmcore, :"core#set_method_alias", Builtin.method(:vmcore_set_method_alias))
|
|
521
|
+
scratch.set_custom_method(klass_vmcore, :"core#undef_method", Builtin.method(:vmcore_undef_method))
|
|
522
|
+
scratch.set_custom_method(klass_vmcore, :"core#hash_merge_kwd", Builtin.method(:vmcore_hash_merge_kwd))
|
|
523
|
+
scratch.set_custom_method(klass_vmcore, :lambda, Builtin.method(:lambda))
|
|
524
|
+
scratch.set_singleton_custom_method(klass_obj, :"new", Builtin.method(:object_s_new))
|
|
525
|
+
scratch.set_singleton_custom_method(klass_obj, :"attr_accessor", Builtin.method(:module_attr_accessor))
|
|
526
|
+
scratch.set_singleton_custom_method(klass_obj, :"attr_reader", Builtin.method(:module_attr_reader))
|
|
527
|
+
scratch.set_singleton_custom_method(klass_obj, :"attr_writer", Builtin.method(:module_attr_writer))
|
|
528
|
+
scratch.set_custom_method(klass_obj, :p, Builtin.method(:kernel_p))
|
|
529
|
+
scratch.set_custom_method(klass_obj, :is_a?, Builtin.method(:object_is_a?))
|
|
530
|
+
scratch.set_custom_method(klass_obj, :respond_to?, Builtin.method(:object_respond_to?))
|
|
531
|
+
scratch.set_custom_method(klass_obj, :class, Builtin.method(:object_class))
|
|
532
|
+
scratch.set_custom_method(klass_obj, :send, Builtin.method(:object_send))
|
|
533
|
+
scratch.set_custom_method(klass_obj, :instance_eval, Builtin.method(:object_instance_eval))
|
|
534
|
+
scratch.set_custom_method(klass_obj, :proc, Builtin.method(:lambda))
|
|
535
|
+
|
|
536
|
+
scratch.set_custom_method(klass_module, :include, Builtin.method(:module_include))
|
|
537
|
+
scratch.set_custom_method(klass_module, :extend, Builtin.method(:module_extend))
|
|
538
|
+
scratch.set_custom_method(klass_module, :module_function, Builtin.method(:module_module_function))
|
|
539
|
+
|
|
540
|
+
scratch.set_custom_method(klass_proc, :[], Builtin.method(:proc_call))
|
|
541
|
+
scratch.set_custom_method(klass_proc, :call, Builtin.method(:proc_call))
|
|
542
|
+
|
|
543
|
+
scratch.set_custom_method(klass_ary, :[], Builtin.method(:array_aref))
|
|
544
|
+
scratch.set_custom_method(klass_ary, :[]=, Builtin.method(:array_aset))
|
|
545
|
+
scratch.set_custom_method(klass_ary, :pop, Builtin.method(:array_pop))
|
|
546
|
+
|
|
547
|
+
scratch.set_custom_method(klass_hash, :[], Builtin.method(:hash_aref))
|
|
548
|
+
scratch.set_custom_method(klass_hash, :[]=, Builtin.method(:hash_aset))
|
|
549
|
+
|
|
550
|
+
scratch.set_custom_method(klass_struct, :initialize, Builtin.method(:struct_initialize))
|
|
551
|
+
scratch.set_singleton_custom_method(klass_struct, :new, Builtin.method(:struct_s_new))
|
|
552
|
+
|
|
553
|
+
scratch.set_custom_method(klass_obj, :require, Builtin.method(:kernel_require))
|
|
554
|
+
scratch.set_custom_method(klass_obj, :require_relative, Builtin.method(:kernel_require_relative))
|
|
555
|
+
scratch.set_custom_method(klass_obj, :Array, Builtin.method(:kernel_Array))
|
|
556
|
+
|
|
557
|
+
# ENV: Hash[String, String]
|
|
558
|
+
str_ty = Type::Instance.new(Type::Builtin[:str])
|
|
559
|
+
env_ty = Type.gen_hash {|h| h[str_ty] = Type.optional(str_ty) }
|
|
560
|
+
scratch.add_constant(klass_obj, :ENV, env_ty, false)
|
|
552
561
|
end
|
|
553
562
|
end
|
|
554
563
|
end
|
data/lib/typeprof/cli.rb
CHANGED
|
@@ -1,38 +1,62 @@
|
|
|
1
1
|
require "optparse"
|
|
2
2
|
|
|
3
3
|
module TypeProf
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
module CLI
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def parse(argv)
|
|
6
8
|
opt = OptionParser.new
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
output = nil
|
|
9
11
|
|
|
10
12
|
# Verbose level:
|
|
11
13
|
# * 0: no output
|
|
12
14
|
# * 1: show indicator
|
|
13
15
|
# * 2: debug print
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
verbose = 1
|
|
17
|
+
|
|
18
|
+
options = {}
|
|
19
|
+
dir_filter = nil
|
|
20
|
+
gem_rbs_features = []
|
|
21
|
+
version = false
|
|
22
|
+
max_sec = max_iter = nil
|
|
23
|
+
|
|
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 }
|
|
33
|
+
|
|
34
|
+
opt.on("--include-dir DIR") do |dir|
|
|
35
|
+
# When `--include-dir` option is specified as the first directory option,
|
|
36
|
+
# typeprof will exclude any files by default unless a file path matches the explicit option
|
|
37
|
+
dir_filter ||= [[:exclude]]
|
|
38
|
+
dir_filter << [:include, File.expand_path(dir)]
|
|
39
|
+
end
|
|
40
|
+
opt.on("--exclude-dir DIR") do |dir|
|
|
41
|
+
# When `--exclude-dir` option is specified as the first directory option,
|
|
42
|
+
# typeprof will include any files by default, except Ruby's install directory and Gem directories
|
|
43
|
+
dir_filter ||= ConfigData::DEFAULT_DIR_FILTER
|
|
44
|
+
dir_filter << [:exclude, File.expand_path(dir)]
|
|
45
|
+
end
|
|
21
46
|
|
|
22
|
-
opt.on("-o OUTFILE") {|v| @output = v }
|
|
23
|
-
opt.on("-q", "--quiet") {|v| @verbose = 0 }
|
|
24
|
-
opt.on("-v", "--verbose") {|v| @verbose = 2 }
|
|
25
47
|
opt.on("-f OPTION") do |v|
|
|
26
48
|
key, args = v.split("=", 2)
|
|
27
49
|
case key
|
|
28
50
|
when "type-depth-limit"
|
|
29
|
-
|
|
51
|
+
options[:type_depth_limit] = Integer(args)
|
|
30
52
|
when "pedantic-output"
|
|
31
|
-
|
|
53
|
+
options[:pedantic_output] = true
|
|
32
54
|
when "show-errors"
|
|
33
|
-
|
|
55
|
+
options[:show_errors] = true
|
|
34
56
|
when "show-container-raw-elements"
|
|
35
|
-
|
|
57
|
+
options[:show_container_raw_elements] = true
|
|
58
|
+
when "stackprof"
|
|
59
|
+
options[:stackprof] = args ? args.to_sym : :cpu
|
|
36
60
|
else
|
|
37
61
|
raise OptionParser::InvalidOption.new("unknown option: #{ key }")
|
|
38
62
|
end
|
|
@@ -40,71 +64,38 @@ module TypeProf
|
|
|
40
64
|
|
|
41
65
|
opt.parse!(argv)
|
|
42
66
|
|
|
43
|
-
|
|
44
|
-
|
|
67
|
+
dir_filter ||= ConfigData::DEFAULT_DIR_FILTER
|
|
68
|
+
rb_files = []
|
|
69
|
+
rbs_files = []
|
|
45
70
|
argv.each do |path|
|
|
46
71
|
if File.extname(path) == ".rbs"
|
|
47
|
-
|
|
72
|
+
rbs_files << path
|
|
48
73
|
else
|
|
49
|
-
|
|
74
|
+
rb_files << path
|
|
50
75
|
end
|
|
51
76
|
end
|
|
52
77
|
|
|
53
|
-
|
|
78
|
+
puts "typeprof #{ VERSION }" if version
|
|
79
|
+
if rb_files.empty?
|
|
80
|
+
exit if version
|
|
81
|
+
raise OptionParser::InvalidOption.new("no input files")
|
|
82
|
+
end
|
|
54
83
|
|
|
55
|
-
|
|
84
|
+
ConfigData.new(
|
|
85
|
+
rb_files: rb_files,
|
|
86
|
+
rbs_files: rbs_files,
|
|
87
|
+
output: output,
|
|
88
|
+
gem_rbs_features: gem_rbs_features,
|
|
89
|
+
verbose: verbose,
|
|
90
|
+
dir_filter: dir_filter,
|
|
91
|
+
max_sec: max_sec,
|
|
92
|
+
max_iter: max_iter,
|
|
93
|
+
options: options,
|
|
94
|
+
)
|
|
56
95
|
|
|
57
96
|
rescue OptionParser::InvalidOption
|
|
58
97
|
puts $!
|
|
59
98
|
exit
|
|
60
99
|
end
|
|
61
|
-
|
|
62
|
-
attr_reader :verbose, :options, :files
|
|
63
|
-
attr_accessor :output
|
|
64
|
-
|
|
65
|
-
def run
|
|
66
|
-
scratch = Scratch.new
|
|
67
|
-
Builtin.setup_initial_global_env(scratch)
|
|
68
|
-
|
|
69
|
-
prologue_ctx = Context.new(nil, nil, nil)
|
|
70
|
-
prologue_ep = ExecutionPoint.new(prologue_ctx, -1, nil)
|
|
71
|
-
prologue_env = Env.new(StaticEnv.new(:top, Type.nil, false), [], [], Utils::HashWrapper.new({}))
|
|
72
|
-
|
|
73
|
-
@rb_files.each do |path|
|
|
74
|
-
if path == "-"
|
|
75
|
-
iseq = ISeq.compile_str($<.read)
|
|
76
|
-
else
|
|
77
|
-
iseq = ISeq.compile(path)
|
|
78
|
-
end
|
|
79
|
-
ep, env = CLI.starting_state(iseq)
|
|
80
|
-
scratch.merge_env(ep, env)
|
|
81
|
-
scratch.add_callsite!(ep.ctx, nil, prologue_ep, prologue_env) {|ty, ep| }
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
@rbs_files.each do |path|
|
|
85
|
-
RubySignatureImporter.import_rbs_file(scratch, path)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
result = scratch.type_profile
|
|
89
|
-
|
|
90
|
-
if @output
|
|
91
|
-
open(@output, "w") do |output|
|
|
92
|
-
scratch.report(result, output)
|
|
93
|
-
end
|
|
94
|
-
else
|
|
95
|
-
scratch.report(result, $stdout)
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def self.starting_state(iseq)
|
|
100
|
-
cref = CRef.new(:bottom, Type::Builtin[:obj], false) # object
|
|
101
|
-
recv = Type::Instance.new(Type::Builtin[:obj])
|
|
102
|
-
ctx = Context.new(iseq, cref, nil)
|
|
103
|
-
ep = ExecutionPoint.new(ctx, 0, nil)
|
|
104
|
-
locals = [Type.nil] * iseq.locals.size
|
|
105
|
-
env = Env.new(StaticEnv.new(recv, Type.nil, false), locals, [], Utils::HashWrapper.new({}))
|
|
106
|
-
|
|
107
|
-
return ep, env
|
|
108
|
-
end
|
|
109
100
|
end
|
|
110
101
|
end
|