typeprof 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -2
- data/Gemfile.lock +1 -1
- data/README.md +6 -0
- data/lib/typeprof/analyzer.rb +67 -28
- data/lib/typeprof/arguments.rb +27 -19
- data/lib/typeprof/block.rb +5 -2
- data/lib/typeprof/builtin.rb +8 -2
- data/lib/typeprof/container-type.rb +104 -97
- data/lib/typeprof/import.rb +16 -8
- data/lib/typeprof/method.rb +70 -12
- data/lib/typeprof/type.rb +103 -88
- data/lib/typeprof/version.rb +1 -1
- data/smoke/arguments2.rb +1 -1
- data/smoke/block-kwarg.rb +1 -1
- data/smoke/block10.rb +1 -1
- 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/ivar2.rb +1 -1
- data/smoke/keyword4.rb +1 -1
- data/smoke/kwsplat1.rb +1 -1
- data/smoke/kwsplat2.rb +1 -1
- data/smoke/pattern-match1.rb +23 -0
- data/smoke/pattern-match2.rb +15 -0
- data/smoke/rbs-tyvar3.rb +11 -19
- data/smoke/rbs-tyvar3.rbs +4 -3
- data/smoke/rbs-tyvar4.rb +36 -0
- data/smoke/rbs-tyvar5.rb +12 -0
- data/smoke/rbs-tyvar5.rbs +8 -0
- data/smoke/uninitialize-var.rb +12 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1cf845328dbfd7b8dc14113c986be27a28457153d4e3b470ca45341035bdff7
|
4
|
+
data.tar.gz: 7e1aa96c7623832dc63e0d60573c28deeb0112c31921d63752553dcbf8127fde
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40e5f8da50d3b31dc96f2b010275083d9907c7510d16afc1f86b23114196a30c8170b9fc77cb8d8e1de0a7ba0b14a5deaf143450f3541e007a56a9170ce7ed93
|
7
|
+
data.tar.gz: 3fd01d2edc108f2ce262af023886fa04c8e2cbc6e98647dad238954428a188aa4637913c2e7f13c983deeb4ac6ff7b3dc3489acc740effcbddbd128519135662
|
data/.github/workflows/main.yml
CHANGED
@@ -17,9 +17,8 @@ jobs:
|
|
17
17
|
uses: ruby/setup-ruby@v1
|
18
18
|
with:
|
19
19
|
ruby-version: ${{ matrix.ruby-version }}
|
20
|
-
- name:
|
20
|
+
- name: Bundle install
|
21
21
|
run: |
|
22
|
-
cd rbs && bundle install && bundle exec rake parser && cd ..
|
23
22
|
bundle install
|
24
23
|
- name: Run the test suite
|
25
24
|
run: |
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
data/lib/typeprof/analyzer.rb
CHANGED
@@ -87,6 +87,11 @@ module TypeProf
|
|
87
87
|
@recv_ty = recv_ty
|
88
88
|
@blk_ty = blk_ty
|
89
89
|
@mod_func = mod_func
|
90
|
+
|
91
|
+
return if recv_ty == :top #OK
|
92
|
+
recv_ty.each_child_global do |ty|
|
93
|
+
raise ty.inspect if !ty.is_a?(Type::Instance) && !ty.is_a?(Type::Class) && ty != Type.any
|
94
|
+
end
|
90
95
|
end
|
91
96
|
|
92
97
|
attr_reader :recv_ty, :blk_ty, :mod_func
|
@@ -129,11 +134,7 @@ module TypeProf
|
|
129
134
|
elems2 = type_params[id]
|
130
135
|
if elems2
|
131
136
|
if elems != elems2
|
132
|
-
|
133
|
-
type_params[id] = elems.zip(elems2).map {|elem1, elem2| elem1.union(elem2) }
|
134
|
-
else
|
135
|
-
type_params[id] = elems.union(elems2)
|
136
|
-
end
|
137
|
+
type_params[id] = elems.union(elems2)
|
137
138
|
end
|
138
139
|
else
|
139
140
|
type_params[id] = elems
|
@@ -151,6 +152,8 @@ module TypeProf
|
|
151
152
|
tys.each do |ty|
|
152
153
|
raise "nil cannot be pushed to the stack" if ty.nil?
|
153
154
|
ty.each_child do |ty|
|
155
|
+
raise if ty.is_a?(Type::Var)
|
156
|
+
#raise if ty.is_a?(Type::Instance) && ty.klass.type_params.size > 1
|
154
157
|
raise "Array cannot be pushed to the stack" if ty.is_a?(Type::Array)
|
155
158
|
raise "Hash cannot be pushed to the stack" if ty.is_a?(Type::Hash)
|
156
159
|
end
|
@@ -572,9 +575,7 @@ module TypeProf
|
|
572
575
|
|
573
576
|
ret_ty = @return_values[callee_ctx] ||= Type.bot
|
574
577
|
if ret_ty != Type.bot
|
575
|
-
|
576
|
-
ctn[ret_ty, caller_ep, @return_envs[caller_ep]]
|
577
|
-
end
|
578
|
+
ctn[ret_ty, caller_ep, @return_envs[caller_ep]]
|
578
579
|
end
|
579
580
|
end
|
580
581
|
|
@@ -632,7 +633,7 @@ module TypeProf
|
|
632
633
|
entry = @tbl[site] ||= Entry.new(!ep, {}, Type.bot, Utils::MutableSet.new)
|
633
634
|
if ep
|
634
635
|
if entry.rbs_declared
|
635
|
-
|
636
|
+
unless Type.match?(ty, entry.type)
|
636
637
|
scratch.warn(ep, "inconsistent assignment to RBS-declared global variable")
|
637
638
|
return
|
638
639
|
end
|
@@ -651,6 +652,7 @@ module TypeProf
|
|
651
652
|
end
|
652
653
|
|
653
654
|
def get_ivar(recv)
|
655
|
+
recv = recv.base_type while recv.respond_to?(:base_type)
|
654
656
|
case recv
|
655
657
|
when Type::Class
|
656
658
|
[@class_defs[recv.idx], true]
|
@@ -884,26 +886,41 @@ module TypeProf
|
|
884
886
|
def pend_method_execution(iseq, meth, recv, mid, cref)
|
885
887
|
ctx = Context.new(iseq, cref, mid)
|
886
888
|
ep = ExecutionPoint.new(ctx, 0, nil)
|
887
|
-
locals = [Type.
|
888
|
-
|
889
|
-
|
889
|
+
locals = [Type.nil] * iseq.locals.size
|
890
|
+
|
891
|
+
fargs_format = iseq.fargs_format
|
892
|
+
lead_num = fargs_format[:lead_num] || 0
|
893
|
+
post_num = fargs_format[:post_num] || 0
|
894
|
+
post_index = fargs_format[:post_start]
|
895
|
+
rest_index = fargs_format[:rest_start]
|
896
|
+
keyword = fargs_format[:keyword]
|
897
|
+
kw_index = fargs_format[:kwbits] - keyword.size if keyword
|
898
|
+
kwrest_index = fargs_format[:kwrest]
|
899
|
+
block_index = fargs_format[:block_start]
|
900
|
+
opt = fargs_format[:opt] || [0]
|
901
|
+
|
902
|
+
(lead_num + opt.size - 1).times {|i| locals[i] = Type.any }
|
903
|
+
post_num.times {|i| locals[i + post_index] = Type.any } if post_index
|
904
|
+
locals[rest_index] = Type.any if rest_index
|
890
905
|
if keyword
|
891
|
-
kw_start = iseq.fargs_format[:kwbits]
|
892
|
-
kw_start -= iseq.fargs_format[:keyword].size if kw_start
|
893
906
|
keyword.each_with_index do |kw, i|
|
894
907
|
case
|
895
908
|
when kw.is_a?(Symbol) # required keyword
|
909
|
+
locals[kw_index + i] = Type.any
|
896
910
|
when kw.size == 2 # optional keyword (default value is a literal)
|
897
911
|
_key, default_ty = *kw
|
898
912
|
default_ty = Type.guess_literal_type(default_ty)
|
899
|
-
default_ty = default_ty.
|
900
|
-
locals[
|
913
|
+
default_ty = default_ty.base_type if default_ty.is_a?(Type::Literal)
|
914
|
+
locals[kw_index + i] = default_ty.union(Type.any)
|
901
915
|
else # optional keyword (default value is an expression)
|
916
|
+
locals[kw_index + i] = Type.any
|
902
917
|
end
|
903
918
|
end
|
904
919
|
end
|
920
|
+
locals[kwrest_index] = Type.any if kwrest_index
|
921
|
+
locals[block_index] = Type.nil if block_index
|
905
922
|
|
906
|
-
env = Env.new(StaticEnv.new(recv, Type.
|
923
|
+
env = Env.new(StaticEnv.new(recv, Type.nil, false), locals, [], Utils::HashWrapper.new({}))
|
907
924
|
|
908
925
|
@pending_execution[iseq] ||= [:method, [meth, ep, env]]
|
909
926
|
end
|
@@ -986,7 +1003,7 @@ module TypeProf
|
|
986
1003
|
when kw.size == 2 # optional keyword (default value is a literal)
|
987
1004
|
key, default_ty = *kw
|
988
1005
|
default_ty = Type.guess_literal_type(default_ty)
|
989
|
-
default_ty = default_ty.
|
1006
|
+
default_ty = default_ty.base_type if default_ty.is_a?(Type::Literal)
|
990
1007
|
req = false
|
991
1008
|
else # optional keyword (default value is an expression)
|
992
1009
|
key, = kw
|
@@ -1029,7 +1046,17 @@ module TypeProf
|
|
1029
1046
|
ty = Type::Literal.new(str, Type::Instance.new(Type::Builtin[:str]))
|
1030
1047
|
env = env.push(ty)
|
1031
1048
|
when :putself
|
1032
|
-
|
1049
|
+
ty = env.static_env.recv_ty
|
1050
|
+
if ty.is_a?(Type::Instance)
|
1051
|
+
klass = ty.klass
|
1052
|
+
if klass.type_params.size >= 1
|
1053
|
+
ty = Type::ContainerType.create_empty_instance(klass)
|
1054
|
+
env, ty = localize_type(ty, env, ep, AllocationSite.new(ep))
|
1055
|
+
else
|
1056
|
+
ty = Type::Instance.new(klass)
|
1057
|
+
end
|
1058
|
+
env, ty = localize_type(ty, env, ep)
|
1059
|
+
end
|
1033
1060
|
env = env.push(ty)
|
1034
1061
|
when :newarray, :newarraykwsplat
|
1035
1062
|
len, = operands
|
@@ -1700,15 +1727,27 @@ module TypeProf
|
|
1700
1727
|
end
|
1701
1728
|
|
1702
1729
|
when :checktype
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
if res
|
1709
|
-
ty = Type::Instance.new(Type::Builtin[:true])
|
1730
|
+
kind, = operands
|
1731
|
+
case kind
|
1732
|
+
when 5 then klass = :str # T_STRING
|
1733
|
+
when 7 then klass = :ary # T_ARRAY
|
1734
|
+
when 8 then klass = :hash # T_HASH
|
1710
1735
|
else
|
1711
|
-
|
1736
|
+
raise NotImplementedError
|
1737
|
+
end
|
1738
|
+
env, (val,) = env.pop(1)
|
1739
|
+
ty = Type.bot
|
1740
|
+
val.each_child do |val|
|
1741
|
+
#globalize_type(val, env, ep).each_child_global do |val|
|
1742
|
+
val = val.base_type while val.respond_to?(:base_type)
|
1743
|
+
case val
|
1744
|
+
when Type::Instance.new(Type::Builtin[klass])
|
1745
|
+
ty = ty.union(Type::Instance.new(Type::Builtin[:true]))
|
1746
|
+
when Type.any
|
1747
|
+
ty = Type.bool
|
1748
|
+
else
|
1749
|
+
ty = ty.union(Type::Instance.new(Type::Builtin[:false]))
|
1750
|
+
end
|
1712
1751
|
end
|
1713
1752
|
env = env.push(ty)
|
1714
1753
|
else
|
@@ -1946,7 +1985,7 @@ module TypeProf
|
|
1946
1985
|
end
|
1947
1986
|
end
|
1948
1987
|
|
1949
|
-
@block_to_ctx[blk.block_body]
|
1988
|
+
@block_to_ctx[blk.block_body]&.each do |blk_ctx|
|
1950
1989
|
ret_ty = ret_ty.union(@return_values[blk_ctx]) if @return_values[blk_ctx]
|
1951
1990
|
end
|
1952
1991
|
end
|
data/lib/typeprof/arguments.rb
CHANGED
@@ -25,7 +25,7 @@ module TypeProf
|
|
25
25
|
self
|
26
26
|
end
|
27
27
|
|
28
|
-
def consistent_with_method_signature?(msig
|
28
|
+
def consistent_with_method_signature?(msig)
|
29
29
|
aargs = @lead_tys.dup
|
30
30
|
|
31
31
|
# aargs: lead_tys, rest_ty
|
@@ -36,53 +36,61 @@ module TypeProf
|
|
36
36
|
(lower_bound..upper_bound).each do |n|
|
37
37
|
# BUG: @rest_ty is an Array, so need to squash
|
38
38
|
tmp_aargs = ActualArguments.new(@lead_tys + [@rest_ty] * n, nil, @kw_tys, @blk_ty)
|
39
|
-
|
40
|
-
|
41
|
-
end
|
39
|
+
subst = tmp_aargs.consistent_with_method_signature?(msig) # XXX: wrong subst handling in the loop!
|
40
|
+
return subst if subst
|
42
41
|
end
|
43
|
-
return
|
42
|
+
return nil
|
44
43
|
end
|
45
44
|
|
45
|
+
subst = {}
|
46
46
|
if msig.rest_ty
|
47
|
-
return
|
47
|
+
return nil if aargs.size < msig.lead_tys.size + msig.post_tys.size
|
48
48
|
aargs.shift(msig.lead_tys.size).zip(msig.lead_tys) do |aarg, farg|
|
49
|
-
return
|
49
|
+
return nil unless subst2 = Type.match?(aarg, farg)
|
50
|
+
subst = Type.merge_substitution(subst, subst2)
|
50
51
|
end
|
51
52
|
aargs.pop(msig.post_tys.size).zip(msig.post_tys) do |aarg, farg|
|
52
|
-
return
|
53
|
+
return nil unless subst2 = Type.match?(aarg, farg)
|
54
|
+
subst = Type.merge_substitution(subst, subst2)
|
53
55
|
end
|
54
56
|
msig.opt_tys.each do |farg|
|
55
57
|
aarg = aargs.shift
|
56
|
-
return
|
58
|
+
return nil unless subst2 = Type.match?(aarg, farg)
|
59
|
+
subst = Type.merge_substitution(subst, subst2)
|
57
60
|
end
|
58
61
|
aargs.each do |aarg|
|
59
|
-
return
|
62
|
+
return nil unless subst2 = Type.match?(aarg, msig.rest_ty)
|
63
|
+
subst = Type.merge_substitution(subst, subst2)
|
60
64
|
end
|
61
65
|
else
|
62
|
-
return
|
63
|
-
return
|
66
|
+
return nil if aargs.size < msig.lead_tys.size + msig.post_tys.size
|
67
|
+
return nil if aargs.size > msig.lead_tys.size + msig.post_tys.size + msig.opt_tys.size
|
64
68
|
aargs.shift(msig.lead_tys.size).zip(msig.lead_tys) do |aarg, farg|
|
65
|
-
return
|
69
|
+
return nil unless subst2 = Type.match?(aarg, farg)
|
70
|
+
subst = Type.merge_substitution(subst, subst2)
|
66
71
|
end
|
67
72
|
aargs.pop(msig.post_tys.size).zip(msig.post_tys) do |aarg, farg|
|
68
|
-
return
|
73
|
+
return nil unless subst2 = Type.match?(aarg, farg)
|
74
|
+
subst = Type.merge_substitution(subst, subst2)
|
69
75
|
end
|
70
76
|
aargs.zip(msig.opt_tys) do |aarg, farg|
|
71
|
-
return
|
77
|
+
return nil unless subst2 = Type.match?(aarg, farg)
|
78
|
+
subst = Type.merge_substitution(subst, subst2)
|
72
79
|
end
|
73
80
|
end
|
74
81
|
# XXX: msig.keyword_tys
|
75
82
|
|
76
83
|
case msig.blk_ty
|
77
84
|
when Type::Proc
|
78
|
-
return
|
85
|
+
return nil if @blk_ty == Type.nil
|
79
86
|
when Type.nil
|
80
|
-
return
|
87
|
+
return nil if @blk_ty != Type.nil
|
81
88
|
when Type::Any
|
82
89
|
else
|
83
90
|
raise "unknown type of formal block signature"
|
84
91
|
end
|
85
|
-
|
92
|
+
|
93
|
+
subst
|
86
94
|
end
|
87
95
|
|
88
96
|
def argument_error(given, exp_lower, exp_upper)
|
@@ -345,7 +353,7 @@ module TypeProf
|
|
345
353
|
when kw.size == 2 # optional keyword (default value is a literal)
|
346
354
|
key, default_ty = *kw
|
347
355
|
default_ty = Type.guess_literal_type(default_ty)
|
348
|
-
default_ty = default_ty.
|
356
|
+
default_ty = default_ty.base_type if default_ty.is_a?(Type::Literal)
|
349
357
|
req = false
|
350
358
|
else # optional keyword (default value is an expression)
|
351
359
|
key, = kw
|
data/lib/typeprof/block.rb
CHANGED
@@ -85,10 +85,13 @@ module TypeProf
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, &ctn)
|
88
|
-
|
89
|
-
|
88
|
+
aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
|
89
|
+
subst = aargs.consistent_with_method_signature?(@msig)
|
90
|
+
unless subst
|
90
91
|
scratch.warn(caller_ep, "The arguments is not compatibile to RBS block")
|
91
92
|
end
|
93
|
+
# check?
|
94
|
+
#subst = { Type::Var.new(:self) => caller_env.static_env.recv_ty }
|
92
95
|
# XXX: Update type vars
|
93
96
|
ctn[@ret_ty, caller_ep, caller_env]
|
94
97
|
end
|
data/lib/typeprof/builtin.rb
CHANGED
@@ -54,6 +54,10 @@ module TypeProf
|
|
54
54
|
ctn[ret_ty, ep, env]
|
55
55
|
end
|
56
56
|
|
57
|
+
def vmcore_raise(recv, mid, aargs, ep, env, scratch, &ctn)
|
58
|
+
# no-op
|
59
|
+
end
|
60
|
+
|
57
61
|
def lambda(recv, mid, aargs, ep, env, scratch, &ctn)
|
58
62
|
ctn[aargs.blk_ty, ep, env]
|
59
63
|
end
|
@@ -63,10 +67,11 @@ module TypeProf
|
|
63
67
|
end
|
64
68
|
|
65
69
|
def object_s_new(recv, mid, aargs, ep, env, scratch, &ctn)
|
66
|
-
ty = Type::Instance.new(recv)
|
67
70
|
if recv.type_params.size >= 1
|
68
|
-
ty = Type::
|
71
|
+
ty = Type::ContainerType.create_empty_instance(recv)
|
69
72
|
env, ty = scratch.localize_type(ty, env, ep, AllocationSite.new(ep).add_id(:object_s_new))
|
73
|
+
else
|
74
|
+
ty = Type::Instance.new(recv)
|
70
75
|
end
|
71
76
|
meths = scratch.get_method(recv, false, :initialize)
|
72
77
|
meths.flat_map do |meth|
|
@@ -520,6 +525,7 @@ module TypeProf
|
|
520
525
|
scratch.set_custom_method(klass_vmcore, :"core#set_method_alias", Builtin.method(:vmcore_set_method_alias))
|
521
526
|
scratch.set_custom_method(klass_vmcore, :"core#undef_method", Builtin.method(:vmcore_undef_method))
|
522
527
|
scratch.set_custom_method(klass_vmcore, :"core#hash_merge_kwd", Builtin.method(:vmcore_hash_merge_kwd))
|
528
|
+
scratch.set_custom_method(klass_vmcore, :"core#raise", Builtin.method(:vmcore_raise))
|
523
529
|
scratch.set_custom_method(klass_vmcore, :lambda, Builtin.method(:lambda))
|
524
530
|
scratch.set_singleton_custom_method(klass_obj, :"new", Builtin.method(:object_s_new))
|
525
531
|
scratch.set_singleton_custom_method(klass_obj, :"attr_accessor", Builtin.method(:module_attr_accessor))
|
@@ -19,13 +19,44 @@ module TypeProf
|
|
19
19
|
# Cell, Array, and Hash are types for global interface, e.g., TypedISeq.
|
20
20
|
# Do not push such types to local environment, stack, etc.
|
21
21
|
|
22
|
+
class ContainerType < Type
|
23
|
+
def match?(other)
|
24
|
+
return nil if self.class != other.class
|
25
|
+
return nil unless @base_type.consistent?(other.base_type)
|
26
|
+
@elems.match?(other.elems)
|
27
|
+
end
|
28
|
+
|
29
|
+
def each_free_type_variable(&blk)
|
30
|
+
@elems.each_free_type_variable(&blk)
|
31
|
+
end
|
32
|
+
|
33
|
+
def consistent?(other)
|
34
|
+
raise "must not be used"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.create_empty_instance(klass)
|
38
|
+
base_type = Type::Instance.new(klass)
|
39
|
+
case klass
|
40
|
+
when Type::Builtin[:ary] # XXX: check inheritance...
|
41
|
+
Type::Array.new(Type::Array::Elements.new([], Type.bot), base_type)
|
42
|
+
when Type::Builtin[:hash]
|
43
|
+
Type.gen_hash(base_type) {|h| }
|
44
|
+
else
|
45
|
+
Type::Cell.new(Type::Cell::Elements.new([Type.bot] * klass.type_params.size), base_type)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
22
50
|
# The most basic container type for default type parameter class
|
23
|
-
class Cell <
|
51
|
+
class Cell < ContainerType
|
24
52
|
def initialize(elems, base_type)
|
25
53
|
raise if !elems.is_a?(Cell::Elements)
|
26
54
|
@elems = elems # Cell::Elements
|
27
55
|
raise unless base_type
|
28
56
|
@base_type = base_type
|
57
|
+
if base_type.klass.type_params.size != elems.elems.size
|
58
|
+
raise
|
59
|
+
end
|
29
60
|
end
|
30
61
|
|
31
62
|
attr_reader :elems, :base_type
|
@@ -44,7 +75,7 @@ module TypeProf
|
|
44
75
|
|
45
76
|
def localize(env, alloc_site, depth)
|
46
77
|
return env, Type.any if depth <= 0
|
47
|
-
alloc_site = alloc_site.add_id(:cell)
|
78
|
+
alloc_site = alloc_site.add_id(:cell).add_id(@base_type)
|
48
79
|
env, elems = @elems.localize(env, alloc_site, depth)
|
49
80
|
env.deploy_type(LocalCell, alloc_site, elems, @base_type)
|
50
81
|
end
|
@@ -58,31 +89,13 @@ module TypeProf
|
|
58
89
|
raise
|
59
90
|
end
|
60
91
|
|
61
|
-
def consistent?(other, subst)
|
62
|
-
case other
|
63
|
-
when Type::Any then true
|
64
|
-
when Type::Var then other.add_subst!(self, subst)
|
65
|
-
when Type::Union
|
66
|
-
other.types.each do |ty2|
|
67
|
-
return true if consistent?(ty2, subst)
|
68
|
-
end
|
69
|
-
return false
|
70
|
-
when Type::Cell
|
71
|
-
@elems.size == other.elems.size &&
|
72
|
-
@base_type.consistent?(other.base_type, subst) &&
|
73
|
-
@elems.zip(other.elems).all? {|elem1, elem2| elem1..consistent?(elem2, subst) }
|
74
|
-
else
|
75
|
-
self == other
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
92
|
def substitute(subst, depth)
|
80
93
|
return Type.any if depth <= 0
|
81
94
|
elems = @elems.substitute(subst, depth)
|
82
95
|
Cell.new(elems, @base_type)
|
83
96
|
end
|
84
97
|
|
85
|
-
class Elements
|
98
|
+
class Elements # Cell
|
86
99
|
include Utils::StructuralEquality
|
87
100
|
|
88
101
|
def initialize(elems)
|
@@ -124,12 +137,21 @@ module TypeProf
|
|
124
137
|
end
|
125
138
|
end
|
126
139
|
|
127
|
-
def
|
128
|
-
|
140
|
+
def match?(other)
|
141
|
+
return nil if @elems.size != other.elems.size
|
142
|
+
subst = nil
|
129
143
|
@elems.zip(other.elems) do |ty0, ty1|
|
130
|
-
|
144
|
+
subst2 = Type.match?(ty0, ty1)
|
145
|
+
return nil unless subst2
|
146
|
+
subst = Type.merge_substitution(subst, subst2)
|
147
|
+
end
|
148
|
+
subst
|
149
|
+
end
|
150
|
+
|
151
|
+
def each_free_type_variable(&blk)
|
152
|
+
@elems.each do |ty|
|
153
|
+
ty.each_free_type_variable(&blk)
|
131
154
|
end
|
132
|
-
return true
|
133
155
|
end
|
134
156
|
|
135
157
|
def substitute(subst, depth)
|
@@ -146,6 +168,9 @@ module TypeProf
|
|
146
168
|
|
147
169
|
def union(other)
|
148
170
|
return self if self == other
|
171
|
+
if @elems.size != other.elems.size
|
172
|
+
raise "#{ @elems.size } != #{ other.elems.size }"
|
173
|
+
end
|
149
174
|
elems = []
|
150
175
|
@elems.zip(other.elems) do |ty0, ty1|
|
151
176
|
elems << ty0.union(ty1)
|
@@ -155,7 +180,7 @@ module TypeProf
|
|
155
180
|
end
|
156
181
|
end
|
157
182
|
|
158
|
-
class LocalCell <
|
183
|
+
class LocalCell < ContainerType
|
159
184
|
def initialize(id, base_type)
|
160
185
|
@id = id
|
161
186
|
raise unless base_type
|
@@ -184,6 +209,7 @@ module TypeProf
|
|
184
209
|
else
|
185
210
|
elems = Cell::Elements.new([]) # XXX
|
186
211
|
end
|
212
|
+
visited.delete(self)
|
187
213
|
Cell.new(elems, @base_type)
|
188
214
|
end
|
189
215
|
end
|
@@ -191,14 +217,10 @@ module TypeProf
|
|
191
217
|
def get_method(mid, scratch)
|
192
218
|
@base_type.get_method(mid, scratch)
|
193
219
|
end
|
194
|
-
|
195
|
-
def consistent?(other, subst)
|
196
|
-
raise "must not be used"
|
197
|
-
end
|
198
220
|
end
|
199
221
|
|
200
222
|
# Do not insert Array type to local environment, stack, etc.
|
201
|
-
class Array <
|
223
|
+
class Array < ContainerType
|
202
224
|
def initialize(elems, base_type)
|
203
225
|
raise unless elems.is_a?(Array::Elements)
|
204
226
|
@elems = elems # Array::Elements
|
@@ -223,7 +245,7 @@ module TypeProf
|
|
223
245
|
|
224
246
|
def localize(env, alloc_site, depth)
|
225
247
|
return env, Type.any if depth <= 0
|
226
|
-
alloc_site = alloc_site.add_id(:ary)
|
248
|
+
alloc_site = alloc_site.add_id(:ary).add_id(@base_type)
|
227
249
|
env, elems = @elems.localize(env, alloc_site, depth - 1)
|
228
250
|
env.deploy_type(LocalArray, alloc_site, elems, @base_type)
|
229
251
|
end
|
@@ -237,29 +259,13 @@ module TypeProf
|
|
237
259
|
raise
|
238
260
|
end
|
239
261
|
|
240
|
-
def consistent?(other, subst)
|
241
|
-
case other
|
242
|
-
when Type::Any then true
|
243
|
-
when Type::Var then other.add_subst!(self, subst)
|
244
|
-
when Type::Union
|
245
|
-
other.types.each do |ty2|
|
246
|
-
return true if consistent?(ty2, subst)
|
247
|
-
end
|
248
|
-
return false
|
249
|
-
when Type::Array
|
250
|
-
@base_type.consistent?(other.base_type, subst) && @elems.consistent?(other.elems, subst)
|
251
|
-
else
|
252
|
-
self == other
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
262
|
def substitute(subst, depth)
|
257
263
|
return Type.any if depth <= 0
|
258
264
|
elems = @elems.substitute(subst, depth - 1)
|
259
265
|
Array.new(elems, @base_type)
|
260
266
|
end
|
261
267
|
|
262
|
-
class Elements
|
268
|
+
class Elements # Array
|
263
269
|
include Utils::StructuralEquality
|
264
270
|
|
265
271
|
def initialize(lead_tys, rest_ty = Type.bot)
|
@@ -318,14 +324,24 @@ module TypeProf
|
|
318
324
|
end
|
319
325
|
end
|
320
326
|
|
321
|
-
def
|
327
|
+
def match?(other)
|
322
328
|
n = [@lead_tys.size, other.lead_tys.size].min
|
323
|
-
n.times do |i|
|
324
|
-
return false unless @lead_tys[i].consistent?(other.lead_tys[i], subst)
|
325
|
-
end
|
326
329
|
rest_ty1 = @lead_tys[n..].inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) }
|
327
330
|
rest_ty2 = other.lead_tys[n..].inject(other.rest_ty) {|ty1, ty2| ty1.union(ty2) }
|
328
|
-
|
331
|
+
subst = nil
|
332
|
+
(@lead_tys[0, n] + [rest_ty1]).zip(other.lead_tys[0, n] + [rest_ty2]) do |ty0, ty1|
|
333
|
+
subst2 = Type.match?(ty0, ty1)
|
334
|
+
return nil unless subst2
|
335
|
+
subst = Type.merge_substitution(subst, subst2)
|
336
|
+
end
|
337
|
+
subst
|
338
|
+
end
|
339
|
+
|
340
|
+
def each_free_type_variable(&blk)
|
341
|
+
@lead_tys.each do |ty|
|
342
|
+
ty.each_free_type_variable(&blk)
|
343
|
+
end
|
344
|
+
@rest_ty&.each_free_type_variable(&blk)
|
329
345
|
end
|
330
346
|
|
331
347
|
def substitute(subst, depth)
|
@@ -476,7 +492,7 @@ module TypeProf
|
|
476
492
|
end
|
477
493
|
|
478
494
|
# Do not insert Array type to local environment, stack, etc.
|
479
|
-
class LocalArray <
|
495
|
+
class LocalArray < ContainerType
|
480
496
|
def initialize(id, base_type)
|
481
497
|
@id = id
|
482
498
|
raise unless base_type
|
@@ -506,6 +522,7 @@ module TypeProf
|
|
506
522
|
# TODO: currently out-of-scope array cannot be accessed
|
507
523
|
elems = Array::Elements.new([], Type.any)
|
508
524
|
end
|
525
|
+
visited.delete(self)
|
509
526
|
Array.new(elems, @base_type)
|
510
527
|
end
|
511
528
|
end
|
@@ -513,14 +530,10 @@ module TypeProf
|
|
513
530
|
def get_method(mid, scratch)
|
514
531
|
@base_type.get_method(mid, scratch)
|
515
532
|
end
|
516
|
-
|
517
|
-
def consistent?(other, subst)
|
518
|
-
raise "must not be used"
|
519
|
-
end
|
520
533
|
end
|
521
534
|
|
522
535
|
|
523
|
-
class Hash <
|
536
|
+
class Hash < ContainerType
|
524
537
|
def initialize(elems, base_type)
|
525
538
|
@elems = elems
|
526
539
|
raise unless elems
|
@@ -539,7 +552,7 @@ module TypeProf
|
|
539
552
|
|
540
553
|
def localize(env, alloc_site, depth)
|
541
554
|
return env, Type.any if depth <= 0
|
542
|
-
alloc_site = alloc_site.add_id(:hash)
|
555
|
+
alloc_site = alloc_site.add_id(:hash).add_id(@base_type)
|
543
556
|
env, elems = @elems.localize(env, alloc_site, depth - 1)
|
544
557
|
env.deploy_type(LocalHash, alloc_site, elems, @base_type)
|
545
558
|
end
|
@@ -553,29 +566,13 @@ module TypeProf
|
|
553
566
|
raise
|
554
567
|
end
|
555
568
|
|
556
|
-
def consistent?(other, subst)
|
557
|
-
case other
|
558
|
-
when Type::Any then true
|
559
|
-
when Type::Var then other.add_subst!(self, subst)
|
560
|
-
when Type::Union
|
561
|
-
other.types.each do |ty2|
|
562
|
-
return true if consistent?(ty2, subst)
|
563
|
-
end
|
564
|
-
return false
|
565
|
-
when Type::Hash
|
566
|
-
@base_type.consistent?(other.base_type, subst) && @elems.consistent?(other.elems, subst)
|
567
|
-
else
|
568
|
-
self == other
|
569
|
-
end
|
570
|
-
end
|
571
|
-
|
572
569
|
def substitute(subst, depth)
|
573
570
|
return Type.any if depth <= 0
|
574
571
|
elems = @elems.substitute(subst, depth - 1)
|
575
572
|
Hash.new(elems, @base_type)
|
576
573
|
end
|
577
574
|
|
578
|
-
class Elements
|
575
|
+
class Elements # Hash
|
579
576
|
include Utils::StructuralEquality
|
580
577
|
|
581
578
|
def initialize(map_tys)
|
@@ -635,9 +632,13 @@ module TypeProf
|
|
635
632
|
|
636
633
|
def screen_name(scratch)
|
637
634
|
s = @map_tys.map do |k_ty, v_ty|
|
638
|
-
k = k_ty.screen_name(scratch)
|
639
635
|
v = v_ty.screen_name(scratch)
|
640
|
-
|
636
|
+
if k_ty.is_a?(Type::Symbol)
|
637
|
+
"#{ k_ty.sym }: #{ v }"
|
638
|
+
else
|
639
|
+
k = k_ty.screen_name(scratch)
|
640
|
+
"#{ k }=>#{ v }"
|
641
|
+
end
|
641
642
|
end.join(", ")
|
642
643
|
"{#{ s }}"
|
643
644
|
end
|
@@ -657,22 +658,31 @@ module TypeProf
|
|
657
658
|
end
|
658
659
|
end
|
659
660
|
|
660
|
-
def
|
661
|
-
|
661
|
+
def match?(other)
|
662
|
+
subst = nil
|
662
663
|
other.map_tys.each do |k1, v1|
|
663
|
-
|
664
|
+
subst2 = nil
|
664
665
|
@map_tys.each do |k0, v0|
|
665
|
-
subst3 =
|
666
|
-
if
|
667
|
-
|
668
|
-
|
669
|
-
|
666
|
+
subst3 = Type.match?(k0, k1)
|
667
|
+
if subst3
|
668
|
+
subst4 = Type.match?(v0, v1)
|
669
|
+
if subst4
|
670
|
+
subst2 = Type.merge_substitution(subst2, subst3)
|
671
|
+
subst2 = Type.merge_substitution(subst2, subst4)
|
672
|
+
end
|
670
673
|
end
|
671
674
|
end
|
672
|
-
return
|
675
|
+
return nil unless subst2
|
676
|
+
subst = Type.merge_substitution(subst, subst2)
|
677
|
+
end
|
678
|
+
subst
|
679
|
+
end
|
680
|
+
|
681
|
+
def each_free_type_variable(&blk)
|
682
|
+
@map_tys.each do |k, v|
|
683
|
+
k.each_free_type_variable(&blk)
|
684
|
+
v.each_free_type_variable(&blk)
|
673
685
|
end
|
674
|
-
subst.replace(subst2)
|
675
|
-
true
|
676
686
|
end
|
677
687
|
|
678
688
|
def substitute(subst, depth)
|
@@ -706,7 +716,7 @@ module TypeProf
|
|
706
716
|
def [](key_ty)
|
707
717
|
val_ty = Type.bot
|
708
718
|
@map_tys.each do |k_ty, v_ty|
|
709
|
-
if
|
719
|
+
if Type.match?(k_ty, key_ty)
|
710
720
|
val_ty = val_ty.union(v_ty)
|
711
721
|
end
|
712
722
|
end
|
@@ -763,7 +773,7 @@ module TypeProf
|
|
763
773
|
end
|
764
774
|
end
|
765
775
|
|
766
|
-
class LocalHash <
|
776
|
+
class LocalHash < ContainerType
|
767
777
|
def initialize(id, base_type)
|
768
778
|
@id = id
|
769
779
|
@base_type = base_type
|
@@ -791,6 +801,7 @@ module TypeProf
|
|
791
801
|
else
|
792
802
|
elems = Hash::Elements.new({Type.any => Type.any})
|
793
803
|
end
|
804
|
+
visited.delete(self)
|
794
805
|
Hash.new(elems, @base_type)
|
795
806
|
end
|
796
807
|
end
|
@@ -798,10 +809,6 @@ module TypeProf
|
|
798
809
|
def get_method(mid, scratch)
|
799
810
|
@base_type.get_method(mid, scratch)
|
800
811
|
end
|
801
|
-
|
802
|
-
def consistent?(other, subst)
|
803
|
-
raise "must not be used"
|
804
|
-
end
|
805
812
|
end
|
806
813
|
end
|
807
814
|
end
|