typeprof 0.2.0 → 0.3.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/.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
|