typeprof 0.2.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -2
- data/.gitignore +1 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +10 -21
- data/LICENSE +21 -0
- data/README.md +6 -0
- data/doc/demo.md +398 -0
- data/doc/doc.ja.md +6 -1
- data/doc/doc.md +7 -2
- data/exe/typeprof +2 -1
- data/lib/typeprof.rb +9 -0
- data/lib/typeprof/analyzer.rb +427 -325
- data/lib/typeprof/arguments.rb +405 -0
- data/lib/typeprof/block.rb +136 -0
- data/lib/typeprof/builtin.rb +36 -25
- data/lib/typeprof/cli.rb +51 -98
- data/lib/typeprof/config.rb +114 -0
- data/lib/typeprof/container-type.rb +280 -92
- data/lib/typeprof/export.rb +197 -108
- data/lib/typeprof/import.rb +134 -80
- data/lib/typeprof/iseq.rb +42 -1
- data/lib/typeprof/method.rb +178 -82
- data/lib/typeprof/type.rb +228 -369
- data/lib/typeprof/utils.rb +4 -18
- data/lib/typeprof/version.rb +3 -0
- data/smoke/arguments2.rb +55 -0
- data/smoke/array-each3.rb +1 -4
- data/smoke/array12.rb +1 -1
- data/smoke/array6.rb +1 -0
- data/smoke/block-ambiguous.rb +36 -0
- data/smoke/block-args1-rest.rb +62 -0
- data/smoke/block-args1.rb +59 -0
- data/smoke/block-args2-rest.rb +62 -0
- data/smoke/block-args2.rb +59 -0
- data/smoke/block-args3-rest.rb +73 -0
- data/smoke/block-args3.rb +70 -0
- data/smoke/block-blockarg.rb +27 -0
- data/smoke/block-kwarg.rb +52 -0
- data/smoke/block10.rb +1 -1
- data/smoke/block11.rb +1 -1
- data/smoke/block14.rb +17 -0
- data/smoke/block4.rb +2 -2
- data/smoke/block5.rb +1 -0
- data/smoke/block6.rb +1 -1
- data/smoke/block7.rb +0 -2
- data/smoke/block8.rb +2 -2
- data/smoke/block9.rb +1 -1
- data/smoke/blown.rb +1 -1
- data/smoke/class-hierarchy.rb +54 -0
- data/smoke/class-hierarchy2.rb +27 -0
- data/smoke/constant1.rb +11 -6
- data/smoke/constant2.rb +2 -0
- data/smoke/cvar.rb +1 -0
- data/smoke/demo10.rb +1 -1
- data/smoke/demo8.rb +2 -2
- data/smoke/demo9.rb +1 -3
- data/smoke/flow7.rb +1 -7
- data/smoke/flow8.rb +13 -0
- data/smoke/hash-fetch.rb +3 -3
- data/smoke/hash-merge-bang.rb +11 -0
- data/smoke/hash1.rb +1 -1
- data/smoke/hash3.rb +1 -1
- data/smoke/hash4.rb +1 -1
- data/smoke/instance_eval.rb +1 -1
- data/smoke/int_times.rb +1 -1
- data/smoke/ivar2.rb +1 -1
- data/smoke/keyword3.rb +1 -2
- data/smoke/keyword4.rb +1 -1
- data/smoke/kwsplat1.rb +1 -1
- data/smoke/kwsplat2.rb +1 -1
- data/smoke/module4.rb +2 -0
- data/smoke/multiple-superclass.rb +4 -0
- data/smoke/next2.rb +1 -1
- data/smoke/optional1.rb +1 -1
- data/smoke/optional2.rb +1 -1
- data/smoke/optional3.rb +10 -0
- data/smoke/pattern-match1.rb +23 -0
- data/smoke/pattern-match2.rb +15 -0
- data/smoke/proc4.rb +1 -1
- data/smoke/rbs-extend.rb +9 -0
- data/smoke/rbs-extend.rbs +7 -0
- data/smoke/rbs-interface.rb +24 -0
- data/smoke/rbs-interface.rbs +12 -0
- data/smoke/rbs-proc1.rb +9 -0
- data/smoke/rbs-proc1.rbs +3 -0
- data/smoke/rbs-proc2.rb +20 -0
- data/smoke/rbs-proc2.rbs +3 -0
- data/smoke/rbs-proc3.rb +13 -0
- data/smoke/rbs-proc3.rbs +4 -0
- data/smoke/rbs-record.rb +17 -0
- data/smoke/rbs-record.rbs +4 -0
- data/smoke/rbs-tyvar.rb +18 -0
- data/smoke/rbs-tyvar.rbs +5 -0
- data/smoke/rbs-tyvar2.rb +20 -0
- data/smoke/rbs-tyvar2.rbs +9 -0
- data/smoke/rbs-tyvar3.rb +17 -0
- data/smoke/rbs-tyvar3.rbs +5 -0
- data/smoke/rbs-tyvar4.rb +36 -0
- data/smoke/rbs-tyvar5.rb +12 -0
- data/smoke/rbs-tyvar5.rbs +8 -0
- data/smoke/rest1.rb +1 -1
- data/smoke/rest2.rb +1 -1
- data/smoke/rest3.rb +1 -1
- data/smoke/rest5.rb +1 -1
- data/smoke/rest6.rb +1 -1
- data/smoke/retry1.rb +1 -1
- data/smoke/return.rb +1 -1
- data/smoke/singleton_method.rb +3 -0
- data/smoke/step.rb +1 -1
- data/smoke/struct.rb +4 -3
- data/smoke/struct3.rb +14 -0
- data/smoke/symbol-proc.rb +24 -0
- data/smoke/uninitialize-var.rb +12 -0
- data/smoke/user-demo.rb +15 -0
- data/smoke/wrong-extend.rb +1 -0
- data/typeprof.gemspec +4 -2
- metadata +53 -6
- data/run.sh +0 -3
- data/smoke/variadic1.rb.notyet +0 -5
|
@@ -6,30 +6,226 @@ module TypeProf
|
|
|
6
6
|
raise if !val.is_a?(Utils::StructuralEquality) && !val.is_a?(Integer) && !val.is_a?(Symbol)
|
|
7
7
|
@val = val
|
|
8
8
|
@parent = parent
|
|
9
|
-
@_hash ||= (@val.hash ^ @parent.hash)
|
|
10
9
|
end
|
|
11
10
|
|
|
12
11
|
attr_reader :val, :parent
|
|
13
12
|
|
|
14
|
-
def hash
|
|
15
|
-
@_hash
|
|
16
|
-
end
|
|
17
|
-
|
|
18
13
|
def add_id(val)
|
|
19
14
|
AllocationSite.new(val, self)
|
|
20
15
|
end
|
|
21
16
|
end
|
|
22
17
|
|
|
23
18
|
class Type # or AbstractValue
|
|
24
|
-
#
|
|
19
|
+
# Cell, Array, and Hash are types for global interface, e.g., TypedISeq.
|
|
20
|
+
# Do not push such types to local environment, stack, etc.
|
|
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
|
+
|
|
50
|
+
# The most basic container type for default type parameter class
|
|
51
|
+
class Cell < ContainerType
|
|
52
|
+
def initialize(elems, base_type)
|
|
53
|
+
raise if !elems.is_a?(Cell::Elements)
|
|
54
|
+
@elems = elems # Cell::Elements
|
|
55
|
+
raise unless base_type
|
|
56
|
+
@base_type = base_type
|
|
57
|
+
if base_type.klass.type_params.size != elems.elems.size
|
|
58
|
+
raise
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
attr_reader :elems, :base_type
|
|
63
|
+
|
|
64
|
+
def inspect
|
|
65
|
+
"Type::Cell[#{ @elems.inspect }, base_type: #{ @base_type.inspect }]"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def screen_name(scratch)
|
|
69
|
+
str = @elems.screen_name(scratch)
|
|
70
|
+
if str.start_with?("*")
|
|
71
|
+
str = @base_type.screen_name(scratch) + str[1..]
|
|
72
|
+
end
|
|
73
|
+
str
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def localize(env, alloc_site, depth)
|
|
77
|
+
return env, Type.any if depth <= 0
|
|
78
|
+
alloc_site = alloc_site.add_id(:cell).add_id(@base_type)
|
|
79
|
+
env, elems = @elems.localize(env, alloc_site, depth)
|
|
80
|
+
env.deploy_type(LocalCell, alloc_site, elems, @base_type)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def limit_size(limit)
|
|
84
|
+
return Type.any if limit <= 0
|
|
85
|
+
Cell.new(@elems.limit_size(limit - 1), @base_type)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def get_method(mid, scratch)
|
|
89
|
+
raise
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def substitute(subst, depth)
|
|
93
|
+
return Type.any if depth <= 0
|
|
94
|
+
elems = @elems.substitute(subst, depth)
|
|
95
|
+
Cell.new(elems, @base_type)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
class Elements # Cell
|
|
99
|
+
include Utils::StructuralEquality
|
|
100
|
+
|
|
101
|
+
def initialize(elems)
|
|
102
|
+
@elems = elems
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
attr_reader :elems
|
|
106
|
+
|
|
107
|
+
def to_local_type(id, base_ty)
|
|
108
|
+
Type::LocalCell.new(id, base_ty)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def globalize(env, visited, depth)
|
|
112
|
+
Elements.new(@elems.map {|ty| ty.globalize(env, visited, depth) })
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def localize(env, alloc_site, depth)
|
|
116
|
+
elems = @elems.map.with_index do |ty, i|
|
|
117
|
+
alloc_site2 = alloc_site.add_id(i)
|
|
118
|
+
env, ty = ty.localize(env, alloc_site2, depth)
|
|
119
|
+
ty
|
|
120
|
+
end
|
|
121
|
+
return env, Elements.new(elems)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def limit_size(limit)
|
|
125
|
+
Elements.new(@elems.map {|ty| ty.limit_size(limit) })
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def screen_name(scratch)
|
|
129
|
+
"*[#{ @elems.map {|ty| ty.screen_name(scratch) }.join(", ") }]"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def pretty_print(q)
|
|
133
|
+
q.group(9, "Elements[", "]") do
|
|
134
|
+
q.seplist(@elems) do |elem|
|
|
135
|
+
q.pp elem
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def match?(other)
|
|
141
|
+
return nil if @elems.size != other.elems.size
|
|
142
|
+
subst = nil
|
|
143
|
+
@elems.zip(other.elems) do |ty0, ty1|
|
|
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)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def substitute(subst, depth)
|
|
158
|
+
Elements.new(@elems.map {|ty| ty.substitute(subst, depth) })
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def [](idx)
|
|
162
|
+
@elems[idx]
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def update(idx, ty)
|
|
166
|
+
Elements.new(Utils.array_update(@elems, idx, @elems[idx].union(ty)))
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def union(other)
|
|
170
|
+
return self if self == other
|
|
171
|
+
if @elems.size != other.elems.size
|
|
172
|
+
raise "#{ @elems.size } != #{ other.elems.size }"
|
|
173
|
+
end
|
|
174
|
+
elems = []
|
|
175
|
+
@elems.zip(other.elems) do |ty0, ty1|
|
|
176
|
+
elems << ty0.union(ty1)
|
|
177
|
+
end
|
|
178
|
+
Elements.new(elems)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
class LocalCell < ContainerType
|
|
184
|
+
def initialize(id, base_type)
|
|
185
|
+
@id = id
|
|
186
|
+
raise unless base_type
|
|
187
|
+
@base_type = base_type
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
attr_reader :id, :base_type
|
|
191
|
+
|
|
192
|
+
def inspect
|
|
193
|
+
"Type::LocalCell[#{ @id }, base_type: #{ @base_type.inspect }]"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def screen_name(scratch)
|
|
197
|
+
#raise "LocalArray must not be included in signature"
|
|
198
|
+
"LocalCell!"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def globalize(env, visited, depth)
|
|
202
|
+
if visited[self] || depth <= 0
|
|
203
|
+
Type.any
|
|
204
|
+
else
|
|
205
|
+
visited[self] = true
|
|
206
|
+
elems = env.get_container_elem_types(@id)
|
|
207
|
+
if elems
|
|
208
|
+
elems = elems.globalize(env, visited, depth - 1)
|
|
209
|
+
else
|
|
210
|
+
elems = Cell::Elements.new([]) # XXX
|
|
211
|
+
end
|
|
212
|
+
visited.delete(self)
|
|
213
|
+
Cell.new(elems, @base_type)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def get_method(mid, scratch)
|
|
218
|
+
@base_type.get_method(mid, scratch)
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
25
222
|
# Do not insert Array type to local environment, stack, etc.
|
|
26
|
-
class Array <
|
|
223
|
+
class Array < ContainerType
|
|
27
224
|
def initialize(elems, base_type)
|
|
28
225
|
raise unless elems.is_a?(Array::Elements)
|
|
29
226
|
@elems = elems # Array::Elements
|
|
30
227
|
raise unless base_type
|
|
31
228
|
@base_type = base_type
|
|
32
|
-
# XXX: need infinite recursion
|
|
33
229
|
end
|
|
34
230
|
|
|
35
231
|
attr_reader :elems, :base_type
|
|
@@ -47,18 +243,11 @@ module TypeProf
|
|
|
47
243
|
str
|
|
48
244
|
end
|
|
49
245
|
|
|
50
|
-
def globalize(env, visited, depth)
|
|
51
|
-
return Type.any if depth <= 0
|
|
52
|
-
elems = @elems.globalize(env, visited, depth - 1)
|
|
53
|
-
base_ty = @base_type.globalize(env, visited, depth - 1)
|
|
54
|
-
Array.new(elems, base_ty)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
246
|
def localize(env, alloc_site, depth)
|
|
58
247
|
return env, Type.any if depth <= 0
|
|
59
|
-
alloc_site = alloc_site.add_id(:ary)
|
|
248
|
+
alloc_site = alloc_site.add_id(:ary).add_id(@base_type)
|
|
60
249
|
env, elems = @elems.localize(env, alloc_site, depth - 1)
|
|
61
|
-
env.
|
|
250
|
+
env.deploy_type(LocalArray, alloc_site, elems, @base_type)
|
|
62
251
|
end
|
|
63
252
|
|
|
64
253
|
def limit_size(limit)
|
|
@@ -70,28 +259,13 @@ module TypeProf
|
|
|
70
259
|
raise
|
|
71
260
|
end
|
|
72
261
|
|
|
73
|
-
def consistent?(other, subst)
|
|
74
|
-
case other
|
|
75
|
-
when Type::Any then true
|
|
76
|
-
when Type::Var then other.add_subst!(self, subst)
|
|
77
|
-
when Type::Union
|
|
78
|
-
other.types.each do |ty2|
|
|
79
|
-
return true if consistent?(ty2, subst)
|
|
80
|
-
end
|
|
81
|
-
when Type::Array
|
|
82
|
-
@base_type.consistent?(other.base_type, subst) && @elems.consistent?(other.elems, subst)
|
|
83
|
-
else
|
|
84
|
-
self == other
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
262
|
def substitute(subst, depth)
|
|
89
263
|
return Type.any if depth <= 0
|
|
90
264
|
elems = @elems.substitute(subst, depth - 1)
|
|
91
265
|
Array.new(elems, @base_type)
|
|
92
266
|
end
|
|
93
267
|
|
|
94
|
-
class Elements
|
|
268
|
+
class Elements # Array
|
|
95
269
|
include Utils::StructuralEquality
|
|
96
270
|
|
|
97
271
|
def initialize(lead_tys, rest_ty = Type.bot)
|
|
@@ -102,8 +276,7 @@ module TypeProf
|
|
|
102
276
|
|
|
103
277
|
attr_reader :lead_tys, :rest_ty
|
|
104
278
|
|
|
105
|
-
def to_local_type(id)
|
|
106
|
-
base_ty = Type::Instance.new(Type::Builtin[:ary])
|
|
279
|
+
def to_local_type(id, base_ty)
|
|
107
280
|
Type::LocalArray.new(id, base_ty)
|
|
108
281
|
end
|
|
109
282
|
|
|
@@ -151,14 +324,24 @@ module TypeProf
|
|
|
151
324
|
end
|
|
152
325
|
end
|
|
153
326
|
|
|
154
|
-
def
|
|
327
|
+
def match?(other)
|
|
155
328
|
n = [@lead_tys.size, other.lead_tys.size].min
|
|
156
|
-
n.times do |i|
|
|
157
|
-
return false unless @lead_tys[i].consistent?(other.lead_tys[i], subst)
|
|
158
|
-
end
|
|
159
329
|
rest_ty1 = @lead_tys[n..].inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) }
|
|
160
330
|
rest_ty2 = other.lead_tys[n..].inject(other.rest_ty) {|ty1, ty2| ty1.union(ty2) }
|
|
161
|
-
|
|
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)
|
|
162
345
|
end
|
|
163
346
|
|
|
164
347
|
def substitute(subst, depth)
|
|
@@ -171,6 +354,11 @@ module TypeProf
|
|
|
171
354
|
@lead_tys.inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) } #.union(Type.nil) # is this needed?
|
|
172
355
|
end
|
|
173
356
|
|
|
357
|
+
def squash_or_any
|
|
358
|
+
ty = squash
|
|
359
|
+
ty == Type.bot ? Type.any : ty
|
|
360
|
+
end
|
|
361
|
+
|
|
174
362
|
def [](idx)
|
|
175
363
|
if idx >= 0
|
|
176
364
|
if idx < @lead_tys.size
|
|
@@ -304,7 +492,7 @@ module TypeProf
|
|
|
304
492
|
end
|
|
305
493
|
|
|
306
494
|
# Do not insert Array type to local environment, stack, etc.
|
|
307
|
-
class LocalArray <
|
|
495
|
+
class LocalArray < ContainerType
|
|
308
496
|
def initialize(id, base_type)
|
|
309
497
|
@id = id
|
|
310
498
|
raise unless base_type
|
|
@@ -334,6 +522,7 @@ module TypeProf
|
|
|
334
522
|
# TODO: currently out-of-scope array cannot be accessed
|
|
335
523
|
elems = Array::Elements.new([], Type.any)
|
|
336
524
|
end
|
|
525
|
+
visited.delete(self)
|
|
337
526
|
Array.new(elems, @base_type)
|
|
338
527
|
end
|
|
339
528
|
end
|
|
@@ -341,14 +530,10 @@ module TypeProf
|
|
|
341
530
|
def get_method(mid, scratch)
|
|
342
531
|
@base_type.get_method(mid, scratch)
|
|
343
532
|
end
|
|
344
|
-
|
|
345
|
-
def consistent?(other, subst)
|
|
346
|
-
raise "must not be used"
|
|
347
|
-
end
|
|
348
533
|
end
|
|
349
534
|
|
|
350
535
|
|
|
351
|
-
class Hash <
|
|
536
|
+
class Hash < ContainerType
|
|
352
537
|
def initialize(elems, base_type)
|
|
353
538
|
@elems = elems
|
|
354
539
|
raise unless elems
|
|
@@ -365,18 +550,11 @@ module TypeProf
|
|
|
365
550
|
@elems.screen_name(scratch)
|
|
366
551
|
end
|
|
367
552
|
|
|
368
|
-
def globalize(env, visited, depth)
|
|
369
|
-
return Type.any if depth <= 0
|
|
370
|
-
elems = @elems.globalize(env, visited, depth - 1)
|
|
371
|
-
base_ty = @base_type.globalize(env, visited, depth - 1)
|
|
372
|
-
Hash.new(elems, base_ty)
|
|
373
|
-
end
|
|
374
|
-
|
|
375
553
|
def localize(env, alloc_site, depth)
|
|
376
554
|
return env, Type.any if depth <= 0
|
|
377
|
-
alloc_site = alloc_site.add_id(:hash)
|
|
555
|
+
alloc_site = alloc_site.add_id(:hash).add_id(@base_type)
|
|
378
556
|
env, elems = @elems.localize(env, alloc_site, depth - 1)
|
|
379
|
-
env.
|
|
557
|
+
env.deploy_type(LocalHash, alloc_site, elems, @base_type)
|
|
380
558
|
end
|
|
381
559
|
|
|
382
560
|
def limit_size(limit)
|
|
@@ -388,28 +566,13 @@ module TypeProf
|
|
|
388
566
|
raise
|
|
389
567
|
end
|
|
390
568
|
|
|
391
|
-
def consistent?(other, subst)
|
|
392
|
-
case other
|
|
393
|
-
when Type::Any then true
|
|
394
|
-
when Type::Var then other.add_subst!(self, subst)
|
|
395
|
-
when Type::Union
|
|
396
|
-
other.types.each do |ty2|
|
|
397
|
-
return true if consistent?(ty2, subst)
|
|
398
|
-
end
|
|
399
|
-
when Type::Hash
|
|
400
|
-
@base_type.consistent?(other.base_type, subst) && @elems.consistent?(other.elems, subst)
|
|
401
|
-
else
|
|
402
|
-
self == other
|
|
403
|
-
end
|
|
404
|
-
end
|
|
405
|
-
|
|
406
569
|
def substitute(subst, depth)
|
|
407
570
|
return Type.any if depth <= 0
|
|
408
571
|
elems = @elems.substitute(subst, depth - 1)
|
|
409
572
|
Hash.new(elems, @base_type)
|
|
410
573
|
end
|
|
411
574
|
|
|
412
|
-
class Elements
|
|
575
|
+
class Elements # Hash
|
|
413
576
|
include Utils::StructuralEquality
|
|
414
577
|
|
|
415
578
|
def initialize(map_tys)
|
|
@@ -427,8 +590,7 @@ module TypeProf
|
|
|
427
590
|
|
|
428
591
|
attr_reader :map_tys
|
|
429
592
|
|
|
430
|
-
def to_local_type(id)
|
|
431
|
-
base_ty = Type::Instance.new(Type::Builtin[:hash])
|
|
593
|
+
def to_local_type(id, base_ty)
|
|
432
594
|
Type::LocalHash.new(id, base_ty)
|
|
433
595
|
end
|
|
434
596
|
|
|
@@ -470,9 +632,13 @@ module TypeProf
|
|
|
470
632
|
|
|
471
633
|
def screen_name(scratch)
|
|
472
634
|
s = @map_tys.map do |k_ty, v_ty|
|
|
473
|
-
k = k_ty.screen_name(scratch)
|
|
474
635
|
v = v_ty.screen_name(scratch)
|
|
475
|
-
|
|
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
|
|
476
642
|
end.join(", ")
|
|
477
643
|
"{#{ s }}"
|
|
478
644
|
end
|
|
@@ -492,22 +658,31 @@ module TypeProf
|
|
|
492
658
|
end
|
|
493
659
|
end
|
|
494
660
|
|
|
495
|
-
def
|
|
496
|
-
|
|
661
|
+
def match?(other)
|
|
662
|
+
subst = nil
|
|
497
663
|
other.map_tys.each do |k1, v1|
|
|
498
|
-
|
|
664
|
+
subst2 = nil
|
|
499
665
|
@map_tys.each do |k0, v0|
|
|
500
|
-
subst3 =
|
|
501
|
-
if
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|
|
505
673
|
end
|
|
506
674
|
end
|
|
507
|
-
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)
|
|
508
685
|
end
|
|
509
|
-
subst.replace(subst2)
|
|
510
|
-
true
|
|
511
686
|
end
|
|
512
687
|
|
|
513
688
|
def substitute(subst, depth)
|
|
@@ -541,7 +716,7 @@ module TypeProf
|
|
|
541
716
|
def [](key_ty)
|
|
542
717
|
val_ty = Type.bot
|
|
543
718
|
@map_tys.each do |k_ty, v_ty|
|
|
544
|
-
if
|
|
719
|
+
if Type.match?(k_ty, key_ty)
|
|
545
720
|
val_ty = val_ty.union(v_ty)
|
|
546
721
|
end
|
|
547
722
|
end
|
|
@@ -579,10 +754,26 @@ module TypeProf
|
|
|
579
754
|
|
|
580
755
|
Elements.new(map_tys)
|
|
581
756
|
end
|
|
757
|
+
|
|
758
|
+
def to_keywords
|
|
759
|
+
kw_tys = {}
|
|
760
|
+
@map_tys.each do |key_ty, val_ty|
|
|
761
|
+
if key_ty.is_a?(Type::Symbol)
|
|
762
|
+
kw_tys[key_ty.sym] = val_ty
|
|
763
|
+
else
|
|
764
|
+
all_val_ty = Type.bot
|
|
765
|
+
@map_tys.each do |_key_ty, val_ty|
|
|
766
|
+
all_val_ty = all_val_ty.union(val_ty)
|
|
767
|
+
end
|
|
768
|
+
return { nil => all_val_ty }
|
|
769
|
+
end
|
|
770
|
+
end
|
|
771
|
+
kw_tys
|
|
772
|
+
end
|
|
582
773
|
end
|
|
583
774
|
end
|
|
584
775
|
|
|
585
|
-
class LocalHash <
|
|
776
|
+
class LocalHash < ContainerType
|
|
586
777
|
def initialize(id, base_type)
|
|
587
778
|
@id = id
|
|
588
779
|
@base_type = base_type
|
|
@@ -610,6 +801,7 @@ module TypeProf
|
|
|
610
801
|
else
|
|
611
802
|
elems = Hash::Elements.new({Type.any => Type.any})
|
|
612
803
|
end
|
|
804
|
+
visited.delete(self)
|
|
613
805
|
Hash.new(elems, @base_type)
|
|
614
806
|
end
|
|
615
807
|
end
|
|
@@ -617,10 +809,6 @@ module TypeProf
|
|
|
617
809
|
def get_method(mid, scratch)
|
|
618
810
|
@base_type.get_method(mid, scratch)
|
|
619
811
|
end
|
|
620
|
-
|
|
621
|
-
def consistent?(other, subst)
|
|
622
|
-
raise "must not be used"
|
|
623
|
-
end
|
|
624
812
|
end
|
|
625
813
|
end
|
|
626
814
|
end
|