typeprof 0.3.0 → 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/Gemfile.lock +1 -1
- data/doc/demo.md +398 -0
- data/doc/doc.ja.md +4 -0
- data/doc/doc.md +4 -0
- data/lib/typeprof.rb +8 -0
- data/lib/typeprof/analyzer.rb +229 -245
- data/lib/typeprof/arguments.rb +397 -0
- data/lib/typeprof/block.rb +133 -0
- data/lib/typeprof/builtin.rb +14 -10
- data/lib/typeprof/container-type.rb +94 -17
- data/lib/typeprof/export.rb +185 -108
- data/lib/typeprof/import.rb +76 -54
- data/lib/typeprof/iseq.rb +27 -2
- data/lib/typeprof/method.rb +87 -73
- data/lib/typeprof/type.rb +125 -309
- data/lib/typeprof/version.rb +1 -1
- data/smoke/arguments2.rb +1 -1
- 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/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/instance_eval.rb +1 -1
- data/smoke/int_times.rb +1 -1
- data/smoke/multiple-superclass.rb +4 -0
- data/smoke/next2.rb +1 -1
- data/smoke/optional3.rb +10 -0
- data/smoke/proc4.rb +1 -1
- 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-tyvar3.rb +25 -0
- data/smoke/rbs-tyvar3.rbs +4 -0
- data/smoke/rest2.rb +1 -1
- data/smoke/rest5.rb +1 -1
- data/smoke/return.rb +1 -1
- data/smoke/singleton_method.rb +3 -0
- data/smoke/struct.rb +4 -3
- data/smoke/struct3.rb +14 -0
- data/smoke/symbol-proc.rb +24 -0
- metadata +31 -3
- data/smoke/variadic1.rb.notyet +0 -5
data/lib/typeprof/import.rb
CHANGED
|
@@ -264,35 +264,38 @@ module TypeProf
|
|
|
264
264
|
end
|
|
265
265
|
|
|
266
266
|
def conv_method_def(rbs_method_types)
|
|
267
|
-
rbs_method_types.map do |
|
|
268
|
-
|
|
269
|
-
type_params = type.type_params
|
|
270
|
-
|
|
271
|
-
lead_tys = type.type.required_positionals.map {|type| conv_type(type.type) }
|
|
272
|
-
opt_tys = type.type.optional_positionals.map {|type| conv_type(type.type) }
|
|
273
|
-
rest_ty = type.type.rest_positionals
|
|
274
|
-
rest_ty = conv_type(rest_ty.type) if rest_ty
|
|
275
|
-
opt_kw_tys = type.type.optional_keywords.to_h {|key, type| [key, conv_type(type.type)] }
|
|
276
|
-
req_kw_tys = type.type.required_keywords.to_h {|key, type| [key, conv_type(type.type)] }
|
|
277
|
-
rest_kw_ty = type.type.rest_keywords
|
|
278
|
-
raise NotImplementedError if rest_kw_ty # XXX
|
|
279
|
-
|
|
280
|
-
ret_ty = conv_type(type.type.return_type)
|
|
281
|
-
|
|
282
|
-
{
|
|
283
|
-
type_params: type_params,
|
|
284
|
-
lead_tys: lead_tys,
|
|
285
|
-
opt_tys: opt_tys,
|
|
286
|
-
rest_ty: rest_ty,
|
|
287
|
-
req_kw_tys: req_kw_tys,
|
|
288
|
-
opt_kw_tys: opt_kw_tys,
|
|
289
|
-
rest_kw_ty: rest_kw_ty,
|
|
290
|
-
blk: blk,
|
|
291
|
-
ret_ty: ret_ty,
|
|
292
|
-
}
|
|
267
|
+
rbs_method_types.map do |method_type|
|
|
268
|
+
conv_func(method_type.type_params, method_type.type, method_type.block)
|
|
293
269
|
end
|
|
294
270
|
end
|
|
295
271
|
|
|
272
|
+
def conv_func(type_params, func, block)
|
|
273
|
+
blk = block ? conv_block(block) : nil
|
|
274
|
+
|
|
275
|
+
lead_tys = func.required_positionals.map {|type| conv_type(type.type) }
|
|
276
|
+
opt_tys = func.optional_positionals.map {|type| conv_type(type.type) }
|
|
277
|
+
rest_ty = func.rest_positionals
|
|
278
|
+
rest_ty = conv_type(rest_ty.type) if rest_ty
|
|
279
|
+
opt_kw_tys = func.optional_keywords.to_h {|key, type| [key, conv_type(type.type)] }
|
|
280
|
+
req_kw_tys = func.required_keywords.to_h {|key, type| [key, conv_type(type.type)] }
|
|
281
|
+
rest_kw_ty = func.rest_keywords
|
|
282
|
+
raise NotImplementedError if rest_kw_ty # XXX
|
|
283
|
+
|
|
284
|
+
ret_ty = conv_type(func.return_type)
|
|
285
|
+
|
|
286
|
+
{
|
|
287
|
+
type_params: type_params,
|
|
288
|
+
lead_tys: lead_tys,
|
|
289
|
+
opt_tys: opt_tys,
|
|
290
|
+
rest_ty: rest_ty,
|
|
291
|
+
req_kw_tys: req_kw_tys,
|
|
292
|
+
opt_kw_tys: opt_kw_tys,
|
|
293
|
+
rest_kw_ty: rest_kw_ty,
|
|
294
|
+
blk: blk,
|
|
295
|
+
ret_ty: ret_ty,
|
|
296
|
+
}
|
|
297
|
+
end
|
|
298
|
+
|
|
296
299
|
def attr_reader_def(ty)
|
|
297
300
|
[{
|
|
298
301
|
type_params: [],
|
|
@@ -401,8 +404,10 @@ module TypeProf
|
|
|
401
404
|
[:instance, conv_type_name(ty.name)]
|
|
402
405
|
end
|
|
403
406
|
when RBS::Types::Bases::Instance then [:any] # XXX: not implemented yet
|
|
404
|
-
when RBS::Types::Record
|
|
405
|
-
|
|
407
|
+
when RBS::Types::Record
|
|
408
|
+
[:hash_record, [:Hash], ty.fields.map {|key, ty| [key, conv_type(ty)] }]
|
|
409
|
+
when RBS::Types::Proc
|
|
410
|
+
[:proc, conv_func(nil, ty.type, nil)]
|
|
406
411
|
else
|
|
407
412
|
warn "unknown RBS type: %p" % ty.class
|
|
408
413
|
[:any]
|
|
@@ -463,6 +468,7 @@ module TypeProf
|
|
|
463
468
|
when [:Symbol] then Type::Builtin[:sym] = klass
|
|
464
469
|
when [:Array] then Type::Builtin[:ary] = klass
|
|
465
470
|
when [:Hash] then Type::Builtin[:hash] = klass
|
|
471
|
+
when [:Proc] then Type::Builtin[:proc] = klass
|
|
466
472
|
end
|
|
467
473
|
end
|
|
468
474
|
|
|
@@ -505,7 +511,7 @@ module TypeProf
|
|
|
505
511
|
@json[:constants].each do |classpath, value|
|
|
506
512
|
base_klass = path_to_klass(classpath[0..-2])
|
|
507
513
|
value = conv_type(value)
|
|
508
|
-
@scratch.add_constant(base_klass, classpath[-1], value)
|
|
514
|
+
@scratch.add_constant(base_klass, classpath[-1], value, nil)
|
|
509
515
|
end
|
|
510
516
|
|
|
511
517
|
@json[:globals].each do |name, value|
|
|
@@ -517,34 +523,38 @@ module TypeProf
|
|
|
517
523
|
|
|
518
524
|
def conv_method_def(method_name, mdef, rbs_source)
|
|
519
525
|
sig_rets = mdef.flat_map do |sig_ret|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
opt_tys = sig_ret[:opt_tys]
|
|
523
|
-
rest_ty = sig_ret[:rest_ty]
|
|
524
|
-
req_kw_tys = sig_ret[:req_kw_tys]
|
|
525
|
-
opt_kw_tys = sig_ret[:opt_kw_tys]
|
|
526
|
-
rest_kw_ty = sig_ret[:rest_kw_ty]
|
|
527
|
-
blk = sig_ret[:blk]
|
|
528
|
-
ret_ty = sig_ret[:ret_ty]
|
|
526
|
+
conv_func(sig_ret)
|
|
527
|
+
end
|
|
529
528
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
rest_ty = conv_type(rest_ty) if rest_ty
|
|
533
|
-
kw_tys = []
|
|
534
|
-
req_kw_tys.each {|key, ty| kw_tys << [true, key, conv_type(ty)] }
|
|
535
|
-
opt_kw_tys.each {|key, ty| kw_tys << [false, key, conv_type(ty)] }
|
|
536
|
-
kw_rest_ty = conv_type(rest_kw_ty) if rest_kw_ty
|
|
529
|
+
TypedMethodDef.new(sig_rets, rbs_source)
|
|
530
|
+
end
|
|
537
531
|
|
|
538
|
-
|
|
532
|
+
def conv_func(sig_ret)
|
|
533
|
+
#type_params = sig_ret[:type_params] # XXX
|
|
534
|
+
lead_tys = sig_ret[:lead_tys]
|
|
535
|
+
opt_tys = sig_ret[:opt_tys]
|
|
536
|
+
rest_ty = sig_ret[:rest_ty]
|
|
537
|
+
req_kw_tys = sig_ret[:req_kw_tys]
|
|
538
|
+
opt_kw_tys = sig_ret[:opt_kw_tys]
|
|
539
|
+
rest_kw_ty = sig_ret[:rest_kw_ty]
|
|
540
|
+
blk = sig_ret[:blk]
|
|
541
|
+
ret_ty = sig_ret[:ret_ty]
|
|
539
542
|
|
|
540
|
-
|
|
543
|
+
lead_tys = lead_tys.map {|ty| conv_type(ty) }
|
|
544
|
+
opt_tys = opt_tys.map {|ty| conv_type(ty) }
|
|
545
|
+
rest_ty = conv_type(rest_ty) if rest_ty
|
|
546
|
+
kw_tys = []
|
|
547
|
+
req_kw_tys.each {|key, ty| kw_tys << [true, key, conv_type(ty)] }
|
|
548
|
+
opt_kw_tys.each {|key, ty| kw_tys << [false, key, conv_type(ty)] }
|
|
549
|
+
kw_rest_ty = conv_type(rest_kw_ty) if rest_kw_ty
|
|
541
550
|
|
|
542
|
-
|
|
543
|
-
[FormalArguments.new(lead_tys, opt_tys, rest_ty, [], kw_tys, kw_rest_ty, blk), ret_ty]
|
|
544
|
-
end
|
|
545
|
-
end
|
|
551
|
+
blks = conv_block(blk)
|
|
546
552
|
|
|
547
|
-
|
|
553
|
+
ret_ty = conv_type(ret_ty)
|
|
554
|
+
|
|
555
|
+
blks.map do |blk|
|
|
556
|
+
[MethodSignature.new(lead_tys, opt_tys, rest_ty, [], kw_tys, kw_rest_ty, blk), ret_ty]
|
|
557
|
+
end
|
|
548
558
|
end
|
|
549
559
|
|
|
550
560
|
def conv_block(blk)
|
|
@@ -552,9 +562,9 @@ module TypeProf
|
|
|
552
562
|
req, lead_tys, opt_tys, ret_ty = blk
|
|
553
563
|
lead_tys = lead_tys.map {|ty| conv_type(ty) }
|
|
554
564
|
opt_tys = opt_tys.map {|ty| conv_type(ty) }
|
|
555
|
-
|
|
565
|
+
msig = MethodSignature.new(lead_tys, opt_tys, nil, nil, nil, nil, nil)
|
|
556
566
|
ret_ty = conv_type(ret_ty)
|
|
557
|
-
ret = [Type::
|
|
567
|
+
ret = [Type::Proc.new(TypedBlock.new(msig, ret_ty), Type::Builtin[:proc])]
|
|
558
568
|
ret << Type.nil unless req
|
|
559
569
|
ret
|
|
560
570
|
end
|
|
@@ -587,11 +597,23 @@ module TypeProf
|
|
|
587
597
|
v_ty = conv_type(v)
|
|
588
598
|
h[k_ty] = v_ty
|
|
589
599
|
end
|
|
600
|
+
when :hash_record
|
|
601
|
+
_, path, key_tys = ty
|
|
602
|
+
Type.gen_hash(Type::Instance.new(path_to_klass(path))) do |h|
|
|
603
|
+
key_tys.each do |key, ty|
|
|
604
|
+
k_ty = Type::Symbol.new(key, Type::Instance.new(Type::Builtin[:sym]))
|
|
605
|
+
v_ty = conv_type(ty)
|
|
606
|
+
h[k_ty] = v_ty
|
|
607
|
+
end
|
|
608
|
+
end
|
|
590
609
|
when :union
|
|
591
610
|
tys = ty[1]
|
|
592
611
|
Type::Union.new(Utils::Set[*tys.map {|ty2| conv_type(ty2) }], nil) # XXX: Array and Hash support
|
|
593
612
|
when :var
|
|
594
613
|
Type::Var.new(ty[1])
|
|
614
|
+
when :proc
|
|
615
|
+
msig, ret_ty = conv_func(ty[1]).first # Currently, RBS Proc does not accept a block, so the size should be always one
|
|
616
|
+
Type::Proc.new(TypedBlock.new(msig, ret_ty), Type::Instance.new(Type::Builtin[:proc]))
|
|
595
617
|
else
|
|
596
618
|
pp ty
|
|
597
619
|
raise NotImplementedError
|
data/lib/typeprof/iseq.rb
CHANGED
|
@@ -32,7 +32,8 @@ module TypeProf
|
|
|
32
32
|
@name, @path, @absolute_path, @start_lineno, @type,
|
|
33
33
|
@locals, @fargs_format, catch_table, insns = *iseq
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
case @type
|
|
36
|
+
when :method, :block
|
|
36
37
|
if @fargs_format[:opt]
|
|
37
38
|
label = @fargs_format[:opt].last
|
|
38
39
|
i = insns.index(label) + 1
|
|
@@ -45,7 +46,7 @@ module TypeProf
|
|
|
45
46
|
label = insns[i + 1][1]
|
|
46
47
|
i = insns.index(label) + 1
|
|
47
48
|
end
|
|
48
|
-
insns[i, 0] = [[:
|
|
49
|
+
insns[i, 0] = [[:_iseq_body_start]]
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
@insns = []
|
|
@@ -216,6 +217,30 @@ module TypeProf
|
|
|
216
217
|
@insns[j + 1] = [:send_branch, [getlocal_operands, send_operands, branch_operands]]
|
|
217
218
|
end
|
|
218
219
|
|
|
220
|
+
# find a pattern: getlocal, dup, branch
|
|
221
|
+
(@insns.size - 2).times do |i|
|
|
222
|
+
next if branch_targets[i + 1] || branch_targets[i + 2]
|
|
223
|
+
insn0, getlocal_operands = @insns[i]
|
|
224
|
+
insn1, dup_operands = @insns[i + 1]
|
|
225
|
+
insn2, branch_operands = @insns[i + 2]
|
|
226
|
+
if insn0 == :getlocal && insn1 == :dup && insn2 == :branch && getlocal_operands[1] == 0
|
|
227
|
+
@insns[i ] = [:nop]
|
|
228
|
+
@insns[i + 1] = [:nop]
|
|
229
|
+
@insns[i + 2] = [:getlocal_dup_branch, [getlocal_operands, dup_operands, branch_operands]]
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# find a pattern: dup, branch
|
|
234
|
+
(@insns.size - 1).times do |i|
|
|
235
|
+
next if branch_targets[i + 1]
|
|
236
|
+
insn0, dup_operands = @insns[i]
|
|
237
|
+
insn1, branch_operands = @insns[i + 1]
|
|
238
|
+
if insn0 == :dup && insn1 == :branch
|
|
239
|
+
@insns[i ] = [:nop]
|
|
240
|
+
@insns[i + 1] = [:dup_branch, [dup_operands, branch_operands]]
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
219
244
|
# find a pattern: getlocal, branch
|
|
220
245
|
(@insns.size - 1).times do |i|
|
|
221
246
|
next if branch_targets[i + 1]
|
data/lib/typeprof/method.rb
CHANGED
|
@@ -14,21 +14,54 @@ module TypeProf
|
|
|
14
14
|
recv = scratch.globalize_type(recv, caller_env, caller_ep)
|
|
15
15
|
aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
locals = [Type.nil] * @iseq.locals.size
|
|
18
|
+
|
|
19
|
+
blk_ty, start_pcs = aargs.setup_formal_arguments(:method, locals, @iseq.fargs_format)
|
|
20
|
+
if blk_ty.is_a?(String)
|
|
21
|
+
scratch.error(caller_ep, blk_ty)
|
|
22
|
+
ctn[Type.any, caller_ep, caller_env]
|
|
23
|
+
return
|
|
24
|
+
end
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
nctx = Context.new(@iseq, @cref, mid)
|
|
27
|
+
callee_ep = ExecutionPoint.new(nctx, 0, nil)
|
|
28
|
+
nenv = Env.new(StaticEnv.new(recv, blk_ty, false), locals, [], Utils::HashWrapper.new({}))
|
|
29
|
+
alloc_site = AllocationSite.new(callee_ep)
|
|
30
|
+
locals.each_with_index do |ty, i|
|
|
31
|
+
alloc_site2 = alloc_site.add_id(i)
|
|
32
|
+
# nenv is top-level, so it is okay to call Type#localize directly
|
|
33
|
+
nenv, ty = ty.localize(nenv, alloc_site2, Config.options[:type_depth_limit])
|
|
34
|
+
nenv = nenv.local_update(i, ty)
|
|
35
|
+
end
|
|
25
36
|
|
|
26
|
-
|
|
27
|
-
scratch.
|
|
37
|
+
start_pcs.each do |start_pc|
|
|
38
|
+
scratch.merge_env(ExecutionPoint.new(nctx, start_pc, @outer_ep), nenv)
|
|
28
39
|
end
|
|
40
|
+
|
|
41
|
+
scratch.add_iseq_method_call!(self, nctx)
|
|
42
|
+
scratch.add_callsite!(nctx, caller_ep, caller_env, &ctn)
|
|
29
43
|
end
|
|
30
44
|
|
|
31
|
-
def
|
|
45
|
+
def do_check_send(msig, recv, mid, ep, scratch)
|
|
46
|
+
lead_num = @iseq.fargs_format[:lead_num] || 0
|
|
47
|
+
post_num = @iseq.fargs_format[:post_num] || 0
|
|
48
|
+
rest_start = @iseq.fargs_format[:rest_start]
|
|
49
|
+
opt = @iseq.fargs_format[:opt] || [0]
|
|
50
|
+
|
|
51
|
+
# TODO: check keywords
|
|
52
|
+
if rest_start
|
|
53
|
+
# almost ok
|
|
54
|
+
else
|
|
55
|
+
if msig.lead_tys.size + msig.post_tys.size < lead_num + post_num
|
|
56
|
+
scratch.error(ep, "RBS says that the arity may be %d, but the method definition requires at least %d arguments" % [msig.lead_tys.size + msig.post_tys.size, lead_num + post_num])
|
|
57
|
+
return
|
|
58
|
+
end
|
|
59
|
+
if msig.lead_tys.size + msig.opt_tys.size + msig.post_tys.size > lead_num + opt.size - 1 + post_num
|
|
60
|
+
scratch.error(ep, "RBS says that the arity may be %d, but the method definition requires at most %d arguments" % [msig.lead_tys.size + msig.opt_tys.size + msig.post_tys.size, lead_num + opt.size - 1 + post_num])
|
|
61
|
+
return
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
32
65
|
lead_num = @iseq.fargs_format[:lead_num] || 0
|
|
33
66
|
post_start = @iseq.fargs_format[:post_start]
|
|
34
67
|
rest_start = @iseq.fargs_format[:rest_start]
|
|
@@ -37,81 +70,61 @@ module TypeProf
|
|
|
37
70
|
kw_rest = @iseq.fargs_format[:kwrest]
|
|
38
71
|
block_start = @iseq.fargs_format[:block_start]
|
|
39
72
|
|
|
40
|
-
# XXX: need to check .rbs
|
|
73
|
+
# XXX: need to check .rbs msig and .rb fargs
|
|
41
74
|
|
|
42
75
|
ctx = Context.new(@iseq, @cref, mid)
|
|
43
|
-
callee_ep = ExecutionPoint.new(ctx,
|
|
76
|
+
callee_ep = ExecutionPoint.new(ctx, 0, nil)
|
|
44
77
|
|
|
45
78
|
locals = [Type.nil] * @iseq.locals.size
|
|
46
|
-
nenv = Env.new(StaticEnv.new(recv,
|
|
79
|
+
nenv = Env.new(StaticEnv.new(recv, msig.blk_ty, false), locals, [], Utils::HashWrapper.new({}))
|
|
47
80
|
alloc_site = AllocationSite.new(callee_ep)
|
|
48
81
|
idx = 0
|
|
49
|
-
|
|
82
|
+
msig.lead_tys.each_with_index do |ty, i|
|
|
50
83
|
alloc_site2 = alloc_site.add_id(idx += 1)
|
|
51
84
|
# nenv is top-level, so it is okay to call Type#localize directly
|
|
52
85
|
nenv, ty = ty.localize(nenv, alloc_site2, Config.options[:type_depth_limit])
|
|
53
86
|
nenv = nenv.local_update(i, ty)
|
|
54
87
|
end
|
|
55
|
-
if
|
|
56
|
-
|
|
88
|
+
if msig.opt_tys
|
|
89
|
+
msig.opt_tys.each_with_index do |ty, i|
|
|
57
90
|
alloc_site2 = alloc_site.add_id(idx += 1)
|
|
58
91
|
nenv, ty = ty.localize(nenv, alloc_site2, Config.options[:type_depth_limit])
|
|
59
92
|
nenv = nenv.local_update(lead_num + i, ty)
|
|
60
93
|
end
|
|
61
94
|
end
|
|
62
|
-
if
|
|
95
|
+
if msig.rest_ty
|
|
63
96
|
alloc_site2 = alloc_site.add_id(idx += 1)
|
|
64
|
-
ty = Type::Array.new(Type::Array::Elements.new([],
|
|
97
|
+
ty = Type::Array.new(Type::Array::Elements.new([], msig.rest_ty), Type::Instance.new(Type::Builtin[:ary]))
|
|
65
98
|
nenv, rest_ty = ty.localize(nenv, alloc_site2, Config.options[:type_depth_limit])
|
|
66
99
|
nenv = nenv.local_update(rest_start, rest_ty)
|
|
67
100
|
end
|
|
68
|
-
if
|
|
69
|
-
|
|
101
|
+
if msig.post_tys
|
|
102
|
+
msig.post_tys.each_with_index do |ty, i|
|
|
70
103
|
alloc_site2 = alloc_site.add_id(idx += 1)
|
|
71
104
|
nenv, ty = ty.localize(nenv, alloc_site2, Config.options[:type_depth_limit])
|
|
72
105
|
nenv = nenv.local_update(post_start + i, ty)
|
|
73
106
|
end
|
|
74
107
|
end
|
|
75
|
-
if
|
|
76
|
-
|
|
108
|
+
if msig.kw_tys
|
|
109
|
+
msig.kw_tys.each_with_index do |(_, key, ty), i|
|
|
77
110
|
alloc_site2 = alloc_site.add_id(key)
|
|
78
111
|
nenv, ty = ty.localize(nenv, alloc_site2, Config.options[:type_depth_limit])
|
|
79
112
|
nenv = nenv.local_update(kw_start + i, ty)
|
|
80
113
|
end
|
|
81
114
|
end
|
|
82
|
-
if
|
|
83
|
-
ty =
|
|
115
|
+
if msig.kw_rest_ty
|
|
116
|
+
ty = msig.kw_rest_ty
|
|
84
117
|
alloc_site2 = alloc_site.add_id(:**)
|
|
85
118
|
nenv, ty = ty.localize(nenv, alloc_site2, Config.options[:type_depth_limit])
|
|
86
119
|
nenv = nenv.local_update(kw_rest, ty)
|
|
87
120
|
end
|
|
88
|
-
nenv = nenv.local_update(block_start,
|
|
89
|
-
|
|
90
|
-
scratch.merge_env(callee_ep, nenv)
|
|
91
|
-
|
|
92
|
-
callee_ep
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def do_check_send_core(fargs, recv, mid, ep, scratch)
|
|
96
|
-
lead_num = @iseq.fargs_format[:lead_num] || 0
|
|
97
|
-
post_num = @iseq.fargs_format[:post_num] || 0
|
|
98
|
-
rest_start = @iseq.fargs_format[:rest_start]
|
|
99
|
-
opt = @iseq.fargs_format[:opt] || [0]
|
|
121
|
+
nenv = nenv.local_update(block_start, msig.blk_ty) if block_start
|
|
100
122
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# almost ok
|
|
104
|
-
else
|
|
105
|
-
if fargs.lead_tys.size + fargs.post_tys.size < lead_num + post_num
|
|
106
|
-
scratch.error(ep, "RBS says that the arity may be %d, but the method definition requires at least %d arguments" % [fargs.lead_tys.size + fargs.post_tys.size, lead_num + post_num])
|
|
107
|
-
return
|
|
108
|
-
end
|
|
109
|
-
if fargs.lead_tys.size + fargs.opt_tys.size + fargs.post_tys.size > lead_num + opt.size - 1 + post_num
|
|
110
|
-
scratch.error(ep, "RBS says that the arity may be %d, but the method definition requires at most %d arguments" % [fargs.lead_tys.size + fargs.opt_tys.size + fargs.post_tys.size, lead_num + opt.size - 1 + post_num])
|
|
111
|
-
return
|
|
112
|
-
end
|
|
123
|
+
opt.each do |start_pc|
|
|
124
|
+
scratch.merge_env(ExecutionPoint.new(ctx, start_pc, nil), nenv)
|
|
113
125
|
end
|
|
114
|
-
|
|
126
|
+
|
|
127
|
+
ctx
|
|
115
128
|
end
|
|
116
129
|
end
|
|
117
130
|
|
|
@@ -147,8 +160,8 @@ module TypeProf
|
|
|
147
160
|
end
|
|
148
161
|
|
|
149
162
|
class TypedMethodDef < MethodDef
|
|
150
|
-
def initialize(
|
|
151
|
-
@
|
|
163
|
+
def initialize(sig_rets, rbs_source) # sig_rets: Array<[MethodSignature, (return)Type]>
|
|
164
|
+
@sig_rets = sig_rets
|
|
152
165
|
@rbs_source = rbs_source
|
|
153
166
|
end
|
|
154
167
|
|
|
@@ -158,12 +171,12 @@ module TypeProf
|
|
|
158
171
|
recv = scratch.globalize_type(recv_orig, caller_env, caller_ep)
|
|
159
172
|
found = false
|
|
160
173
|
aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
|
|
161
|
-
@
|
|
174
|
+
@sig_rets.each do |msig, ret_ty|
|
|
162
175
|
ncaller_env = caller_env
|
|
163
|
-
#pp [mid, aargs,
|
|
164
|
-
# XXX: support self type in
|
|
176
|
+
#pp [mid, aargs, msig]
|
|
177
|
+
# XXX: support self type in msig
|
|
165
178
|
subst = { Type::Var.new(:self) => recv }
|
|
166
|
-
next unless aargs.
|
|
179
|
+
next unless aargs.consistent_with_method_signature?(msig, subst)
|
|
167
180
|
case
|
|
168
181
|
when recv.is_a?(Type::Cell) && recv_orig.is_a?(Type::LocalCell)
|
|
169
182
|
tyvars = recv.base_type.klass.type_params.map {|name,| Type::Var.new(name) }
|
|
@@ -171,12 +184,12 @@ module TypeProf
|
|
|
171
184
|
ty = subst[tyvar]
|
|
172
185
|
if ty
|
|
173
186
|
ncaller_env, ty = scratch.localize_type(ty, ncaller_env, caller_ep)
|
|
174
|
-
ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id) do |elems|
|
|
175
|
-
|
|
187
|
+
ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id, recv_orig.base_type) do |elems|
|
|
188
|
+
elems.update(idx, ty)
|
|
176
189
|
end
|
|
177
190
|
end
|
|
178
191
|
end
|
|
179
|
-
tyvars.zip(recv.elems) do |tyvar, elem|
|
|
192
|
+
tyvars.zip(recv.elems.elems) do |tyvar, elem|
|
|
180
193
|
if subst[tyvar]
|
|
181
194
|
subst[tyvar] = subst[tyvar].union(elem)
|
|
182
195
|
else
|
|
@@ -188,11 +201,11 @@ module TypeProf
|
|
|
188
201
|
if subst[tyvar_elem]
|
|
189
202
|
ty = subst[tyvar_elem]
|
|
190
203
|
ncaller_env, ty = scratch.localize_type(ty, ncaller_env, caller_ep)
|
|
191
|
-
ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id) do |elems|
|
|
204
|
+
ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id, recv_orig.base_type) do |elems|
|
|
192
205
|
elems.update(nil, ty)
|
|
193
206
|
end
|
|
194
207
|
end
|
|
195
|
-
subst.merge!({ tyvar_elem => recv.elems.
|
|
208
|
+
subst.merge!({ tyvar_elem => recv.elems.squash_or_any })
|
|
196
209
|
when recv.is_a?(Type::Hash) && recv_orig.is_a?(Type::LocalHash)
|
|
197
210
|
tyvar_k = Type::Var.new(:K)
|
|
198
211
|
tyvar_v = Type::Var.new(:V)
|
|
@@ -203,18 +216,19 @@ module TypeProf
|
|
|
203
216
|
end
|
|
204
217
|
ret_ty = ret_ty.substitute(subst, Config.options[:type_depth_limit])
|
|
205
218
|
found = true
|
|
206
|
-
if aargs.blk_ty.is_a?(Type::
|
|
219
|
+
if aargs.blk_ty.is_a?(Type::Proc)
|
|
220
|
+
#raise NotImplementedError unless aargs.blk_ty.block_body.is_a?(ISeqBlock) # XXX
|
|
207
221
|
dummy_ctx = TypedContext.new(caller_ep, mid)
|
|
208
222
|
dummy_ep = ExecutionPoint.new(dummy_ctx, -1, caller_ep)
|
|
209
|
-
dummy_env = Env.new(StaticEnv.new(recv,
|
|
210
|
-
if
|
|
223
|
+
dummy_env = Env.new(StaticEnv.new(recv, msig.blk_ty, false), [], [], Utils::HashWrapper.new({}))
|
|
224
|
+
if msig.blk_ty.is_a?(Type::Proc)
|
|
211
225
|
scratch.add_callsite!(dummy_ctx, caller_ep, ncaller_env, &ctn)
|
|
212
|
-
nfargs =
|
|
226
|
+
nfargs = msig.blk_ty.block_body.msig
|
|
213
227
|
alloc_site = AllocationSite.new(caller_ep).add_id(self)
|
|
214
228
|
nlead_tys = (nfargs.lead_tys + nfargs.opt_tys).map.with_index do |ty, i|
|
|
215
229
|
if recv.is_a?(Type::Array)
|
|
216
230
|
tyvar_elem = Type::Var.new(:Elem)
|
|
217
|
-
ty = ty.substitute(subst.merge({ tyvar_elem => recv.elems.
|
|
231
|
+
ty = ty.substitute(subst.merge({ tyvar_elem => recv.elems.squash_or_any }), Config.options[:type_depth_limit])
|
|
218
232
|
else
|
|
219
233
|
ty = ty.substitute(subst, Config.options[:type_depth_limit])
|
|
220
234
|
end
|
|
@@ -225,13 +239,13 @@ module TypeProf
|
|
|
225
239
|
end
|
|
226
240
|
0.upto(nfargs.opt_tys.size) do |n|
|
|
227
241
|
naargs = ActualArguments.new(nlead_tys[0, nfargs.lead_tys.size + n], nil, {}, Type.nil) # XXX: support block to block?
|
|
228
|
-
scratch.do_invoke_block(
|
|
242
|
+
scratch.do_invoke_block(aargs.blk_ty, naargs, dummy_ep, dummy_env) do |blk_ret_ty, _ep, _env|
|
|
229
243
|
subst2 = {}
|
|
230
|
-
if blk_ret_ty.consistent?(
|
|
244
|
+
if blk_ret_ty.consistent?(msig.blk_ty.block_body.ret_ty, subst2)
|
|
231
245
|
if recv.is_a?(Type::Array) && recv_orig.is_a?(Type::LocalArray)
|
|
232
246
|
tyvar_elem = Type::Var.new(:Elem)
|
|
233
247
|
if subst2[tyvar_elem]
|
|
234
|
-
ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id) do |elems|
|
|
248
|
+
ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id, recv_orig.base_type) do |elems|
|
|
235
249
|
elems.update(nil, subst2[tyvar_elem])
|
|
236
250
|
end
|
|
237
251
|
scratch.merge_return_env(caller_ep) {|env| env ? env.merge(ncaller_env) : ncaller_env }
|
|
@@ -247,10 +261,10 @@ module TypeProf
|
|
|
247
261
|
end
|
|
248
262
|
ret_ty = ret_ty.remove_type_vars
|
|
249
263
|
# XXX: check the return type from the block
|
|
250
|
-
# sig.blk_ty.ret_ty.eql?(_ret_ty) ???
|
|
251
|
-
scratch.
|
|
264
|
+
# sig.blk_ty.block_body.ret_ty.eql?(_ret_ty) ???
|
|
265
|
+
scratch.add_return_value!(dummy_ctx, ret_ty)
|
|
252
266
|
end
|
|
253
|
-
# scratch.
|
|
267
|
+
# scratch.add_return_value!(dummy_ctx, ret_ty) ?
|
|
254
268
|
# This makes `def foo; 1.times { return "str" }; end` return Integer|String
|
|
255
269
|
end
|
|
256
270
|
else
|
|
@@ -273,8 +287,8 @@ module TypeProf
|
|
|
273
287
|
|
|
274
288
|
def do_match_iseq_mdef(iseq_mdef, recv, mid, env, ep, scratch)
|
|
275
289
|
recv = scratch.globalize_type(recv, env, ep)
|
|
276
|
-
@
|
|
277
|
-
iseq_mdef.
|
|
290
|
+
@sig_rets.each do |msig, _ret_ty|
|
|
291
|
+
iseq_mdef.do_check_send(msig, recv, mid, ep, scratch)
|
|
278
292
|
end
|
|
279
293
|
end
|
|
280
294
|
end
|