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.
@@ -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 "statistics:"
203
- output.puts " %d execution points" % stat_eps.size
204
- output.puts " %d classes" % stat_classes.size
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
@@ -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
- classes
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
- @all_env.class_decls[name].decls.each do |decl|
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 [:any]
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
- [:any]
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
- Import.new(scratch, scratch.rbs_reader.load_path(Pathname(rbs_path))).import(true)
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.map do |sig_ret|
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
- blk = blk ? conv_block(blk) : Type.nil
521
- fargs = FormalArguments.new(lead_tys, opt_tys, rest_ty, [], kw_tys, kw_rest_ty, blk)
537
+
538
+ blks = conv_block(blk)
522
539
 
523
540
  ret_ty = conv_type(ret_ty)
524
541
 
525
- [fargs, ret_ty]
526
- end.compact
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
- lead_tys, opt_tys, ret_ty = blk
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
@@ -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)
@@ -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, fargs, caller_ep, caller_env, &ctn)
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 |(_, _, ty), i|
76
- alloc_site2 = alloc_site.add_id(idx += 1)
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
- # kwrest
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
- if recv.is_a?(Type::Array) && recv_orig.is_a?(Type::LocalArray)
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
- elsif recv.is_a?(Type::Hash) && recv_orig.is_a?(Type::LocalHash)
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, nil, caller_ep, ncaller_env, &ctn)
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, nil, Type.nil) # XXX: support block to block?
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)
@@ -3,7 +3,7 @@ module TypeProf
3
3
  include Utils::StructuralEquality
4
4
 
5
5
  def initialize
6
- raise "cannot instanciate abstract type"
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, kw_ty, blk_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
- @kw_ty = kw_ty
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, :kw_ty, :blk_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
- #kw_ty = @kw_ty.union(aargs.kw_ty) # TODO
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, kw_ty, blk_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
- kw_ty = @kw_ty.globalize(caller_env, visited, depth) if @kw_ty
898
- ActualArguments.new(lead_tys, rest_ty, kw_ty, @blk_ty)
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
- sym = Type::Symbol.new(key, Type::Instance.new(Type::Builtin[:sym]))
963
- ty = Type.bot
964
- if @kw_ty.is_a?(Type::Hash)
965
- # XXX: consider Union
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
- kw_rest_ty = @kw_ty
979
- if kw_rest_ty == Type.any
980
- kw_rest_ty = Type.gen_hash {|h| h[Type.any] = Type.any }
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 @kw_ty
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, @kw_ty, @blk_ty)
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 @kw_ty
1082
- aargs << ("**" + @kw_ty.screen_name(scratch)) # TODO: Hash notation -> keyword notation
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