typeprof 0.4.2 → 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/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
|