typeprof 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +9 -20
- data/LICENSE +21 -0
- data/doc/doc.ja.md +2 -1
- data/doc/doc.md +3 -2
- data/exe/typeprof +2 -1
- data/lib/typeprof.rb +1 -0
- data/lib/typeprof/analyzer.rb +163 -84
- data/lib/typeprof/builtin.rb +20 -19
- data/lib/typeprof/cli.rb +51 -98
- data/lib/typeprof/config.rb +114 -0
- data/lib/typeprof/container-type.rb +125 -21
- data/lib/typeprof/export.rb +20 -8
- data/lib/typeprof/import.rb +43 -20
- data/lib/typeprof/iseq.rb +17 -1
- data/lib/typeprof/method.rb +33 -9
- data/lib/typeprof/type.rb +52 -24
- data/lib/typeprof/utils.rb +4 -18
- data/lib/typeprof/version.rb +3 -0
- data/smoke/arguments2.rb +55 -0
- data/smoke/hash4.rb +1 -1
- data/smoke/keyword3.rb +1 -2
- data/smoke/keyword4.rb +1 -1
- data/smoke/module4.rb +2 -0
- data/smoke/optional1.rb +1 -1
- data/smoke/optional2.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-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/rest1.rb +1 -1
- data/smoke/rest3.rb +1 -1
- data/smoke/rest6.rb +1 -1
- data/smoke/retry1.rb +1 -1
- data/smoke/step.rb +1 -1
- data/smoke/user-demo.rb +15 -0
- data/smoke/wrong-extend.rb +1 -0
- data/typeprof.gemspec +4 -2
- metadata +17 -5
- data/run.sh +0 -3
data/lib/typeprof/export.rb
CHANGED
@@ -25,6 +25,13 @@ module TypeProf
|
|
25
25
|
ntrace
|
26
26
|
end
|
27
27
|
|
28
|
+
def show_message(terminated, output)
|
29
|
+
if terminated
|
30
|
+
output.puts "# CAUTION: Type profiling was terminated prematurely because of the limitation"
|
31
|
+
output.puts
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
28
35
|
def show_error(errors, backward_edge, output)
|
29
36
|
return if errors.empty?
|
30
37
|
return unless Config.options[:show_errors]
|
@@ -87,8 +94,6 @@ module TypeProf
|
|
87
94
|
def show(stat_eps, output)
|
88
95
|
output.puts "# Classes" # and Modules
|
89
96
|
|
90
|
-
stat_classes = {}
|
91
|
-
stat_methods = {}
|
92
97
|
first = true
|
93
98
|
|
94
99
|
@class_defs.each_value do |class_def|
|
@@ -97,6 +102,11 @@ module TypeProf
|
|
97
102
|
mod_def.name
|
98
103
|
end
|
99
104
|
|
105
|
+
extended_mods = class_def.modules[true].filter_map do |mod_def, absolute_paths|
|
106
|
+
next if absolute_paths.all? {|path| !path || Config.check_dir_filter(path) == :exclude }
|
107
|
+
mod_def.name
|
108
|
+
end
|
109
|
+
|
100
110
|
explicit_methods = {}
|
101
111
|
iseq_methods = {}
|
102
112
|
attr_methods = {}
|
@@ -161,7 +171,7 @@ module TypeProf
|
|
161
171
|
end
|
162
172
|
|
163
173
|
if !class_def.absolute_path || Config.check_dir_filter(class_def.absolute_path) == :exclude
|
164
|
-
next if included_mods.empty? && ivars.empty? && cvars.empty? && iseq_methods.empty? && attr_methods.empty?
|
174
|
+
next if included_mods.empty? && extended_mods.empty? && ivars.empty? && cvars.empty? && iseq_methods.empty? && attr_methods.empty?
|
165
175
|
end
|
166
176
|
|
167
177
|
output.puts unless first
|
@@ -176,6 +186,9 @@ module TypeProf
|
|
176
186
|
included_mods.sort.each do |ty|
|
177
187
|
output.puts " include #{ ty }"
|
178
188
|
end
|
189
|
+
extended_mods.sort.each do |ty|
|
190
|
+
output.puts " extend #{ ty }"
|
191
|
+
end
|
179
192
|
ivars.each do |var, ty, rbs_declared|
|
180
193
|
s = rbs_declared ? "# " : " "
|
181
194
|
output.puts s + "#{ var } : #{ ty }" unless var.start_with?("_")
|
@@ -199,10 +212,9 @@ module TypeProf
|
|
199
212
|
end
|
200
213
|
|
201
214
|
if ENV["TP_STAT"]
|
202
|
-
output.puts "
|
203
|
-
output.puts "
|
204
|
-
output.puts "
|
205
|
-
output.puts " %d methods (in total)" % stat_methods.size
|
215
|
+
output.puts ""
|
216
|
+
output.puts "# TypeProf statistics:"
|
217
|
+
output.puts "# %d execution points" % stat_eps.size
|
206
218
|
end
|
207
219
|
if ENV["TP_COVERAGE"]
|
208
220
|
coverage = {}
|
@@ -212,7 +224,7 @@ module TypeProf
|
|
212
224
|
(coverage[path] ||= [])[lineno] ||= 0
|
213
225
|
(coverage[path] ||= [])[lineno] += 1
|
214
226
|
end
|
215
|
-
File.binwrite("coverage.dump", Marshal.dump(coverage))
|
227
|
+
File.binwrite("typeprof-analysis-coverage.dump", Marshal.dump(coverage))
|
216
228
|
end
|
217
229
|
end
|
218
230
|
end
|
data/lib/typeprof/import.rb
CHANGED
@@ -89,12 +89,13 @@ module TypeProf
|
|
89
89
|
json = {}
|
90
90
|
|
91
91
|
each_class_decl do |name, decls|
|
92
|
-
super_class_name = get_super_class_name(name)
|
92
|
+
super_class_name = get_super_class_name(name, decls)
|
93
93
|
klass = conv_type_name(name)
|
94
94
|
superclass = super_class_name ? conv_type_name(super_class_name) : nil
|
95
95
|
|
96
96
|
type_params = nil
|
97
97
|
included_modules = []
|
98
|
+
extended_modules = []
|
98
99
|
methods = {}
|
99
100
|
ivars = {}
|
100
101
|
cvars = {}
|
@@ -103,8 +104,6 @@ module TypeProf
|
|
103
104
|
decls.each do |decl|
|
104
105
|
decl = decl.decl
|
105
106
|
|
106
|
-
raise NotImplementedError if decl.is_a?(RBS::AST::Declarations::Interface) # XXX
|
107
|
-
|
108
107
|
type_params2 = decl.type_params.params.map {|param| [param.name, param.variance] }
|
109
108
|
raise "inconsistent type parameter declaration" if type_params && type_params != type_params2
|
110
109
|
type_params = type_params2
|
@@ -160,6 +159,15 @@ module TypeProf
|
|
160
159
|
# including an interface is not supported yet
|
161
160
|
end
|
162
161
|
|
162
|
+
when RBS::AST::Members::Extend
|
163
|
+
name = member.name
|
164
|
+
if name.kind == :class
|
165
|
+
mod = conv_type_name(name)
|
166
|
+
extended_modules << mod
|
167
|
+
else
|
168
|
+
# extending a module with an interface is not supported yet
|
169
|
+
end
|
170
|
+
|
163
171
|
when RBS::AST::Members::InstanceVariable
|
164
172
|
ivars[member.name] = conv_type(member.type)
|
165
173
|
when RBS::AST::Members::ClassVariable
|
@@ -184,6 +192,7 @@ module TypeProf
|
|
184
192
|
superclass: superclass,
|
185
193
|
members: {
|
186
194
|
included_modules: included_modules,
|
195
|
+
extended_modules: extended_modules,
|
187
196
|
methods: methods,
|
188
197
|
ivars: ivars,
|
189
198
|
cvars: cvars,
|
@@ -196,8 +205,6 @@ module TypeProf
|
|
196
205
|
end
|
197
206
|
|
198
207
|
def each_class_decl
|
199
|
-
classes = []
|
200
|
-
|
201
208
|
# topological sort
|
202
209
|
# * superclasses and modules appear earlier than their subclasses (Object is earlier than String)
|
203
210
|
# * namespace module appers earlier than its children (Process is earlier than Process::Status)
|
@@ -223,7 +230,9 @@ module TypeProf
|
|
223
230
|
end
|
224
231
|
end
|
225
232
|
|
226
|
-
|
233
|
+
@cur_env.interface_decls.each do |name, decl|
|
234
|
+
yield name, [decl]
|
235
|
+
end
|
227
236
|
end
|
228
237
|
|
229
238
|
def each_ancestor(decl, &blk)
|
@@ -236,15 +245,15 @@ module TypeProf
|
|
236
245
|
end
|
237
246
|
end
|
238
247
|
|
239
|
-
def get_super_class_name(name)
|
248
|
+
def get_super_class_name(name, decls)
|
240
249
|
return nil if name == RBS::BuiltinNames::BasicObject.name
|
241
250
|
|
242
|
-
|
251
|
+
decls.each do |decl|
|
243
252
|
decl = decl.decl
|
244
253
|
case decl
|
245
254
|
when RBS::AST::Declarations::Class
|
246
255
|
return decl.super_class.name if decl.super_class
|
247
|
-
when RBS::AST::Declarations::Module
|
256
|
+
when RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface
|
248
257
|
return nil
|
249
258
|
else
|
250
259
|
raise "unknown declaration: %p" % decl.class
|
@@ -320,6 +329,8 @@ module TypeProf
|
|
320
329
|
raise NotImplementedError unless type.required_keywords.empty?
|
321
330
|
raise NotImplementedError if type.rest_keywords
|
322
331
|
|
332
|
+
req = rbs_block.required
|
333
|
+
|
323
334
|
lead_tys = type.required_positionals.map do |type|
|
324
335
|
conv_type(type.type)
|
325
336
|
end
|
@@ -329,7 +340,7 @@ module TypeProf
|
|
329
340
|
|
330
341
|
ret_ty = conv_type(type.return_type)
|
331
342
|
|
332
|
-
[lead_tys, opt_tys, ret_ty]
|
343
|
+
[req, lead_tys, opt_tys, ret_ty]
|
333
344
|
end
|
334
345
|
|
335
346
|
def conv_type(ty)
|
@@ -354,7 +365,7 @@ module TypeProf
|
|
354
365
|
end
|
355
366
|
when RBS::Types::Bases::Bool then [:bool]
|
356
367
|
when RBS::Types::Bases::Any then [:any]
|
357
|
-
when RBS::Types::Bases::Void then [:
|
368
|
+
when RBS::Types::Bases::Void then [:void]
|
358
369
|
when RBS::Types::Bases::Self then [:self]
|
359
370
|
when RBS::Types::Bases::Nil then [:nil]
|
360
371
|
when RBS::Types::Bases::Bottom then [:union, []]
|
@@ -387,7 +398,7 @@ module TypeProf
|
|
387
398
|
when "::_ToInt" then [:int]
|
388
399
|
when "::_ToAry[U]" then [:array, [:Array], [], [:var, :U]]
|
389
400
|
else
|
390
|
-
[:
|
401
|
+
[:instance, conv_type_name(ty.name)]
|
391
402
|
end
|
392
403
|
when RBS::Types::Bases::Instance then [:any] # XXX: not implemented yet
|
393
404
|
when RBS::Types::Record then [:any] # XXX: not implemented yet
|
@@ -419,7 +430,8 @@ module TypeProf
|
|
419
430
|
end
|
420
431
|
|
421
432
|
def self.import_rbs_file(scratch, rbs_path)
|
422
|
-
|
433
|
+
rbs_path = Pathname(rbs_path) unless rbs_path.is_a?(Pathname)
|
434
|
+
Import.new(scratch, scratch.rbs_reader.load_path(rbs_path)).import(true)
|
423
435
|
end
|
424
436
|
|
425
437
|
def initialize(scratch, json)
|
@@ -459,6 +471,7 @@ module TypeProf
|
|
459
471
|
|
460
472
|
classes.each do |klass, members|
|
461
473
|
included_modules = members[:included_modules]
|
474
|
+
extended_modules = members[:extended_modules]
|
462
475
|
methods = members[:methods]
|
463
476
|
ivars = members[:ivars]
|
464
477
|
cvars = members[:cvars]
|
@@ -468,6 +481,10 @@ module TypeProf
|
|
468
481
|
@scratch.include_module(klass, path_to_klass(mod), nil)
|
469
482
|
end
|
470
483
|
|
484
|
+
extended_modules.each do |mod|
|
485
|
+
@scratch.extend_module(klass, path_to_klass(mod), nil)
|
486
|
+
end
|
487
|
+
|
471
488
|
methods.each do |(singleton, method_name), mdef|
|
472
489
|
rbs_source = explicit ? rbs_sources[[singleton, method_name]] : nil
|
473
490
|
mdef = conv_method_def(method_name, mdef, rbs_source)
|
@@ -499,7 +516,7 @@ module TypeProf
|
|
499
516
|
end
|
500
517
|
|
501
518
|
def conv_method_def(method_name, mdef, rbs_source)
|
502
|
-
sig_rets = mdef.
|
519
|
+
sig_rets = mdef.flat_map do |sig_ret|
|
503
520
|
#type_params = sig_ret[:type_params] # XXX
|
504
521
|
lead_tys = sig_ret[:lead_tys]
|
505
522
|
opt_tys = sig_ret[:opt_tys]
|
@@ -517,24 +534,29 @@ module TypeProf
|
|
517
534
|
req_kw_tys.each {|key, ty| kw_tys << [true, key, conv_type(ty)] }
|
518
535
|
opt_kw_tys.each {|key, ty| kw_tys << [false, key, conv_type(ty)] }
|
519
536
|
kw_rest_ty = conv_type(rest_kw_ty) if rest_kw_ty
|
520
|
-
|
521
|
-
|
537
|
+
|
538
|
+
blks = conv_block(blk)
|
522
539
|
|
523
540
|
ret_ty = conv_type(ret_ty)
|
524
541
|
|
525
|
-
|
526
|
-
|
542
|
+
blks.map do |blk|
|
543
|
+
[FormalArguments.new(lead_tys, opt_tys, rest_ty, [], kw_tys, kw_rest_ty, blk), ret_ty]
|
544
|
+
end
|
545
|
+
end
|
527
546
|
|
528
547
|
TypedMethodDef.new(sig_rets, rbs_source)
|
529
548
|
end
|
530
549
|
|
531
550
|
def conv_block(blk)
|
532
|
-
|
551
|
+
return [Type.nil] unless blk
|
552
|
+
req, lead_tys, opt_tys, ret_ty = blk
|
533
553
|
lead_tys = lead_tys.map {|ty| conv_type(ty) }
|
534
554
|
opt_tys = opt_tys.map {|ty| conv_type(ty) }
|
535
555
|
fargs = FormalArguments.new(lead_tys, opt_tys, nil, nil, nil, nil, nil)
|
536
556
|
ret_ty = conv_type(ret_ty)
|
537
|
-
Type::TypedProc.new(fargs, ret_ty, Type::Builtin[:proc])
|
557
|
+
ret = [Type::TypedProc.new(fargs, ret_ty, Type::Builtin[:proc])]
|
558
|
+
ret << Type.nil unless req
|
559
|
+
ret
|
538
560
|
end
|
539
561
|
|
540
562
|
def conv_type(ty)
|
@@ -542,6 +564,7 @@ module TypeProf
|
|
542
564
|
when :class then path_to_klass(ty[1])
|
543
565
|
when :instance then Type::Instance.new(path_to_klass(ty[1]))
|
544
566
|
when :any then Type.any
|
567
|
+
when :void then Type::Void.new
|
545
568
|
when :nil then Type.nil
|
546
569
|
when :optional then Type.optional(conv_type(ty[1]))
|
547
570
|
when :bool then Type.bool
|
data/lib/typeprof/iseq.rb
CHANGED
@@ -32,6 +32,22 @@ module TypeProf
|
|
32
32
|
@name, @path, @absolute_path, @start_lineno, @type,
|
33
33
|
@locals, @fargs_format, catch_table, insns = *iseq
|
34
34
|
|
35
|
+
if @type == :method
|
36
|
+
if @fargs_format[:opt]
|
37
|
+
label = @fargs_format[:opt].last
|
38
|
+
i = insns.index(label) + 1
|
39
|
+
else
|
40
|
+
i = insns.find_index {|insn| insn.is_a?(Array) }
|
41
|
+
end
|
42
|
+
# skip keyword initialization
|
43
|
+
while insns[i][0] == :checkkeyword
|
44
|
+
raise if insns[i + 1][0] != :branchif
|
45
|
+
label = insns[i + 1][1]
|
46
|
+
i = insns.index(label) + 1
|
47
|
+
end
|
48
|
+
insns[i, 0] = [[:_method_body]]
|
49
|
+
end
|
50
|
+
|
35
51
|
@insns = []
|
36
52
|
@linenos = []
|
37
53
|
|
@@ -79,7 +95,7 @@ module TypeProf
|
|
79
95
|
nil
|
80
96
|
when Array
|
81
97
|
insn, *operands = e
|
82
|
-
operands = INSN_TABLE[insn].zip(operands).map do |type, operand|
|
98
|
+
operands = (INSN_TABLE[insn] || []).zip(operands).map do |type, operand|
|
83
99
|
case type
|
84
100
|
when "ISEQ"
|
85
101
|
operand && ISeq.new(operand)
|
data/lib/typeprof/method.rb
CHANGED
@@ -24,7 +24,7 @@ module TypeProf
|
|
24
24
|
callee_ep = do_send_core(fargs, start_pc, recv, mid, scratch)
|
25
25
|
|
26
26
|
scratch.add_iseq_method_call!(self, callee_ep.ctx)
|
27
|
-
scratch.add_callsite!(callee_ep.ctx,
|
27
|
+
scratch.add_callsite!(callee_ep.ctx, caller_ep, caller_env, &ctn)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -34,6 +34,7 @@ module TypeProf
|
|
34
34
|
rest_start = @iseq.fargs_format[:rest_start]
|
35
35
|
kw_start = @iseq.fargs_format[:kwbits]
|
36
36
|
kw_start -= @iseq.fargs_format[:keyword].size if kw_start
|
37
|
+
kw_rest = @iseq.fargs_format[:kwrest]
|
37
38
|
block_start = @iseq.fargs_format[:block_start]
|
38
39
|
|
39
40
|
# XXX: need to check .rbs fargs and .rb fargs
|
@@ -72,13 +73,18 @@ module TypeProf
|
|
72
73
|
end
|
73
74
|
end
|
74
75
|
if fargs.kw_tys
|
75
|
-
fargs.kw_tys.each_with_index do |(_,
|
76
|
-
alloc_site2 = alloc_site.add_id(
|
76
|
+
fargs.kw_tys.each_with_index do |(_, key, ty), i|
|
77
|
+
alloc_site2 = alloc_site.add_id(key)
|
77
78
|
nenv, ty = ty.localize(nenv, alloc_site2, Config.options[:type_depth_limit])
|
78
79
|
nenv = nenv.local_update(kw_start + i, ty)
|
79
80
|
end
|
80
81
|
end
|
81
|
-
|
82
|
+
if fargs.kw_rest_ty
|
83
|
+
ty = fargs.kw_rest_ty
|
84
|
+
alloc_site2 = alloc_site.add_id(:**)
|
85
|
+
nenv, ty = ty.localize(nenv, alloc_site2, Config.options[:type_depth_limit])
|
86
|
+
nenv = nenv.local_update(kw_rest, ty)
|
87
|
+
end
|
82
88
|
nenv = nenv.local_update(block_start, fargs.blk_ty) if block_start
|
83
89
|
|
84
90
|
scratch.merge_env(callee_ep, nenv)
|
@@ -158,18 +164,36 @@ module TypeProf
|
|
158
164
|
# XXX: support self type in fargs
|
159
165
|
subst = { Type::Var.new(:self) => recv }
|
160
166
|
next unless aargs.consistent_with_formal_arguments?(fargs, subst)
|
161
|
-
|
167
|
+
case
|
168
|
+
when recv.is_a?(Type::Cell) && recv_orig.is_a?(Type::LocalCell)
|
169
|
+
tyvars = recv.base_type.klass.type_params.map {|name,| Type::Var.new(name) }
|
170
|
+
tyvars.each_with_index do |tyvar, idx|
|
171
|
+
ty = subst[tyvar]
|
172
|
+
if ty
|
173
|
+
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
|
+
Utils.array_update(elems, idx, elems[idx].union(ty))
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
tyvars.zip(recv.elems) do |tyvar, elem|
|
180
|
+
if subst[tyvar]
|
181
|
+
subst[tyvar] = subst[tyvar].union(elem)
|
182
|
+
else
|
183
|
+
subst[tyvar] = elem
|
184
|
+
end
|
185
|
+
end
|
186
|
+
when recv.is_a?(Type::Array) && recv_orig.is_a?(Type::LocalArray)
|
162
187
|
tyvar_elem = Type::Var.new(:Elem)
|
163
188
|
if subst[tyvar_elem]
|
164
189
|
ty = subst[tyvar_elem]
|
165
|
-
alloc_site = AllocationSite.new(caller_ep).add_id(self)
|
166
190
|
ncaller_env, ty = scratch.localize_type(ty, ncaller_env, caller_ep)
|
167
191
|
ncaller_env = scratch.update_container_elem_types(ncaller_env, caller_ep, recv_orig.id) do |elems|
|
168
192
|
elems.update(nil, ty)
|
169
193
|
end
|
170
194
|
end
|
171
195
|
subst.merge!({ tyvar_elem => recv.elems.squash })
|
172
|
-
|
196
|
+
when recv.is_a?(Type::Hash) && recv_orig.is_a?(Type::LocalHash)
|
173
197
|
tyvar_k = Type::Var.new(:K)
|
174
198
|
tyvar_v = Type::Var.new(:V)
|
175
199
|
# XXX: need to support destructive operation
|
@@ -184,7 +208,7 @@ module TypeProf
|
|
184
208
|
dummy_ep = ExecutionPoint.new(dummy_ctx, -1, caller_ep)
|
185
209
|
dummy_env = Env.new(StaticEnv.new(recv, fargs.blk_ty, false), [], [], Utils::HashWrapper.new({}))
|
186
210
|
if fargs.blk_ty.is_a?(Type::TypedProc)
|
187
|
-
scratch.add_callsite!(dummy_ctx,
|
211
|
+
scratch.add_callsite!(dummy_ctx, caller_ep, ncaller_env, &ctn)
|
188
212
|
nfargs = fargs.blk_ty.fargs
|
189
213
|
alloc_site = AllocationSite.new(caller_ep).add_id(self)
|
190
214
|
nlead_tys = (nfargs.lead_tys + nfargs.opt_tys).map.with_index do |ty, i|
|
@@ -200,7 +224,7 @@ module TypeProf
|
|
200
224
|
ty
|
201
225
|
end
|
202
226
|
0.upto(nfargs.opt_tys.size) do |n|
|
203
|
-
naargs = ActualArguments.new(nlead_tys[0, nfargs.lead_tys.size + n], nil,
|
227
|
+
naargs = ActualArguments.new(nlead_tys[0, nfargs.lead_tys.size + n], nil, {}, Type.nil) # XXX: support block to block?
|
204
228
|
scratch.do_invoke_block(false, aargs.blk_ty, naargs, dummy_ep, dummy_env) do |blk_ret_ty, _ep, _env|
|
205
229
|
subst2 = {}
|
206
230
|
if blk_ret_ty.consistent?(fargs.blk_ty.ret_ty, subst2)
|
data/lib/typeprof/type.rb
CHANGED
@@ -3,7 +3,7 @@ module TypeProf
|
|
3
3
|
include Utils::StructuralEquality
|
4
4
|
|
5
5
|
def initialize
|
6
|
-
raise "cannot
|
6
|
+
raise "cannot instantiate abstract type"
|
7
7
|
end
|
8
8
|
|
9
9
|
Builtin = {}
|
@@ -129,6 +129,17 @@ module TypeProf
|
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
|
+
class Void < Any
|
133
|
+
def inspect
|
134
|
+
"Type::Void"
|
135
|
+
end
|
136
|
+
|
137
|
+
def screen_name(scratch)
|
138
|
+
"void"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
132
143
|
class Union < Type
|
133
144
|
def initialize(tys, elems)
|
134
145
|
raise unless tys.is_a?(Utils::Set)
|
@@ -810,8 +821,6 @@ module TypeProf
|
|
810
821
|
raise if !!kws1[kw] != !!kws2[kw]
|
811
822
|
end
|
812
823
|
elsif @kw_tys || other.kw_tys
|
813
|
-
puts
|
814
|
-
p self, other
|
815
824
|
(@kw_tys || other.kw_tys).each do |req,|
|
816
825
|
raise if req
|
817
826
|
end
|
@@ -865,15 +874,16 @@ module TypeProf
|
|
865
874
|
|
866
875
|
# Arguments from caller side
|
867
876
|
class ActualArguments
|
868
|
-
def initialize(lead_tys, rest_ty,
|
877
|
+
def initialize(lead_tys, rest_ty, kw_tys, blk_ty)
|
869
878
|
@lead_tys = lead_tys
|
870
879
|
@rest_ty = rest_ty
|
871
|
-
@
|
880
|
+
@kw_tys = kw_tys # kw_tys should be {:key1 => Type.bool, :key2 => Type.bool, ...} or {nil => Type.bool}
|
881
|
+
raise if !kw_tys.is_a?(::Hash)
|
872
882
|
@blk_ty = blk_ty
|
873
883
|
raise unless blk_ty
|
874
884
|
end
|
875
885
|
|
876
|
-
attr_reader :lead_tys, :rest_ty, :
|
886
|
+
attr_reader :lead_tys, :rest_ty, :kw_tys, :blk_ty
|
877
887
|
|
878
888
|
def merge(aargs)
|
879
889
|
len = [@lead_tys.size, aargs.lead_tys.size].min
|
@@ -886,16 +896,25 @@ module TypeProf
|
|
886
896
|
rest_ty = rest_ty.union(ty)
|
887
897
|
end
|
888
898
|
rest_ty = nil if rest_ty == Type.bot
|
889
|
-
|
899
|
+
kw_tys = @kw_tys.dup
|
900
|
+
aargs.kw_tys.each do |sym, ty|
|
901
|
+
if kw_tys[sym]
|
902
|
+
kw_tys[sym] = kw_tys[sym].union(ty)
|
903
|
+
else
|
904
|
+
kw_tys[sym] = ty
|
905
|
+
end
|
906
|
+
end
|
890
907
|
blk_ty = @blk_ty.union(aargs.blk_ty)
|
891
|
-
ActualArguments.new(lead_tys, rest_ty,
|
908
|
+
ActualArguments.new(lead_tys, rest_ty, kw_tys, blk_ty)
|
892
909
|
end
|
893
910
|
|
894
911
|
def globalize(caller_env, visited, depth)
|
895
912
|
lead_tys = @lead_tys.map {|ty| ty.globalize(caller_env, visited, depth) }
|
896
913
|
rest_ty = @rest_ty.globalize(caller_env, visited, depth) if @rest_ty
|
897
|
-
|
898
|
-
|
914
|
+
kw_tys = @kw_tys.to_h do |key, ty|
|
915
|
+
[key, ty.globalize(caller_env, visited, depth)]
|
916
|
+
end
|
917
|
+
ActualArguments.new(lead_tys, rest_ty, kw_tys, @blk_ty)
|
899
918
|
end
|
900
919
|
|
901
920
|
def limit_size(limit)
|
@@ -942,6 +961,7 @@ module TypeProf
|
|
942
961
|
lower_bound = upper_bound = 0
|
943
962
|
end
|
944
963
|
|
964
|
+
a_kw_tys = @kw_tys.dup
|
945
965
|
if keyword
|
946
966
|
kw_tys = []
|
947
967
|
keyword.each do |kw|
|
@@ -959,14 +979,12 @@ module TypeProf
|
|
959
979
|
req = false
|
960
980
|
end
|
961
981
|
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
ty = @kw_ty.elems[sym]
|
967
|
-
# XXX: remove the key
|
982
|
+
if a_kw_tys.key?(key)
|
983
|
+
ty = a_kw_tys.delete(key)
|
984
|
+
else
|
985
|
+
ty = a_kw_tys[nil] || Type.bot
|
968
986
|
end
|
969
|
-
if ty == Type.bot
|
987
|
+
if ty == Type.bot && req
|
970
988
|
yield "no argument for required keywords"
|
971
989
|
return
|
972
990
|
end
|
@@ -975,12 +993,18 @@ module TypeProf
|
|
975
993
|
end
|
976
994
|
end
|
977
995
|
if kw_rest_acceptable
|
978
|
-
|
979
|
-
|
980
|
-
|
996
|
+
if a_kw_tys.key?(nil)
|
997
|
+
kw_rest_ty = Type.gen_hash {|h| h[Type.any] = a_kw_tys[nil] }
|
998
|
+
else
|
999
|
+
kw_rest_ty = Type.gen_hash do |h|
|
1000
|
+
a_kw_tys.each do |key, ty|
|
1001
|
+
sym = Type::Symbol.new(key, Type::Instance.new(Type::Builtin[:sym]))
|
1002
|
+
h[sym] = ty
|
1003
|
+
end
|
1004
|
+
end
|
981
1005
|
end
|
982
1006
|
end
|
983
|
-
#if @
|
1007
|
+
#if @kw_tys
|
984
1008
|
# yield "passed a keyword to non-keyword method"
|
985
1009
|
#end
|
986
1010
|
|
@@ -1023,7 +1047,7 @@ module TypeProf
|
|
1023
1047
|
lower_bound = [0, fargs.lead_tys.size + fargs.post_tys.size - aargs.size].max
|
1024
1048
|
upper_bound = [0, lower_bound + fargs.opt_tys.size].max
|
1025
1049
|
(lower_bound..upper_bound).each do |n|
|
1026
|
-
tmp_aargs = ActualArguments.new(@lead_tys + [@rest_ty] * n, nil, @
|
1050
|
+
tmp_aargs = ActualArguments.new(@lead_tys + [@rest_ty] * n, nil, @kw_tys, @blk_ty)
|
1027
1051
|
if tmp_aargs.consistent_with_formal_arguments?(fargs, subst)
|
1028
1052
|
return true
|
1029
1053
|
end
|
@@ -1078,8 +1102,12 @@ module TypeProf
|
|
1078
1102
|
if @rest_ty
|
1079
1103
|
aargs << ("*" + @rest_ty.screen_name(scratch))
|
1080
1104
|
end
|
1081
|
-
if @
|
1082
|
-
aargs << (
|
1105
|
+
if @kw_tys.key?(nil)
|
1106
|
+
aargs << "(unknown key): #{ @kw_tys[nil].screen_name(scratch) }"
|
1107
|
+
else
|
1108
|
+
@kw_tys.sort.each do |key, ty|
|
1109
|
+
aargs << "#{ key }: #{ ty.screen_name(scratch) }"
|
1110
|
+
end
|
1083
1111
|
end
|
1084
1112
|
s = "(#{ aargs.join(", ") })"
|
1085
1113
|
s << " { #{ scratch.proc_screen_name(@blk_ty) } }" if @blk_ty != Type.nil
|