typeprof 0.4.2 → 0.5.4

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +1 -2
  3. data/Gemfile.lock +3 -3
  4. data/README.md +6 -0
  5. data/lib/typeprof/analyzer.rb +97 -84
  6. data/lib/typeprof/arguments.rb +27 -19
  7. data/lib/typeprof/block.rb +5 -2
  8. data/lib/typeprof/builtin.rb +14 -4
  9. data/lib/typeprof/config.rb +10 -6
  10. data/lib/typeprof/container-type.rb +117 -101
  11. data/lib/typeprof/export.rb +1 -1
  12. data/lib/typeprof/import.rb +44 -22
  13. data/lib/typeprof/method.rb +70 -12
  14. data/lib/typeprof/type.rb +108 -89
  15. data/lib/typeprof/version.rb +1 -1
  16. data/smoke/arguments2.rb +1 -1
  17. data/smoke/array11.rb +1 -1
  18. data/smoke/array6.rb +2 -2
  19. data/smoke/array8.rb +1 -1
  20. data/smoke/block-args2.rb +3 -3
  21. data/smoke/block-args3.rb +4 -4
  22. data/smoke/block-blockarg.rb +1 -1
  23. data/smoke/block-kwarg.rb +1 -1
  24. data/smoke/block10.rb +1 -1
  25. data/smoke/block5.rb +1 -1
  26. data/smoke/constant2.rb +1 -2
  27. data/smoke/demo5.rb +1 -1
  28. data/smoke/demo9.rb +1 -1
  29. data/smoke/hash-fetch.rb +3 -3
  30. data/smoke/hash-merge-bang.rb +11 -0
  31. data/smoke/hash1.rb +3 -2
  32. data/smoke/hash3.rb +1 -1
  33. data/smoke/inheritance2.rb +2 -2
  34. data/smoke/ivar2.rb +2 -2
  35. data/smoke/kernel-class.rb +1 -1
  36. data/smoke/keyword4.rb +1 -1
  37. data/smoke/kwsplat1.rb +2 -2
  38. data/smoke/kwsplat2.rb +1 -1
  39. data/smoke/multiple-superclass.rb +1 -1
  40. data/smoke/parameterizedd-self.rb +2 -2
  41. data/smoke/pattern-match1.rb +23 -0
  42. data/smoke/pattern-match2.rb +15 -0
  43. data/smoke/rbs-tyvar3.rb +11 -19
  44. data/smoke/rbs-tyvar3.rbs +4 -3
  45. data/smoke/rbs-tyvar4.rb +36 -0
  46. data/smoke/rbs-tyvar5.rb +12 -0
  47. data/smoke/rbs-tyvar5.rbs +8 -0
  48. data/smoke/struct.rb +2 -2
  49. data/smoke/uninitialize-var.rb +12 -0
  50. data/smoke/union-recv.rb +2 -2
  51. data/typeprof.gemspec +1 -1
  52. metadata +11 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2ffa092b1a33661649a9a3b48347d78baf5d9bac0ba4020f72a122442d4d287
4
- data.tar.gz: fbe985ca3547bd831564f5921f38edf65160c86133bb0219596aaa4e5962066a
3
+ metadata.gz: 2d60066fe3965ec65f9885e311f856277d0e41330478489c026fdf6b387ba2ba
4
+ data.tar.gz: 963b66fe97d98207d72645011bcd012368937ded76278d92a4b677b961c92cdc
5
5
  SHA512:
6
- metadata.gz: b260426c710befa65825fc41998643ced8ef3b43d4edc16b5eb9a2f00cbaf865c832f80ee3443c6a8e9f725e5def2d6bd47a1109e97dffaab8d17771035ae08a
7
- data.tar.gz: 47cf9f339601864c16464859d92aa9b904e51c471da84c2f2997519947edbc9c647b1762129cc0d677264fe0c0372de56acf04e98968a7b6e1c372d43af8a543
6
+ metadata.gz: a40e89e05c1680480eb66798863ab99a4b38b3faaacdc471a6cdd45dfc1f897efcc8f613800ef28e5bc722c3504dec510ca943435873b6cb765a27f1bb073425
7
+ data.tar.gz: 94dddf2c3e465ee19093ce571d50440293118b07ab7c90203aa5ccb40c4f9eb9afe1059eff045c965006affa8f0d66d141be2064feddf9a2b1f8384f8cadae64
@@ -17,9 +17,8 @@ jobs:
17
17
  uses: ruby/setup-ruby@v1
18
18
  with:
19
19
  ruby-version: ${{ matrix.ruby-version }}
20
- - name: Set up RBS and bundle install
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: |
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- typeprof (0.4.1)
5
- rbs (>= 0.16.0)
4
+ typeprof (0.5.4)
5
+ rbs (>= 0.17.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
@@ -11,7 +11,7 @@ GEM
11
11
  docile (1.3.2)
12
12
  power_assert (1.2.0)
13
13
  rake (13.0.1)
14
- rbs (0.16.0)
14
+ rbs (0.17.0)
15
15
  simplecov (0.19.1)
16
16
  docile (~> 1.1)
17
17
  simplecov-html (~> 0.11)
data/README.md CHANGED
@@ -33,3 +33,9 @@ end
33
33
  ## Documentation
34
34
 
35
35
  [English](doc/doc.md) / [日本語](doc/doc.ja.md)
36
+
37
+ ## Playground
38
+
39
+ You can try typeprof gem on the Web via the URL below.
40
+
41
+ https://mame.github.io/typeprof-playground/
@@ -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
- if elems.is_a?(Array) # should be refactored as Cell::Elements
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
@@ -249,6 +252,8 @@ module TypeProf
249
252
  @rbs_reader = RBSReader.new
250
253
 
251
254
  @terminated = false
255
+
256
+ @anonymous_struct_gen_id = 0
252
257
  end
253
258
 
254
259
  attr_reader :return_envs, :loaded_features, :rbs_reader
@@ -293,20 +298,11 @@ module TypeProf
293
298
  attr_reader :kind, :superclass, :modules, :consts, :methods, :ivars, :cvars, :absolute_path
294
299
  attr_accessor :name, :klass_obj
295
300
 
296
- def include_module(mod, absolute_path)
297
- # XXX: need to check if mod is already included by the ancestors?
298
- absolute_paths = @modules[false][mod]
299
- unless absolute_paths
300
- @modules[false][mod] = absolute_paths = Utils::MutableSet.new
301
- end
302
- absolute_paths << absolute_path
303
- end
304
-
305
- def extend_module(mod, absolute_path)
301
+ def include_module(mod, singleton, absolute_path)
306
302
  # XXX: need to check if mod is already included by the ancestors?
307
- absolute_paths = @modules[true][mod]
303
+ absolute_paths = @modules[singleton][mod]
308
304
  unless absolute_paths
309
- @modules[true][mod] = absolute_paths = Utils::MutableSet.new
305
+ @modules[singleton][mod] = absolute_paths = Utils::MutableSet.new
310
306
  end
311
307
  absolute_paths << absolute_path
312
308
  end
@@ -353,7 +349,7 @@ module TypeProf
353
349
  end
354
350
  end
355
351
 
356
- def include_module(including_mod, included_mod, absolute_path)
352
+ def include_module(including_mod, included_mod, singleton, absolute_path)
357
353
  return if included_mod == Type.any
358
354
 
359
355
  including_mod = @class_defs[including_mod.idx]
@@ -361,7 +357,7 @@ module TypeProf
361
357
  if included_mod.is_a?(Type::Class)
362
358
  included_mod = @class_defs[included_mod.idx]
363
359
  if included_mod && included_mod.kind == :module
364
- including_mod.include_module(included_mod, absolute_path)
360
+ including_mod.include_module(included_mod, singleton, absolute_path)
365
361
  else
366
362
  warn "including something that is not a module"
367
363
  end
@@ -369,20 +365,6 @@ module TypeProf
369
365
  end
370
366
  end
371
367
 
372
- def extend_module(extending_mod, extended_mod, absolute_path)
373
- extending_mod = @class_defs[extending_mod.idx]
374
- extended_mod.each_child do |extended_mod|
375
- if extended_mod.is_a?(Type::Class)
376
- extended_mod = @class_defs[extended_mod.idx]
377
- if extended_mod && extended_mod.kind == :module
378
- extending_mod.extend_module(extended_mod, absolute_path)
379
- else
380
- warn "extending something that is not a module"
381
- end
382
- end
383
- end
384
- end
385
-
386
368
  def cbase_path(cbase)
387
369
  cbase && cbase.idx != 1 ? @class_defs[cbase.idx].name : []
388
370
  end
@@ -417,8 +399,9 @@ module TypeProf
417
399
 
418
400
  idx = @class_defs.size
419
401
  superclass = Type::Builtin[:struct]
420
- @class_defs[idx] = ClassDef.new(:class, ["(Anonymous Struct)"], superclass.idx, ep.ctx.iseq.absolute_path)
421
- klass = Type::Class.new(:class, idx, [], superclass, "(Anonymous Struct)")
402
+ name = "AnonymousStruct_generated_#{ @anonymous_struct_gen_id += 1 }"
403
+ @class_defs[idx] = ClassDef.new(:class, [name], superclass.idx, ep.ctx.iseq.absolute_path)
404
+ klass = Type::Class.new(:class, idx, [], superclass, name)
422
405
  @class_defs[idx].klass_obj = klass
423
406
 
424
407
  @struct_defs[ep] = klass
@@ -572,9 +555,7 @@ module TypeProf
572
555
 
573
556
  ret_ty = @return_values[callee_ctx] ||= Type.bot
574
557
  if ret_ty != Type.bot
575
- @callsites[callee_ctx].each do |caller_ep, ctn|
576
- ctn[ret_ty, caller_ep, @return_envs[caller_ep]]
577
- end
558
+ ctn[ret_ty, caller_ep, @return_envs[caller_ep]]
578
559
  end
579
560
  end
580
561
 
@@ -632,7 +613,7 @@ module TypeProf
632
613
  entry = @tbl[site] ||= Entry.new(!ep, {}, Type.bot, Utils::MutableSet.new)
633
614
  if ep
634
615
  if entry.rbs_declared
635
- if !entry.type.consistent?(ty, {})
616
+ unless Type.match?(ty, entry.type)
636
617
  scratch.warn(ep, "inconsistent assignment to RBS-declared global variable")
637
618
  return
638
619
  end
@@ -651,6 +632,7 @@ module TypeProf
651
632
  end
652
633
 
653
634
  def get_ivar(recv)
635
+ recv = recv.base_type while recv.respond_to?(:base_type)
654
636
  case recv
655
637
  when Type::Class
656
638
  [@class_defs[recv.idx], true]
@@ -884,26 +866,41 @@ module TypeProf
884
866
  def pend_method_execution(iseq, meth, recv, mid, cref)
885
867
  ctx = Context.new(iseq, cref, mid)
886
868
  ep = ExecutionPoint.new(ctx, 0, nil)
887
- locals = [Type.any] * iseq.locals.size
888
-
889
- keyword = iseq.fargs_format[:keyword]
869
+ locals = [Type.nil] * iseq.locals.size
870
+
871
+ fargs_format = iseq.fargs_format
872
+ lead_num = fargs_format[:lead_num] || 0
873
+ post_num = fargs_format[:post_num] || 0
874
+ post_index = fargs_format[:post_start]
875
+ rest_index = fargs_format[:rest_start]
876
+ keyword = fargs_format[:keyword]
877
+ kw_index = fargs_format[:kwbits] - keyword.size if keyword
878
+ kwrest_index = fargs_format[:kwrest]
879
+ block_index = fargs_format[:block_start]
880
+ opt = fargs_format[:opt] || [0]
881
+
882
+ (lead_num + opt.size - 1).times {|i| locals[i] = Type.any }
883
+ post_num.times {|i| locals[i + post_index] = Type.any } if post_index
884
+ locals[rest_index] = Type.any if rest_index
890
885
  if keyword
891
- kw_start = iseq.fargs_format[:kwbits]
892
- kw_start -= iseq.fargs_format[:keyword].size if kw_start
893
886
  keyword.each_with_index do |kw, i|
894
887
  case
895
888
  when kw.is_a?(Symbol) # required keyword
889
+ locals[kw_index + i] = Type.any
896
890
  when kw.size == 2 # optional keyword (default value is a literal)
897
891
  _key, default_ty = *kw
898
892
  default_ty = Type.guess_literal_type(default_ty)
899
- default_ty = default_ty.type if default_ty.is_a?(Type::Literal)
900
- locals[kw_start + i] = default_ty.union(Type.any)
893
+ default_ty = default_ty.base_type if default_ty.is_a?(Type::Literal)
894
+ locals[kw_index + i] = default_ty.union(Type.any)
901
895
  else # optional keyword (default value is an expression)
896
+ locals[kw_index + i] = Type.any
902
897
  end
903
898
  end
904
899
  end
900
+ locals[kwrest_index] = Type.any if kwrest_index
901
+ locals[block_index] = Type.nil if block_index
905
902
 
906
- env = Env.new(StaticEnv.new(recv, Type.any, false), locals, [], Utils::HashWrapper.new({}))
903
+ env = Env.new(StaticEnv.new(recv, Type.nil, false), locals, [], Utils::HashWrapper.new({}))
907
904
 
908
905
  @pending_execution[iseq] ||= [:method, [meth, ep, env]]
909
906
  end
@@ -986,7 +983,7 @@ module TypeProf
986
983
  when kw.size == 2 # optional keyword (default value is a literal)
987
984
  key, default_ty = *kw
988
985
  default_ty = Type.guess_literal_type(default_ty)
989
- default_ty = default_ty.type if default_ty.is_a?(Type::Literal)
986
+ default_ty = default_ty.base_type if default_ty.is_a?(Type::Literal)
990
987
  req = false
991
988
  else # optional keyword (default value is an expression)
992
989
  key, = kw
@@ -1029,7 +1026,17 @@ module TypeProf
1029
1026
  ty = Type::Literal.new(str, Type::Instance.new(Type::Builtin[:str]))
1030
1027
  env = env.push(ty)
1031
1028
  when :putself
1032
- env, ty = localize_type(env.static_env.recv_ty, env, ep)
1029
+ ty = env.static_env.recv_ty
1030
+ if ty.is_a?(Type::Instance)
1031
+ klass = ty.klass
1032
+ if klass.type_params.size >= 1
1033
+ ty = Type::ContainerType.create_empty_instance(klass)
1034
+ env, ty = localize_type(ty, env, ep, AllocationSite.new(ep))
1035
+ else
1036
+ ty = Type::Instance.new(klass)
1037
+ end
1038
+ env, ty = localize_type(ty, env, ep)
1039
+ end
1033
1040
  env = env.push(ty)
1034
1041
  when :newarray, :newarraykwsplat
1035
1042
  len, = operands
@@ -1128,35 +1135,29 @@ module TypeProf
1128
1135
  else
1129
1136
  if existing_klass != Type.any
1130
1137
  error(ep, "the class \"#{ id }\" is #{ existing_klass.screen_name(self) }")
1131
- id = :"#{ id }(dummy)"
1132
1138
  end
1133
- existing_klass = get_constant(cbase, id) # TODO: multiple return values
1134
- if existing_klass != Type.any
1135
- klass = existing_klass
1136
- else
1137
- if type == :class
1138
- if superclass.is_a?(Type::Class)
1139
- # okay
1140
- elsif superclass == Type.any
1141
- warn(ep, "superclass is any; Object is used instead")
1142
- superclass = Type::Builtin[:obj]
1143
- elsif superclass == Type.nil
1144
- superclass = Type::Builtin[:obj]
1145
- elsif superclass.is_a?(Type::Instance)
1146
- warn(ep, "superclass is an instance; Object is used instead")
1147
- superclass = Type::Builtin[:obj]
1148
- else
1149
- warn(ep, "superclass is not a class; Object is used instead")
1150
- superclass = Type::Builtin[:obj]
1151
- end
1152
- else # module
1153
- superclass = nil
1154
- end
1155
- if cbase == Type.any
1156
- klass = Type.any
1139
+ if type == :class
1140
+ if superclass.is_a?(Type::Class)
1141
+ # okay
1142
+ elsif superclass == Type.any
1143
+ warn(ep, "superclass is any; Object is used instead")
1144
+ superclass = Type::Builtin[:obj]
1145
+ elsif superclass == Type.nil
1146
+ superclass = Type::Builtin[:obj]
1147
+ elsif superclass.is_a?(Type::Instance)
1148
+ warn(ep, "superclass is an instance; Object is used instead")
1149
+ superclass = Type::Builtin[:obj]
1157
1150
  else
1158
- klass = new_class(cbase, id, [], superclass, ep.ctx.iseq.absolute_path)
1151
+ warn(ep, "superclass is not a class; Object is used instead")
1152
+ superclass = Type::Builtin[:obj]
1159
1153
  end
1154
+ else # module
1155
+ superclass = nil
1156
+ end
1157
+ if cbase == Type.any
1158
+ klass = Type.any
1159
+ else
1160
+ klass = new_class(cbase, id, [], superclass, ep.ctx.iseq.absolute_path)
1160
1161
  end
1161
1162
  end
1162
1163
  singleton = false
@@ -1700,15 +1701,27 @@ module TypeProf
1700
1701
  end
1701
1702
 
1702
1703
  when :checktype
1703
- type, = operands
1704
- raise NotImplementedError if type != 5 # T_STRING
1705
- # XXX: is_a?
1706
- env, (val,) = env.pop(1)
1707
- res = globalize_type(val, env, ep) == Type::Instance.new(Type::Builtin[:str])
1708
- if res
1709
- ty = Type::Instance.new(Type::Builtin[:true])
1704
+ kind, = operands
1705
+ case kind
1706
+ when 5 then klass = :str # T_STRING
1707
+ when 7 then klass = :ary # T_ARRAY
1708
+ when 8 then klass = :hash # T_HASH
1710
1709
  else
1711
- ty = Type::Instance.new(Type::Builtin[:false])
1710
+ raise NotImplementedError
1711
+ end
1712
+ env, (val,) = env.pop(1)
1713
+ ty = Type.bot
1714
+ val.each_child do |val|
1715
+ #globalize_type(val, env, ep).each_child_global do |val|
1716
+ val = val.base_type while val.respond_to?(:base_type)
1717
+ case val
1718
+ when Type::Instance.new(Type::Builtin[klass])
1719
+ ty = ty.union(Type::Instance.new(Type::Builtin[:true]))
1720
+ when Type.any
1721
+ ty = Type.bool
1722
+ else
1723
+ ty = ty.union(Type::Instance.new(Type::Builtin[:false]))
1724
+ end
1712
1725
  end
1713
1726
  env = env.push(ty)
1714
1727
  else
@@ -1946,7 +1959,7 @@ module TypeProf
1946
1959
  end
1947
1960
  end
1948
1961
 
1949
- @block_to_ctx[blk.block_body].each do |blk_ctx|
1962
+ @block_to_ctx[blk.block_body]&.each do |blk_ctx|
1950
1963
  ret_ty = ret_ty.union(@return_values[blk_ctx]) if @return_values[blk_ctx]
1951
1964
  end
1952
1965
  end
@@ -25,7 +25,7 @@ module TypeProf
25
25
  self
26
26
  end
27
27
 
28
- def consistent_with_method_signature?(msig, subst)
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
- if tmp_aargs.consistent_with_method_signature?(msig, subst) # XXX: wrong subst handling in the loop!
40
- return true
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 false
42
+ return nil
44
43
  end
45
44
 
45
+ subst = {}
46
46
  if msig.rest_ty
47
- return false if aargs.size < msig.lead_tys.size + msig.post_tys.size
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 false unless aarg.consistent?(farg, subst)
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 false unless aarg.consistent?(farg, subst)
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 false unless aarg.consistent?(farg, subst)
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 false unless aarg.consistent?(msig.rest_ty, subst)
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 false if aargs.size < msig.lead_tys.size + msig.post_tys.size
63
- return false if aargs.size > msig.lead_tys.size + msig.post_tys.size + msig.opt_tys.size
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 false unless aarg.consistent?(farg, subst)
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 false unless aarg.consistent?(farg, subst)
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 false unless aarg.consistent?(farg, subst)
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 false if @blk_ty == Type.nil
85
+ return nil if @blk_ty == Type.nil
79
86
  when Type.nil
80
- return false if @blk_ty != Type.nil
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
- true
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.type if default_ty.is_a?(Type::Literal)
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