typeprof 0.3.0 → 0.4.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/doc/demo.md +398 -0
  4. data/doc/doc.ja.md +4 -0
  5. data/doc/doc.md +4 -0
  6. data/lib/typeprof.rb +8 -0
  7. data/lib/typeprof/analyzer.rb +229 -245
  8. data/lib/typeprof/arguments.rb +397 -0
  9. data/lib/typeprof/block.rb +133 -0
  10. data/lib/typeprof/builtin.rb +14 -10
  11. data/lib/typeprof/container-type.rb +94 -17
  12. data/lib/typeprof/export.rb +185 -108
  13. data/lib/typeprof/import.rb +76 -54
  14. data/lib/typeprof/iseq.rb +27 -2
  15. data/lib/typeprof/method.rb +87 -73
  16. data/lib/typeprof/type.rb +125 -309
  17. data/lib/typeprof/version.rb +1 -1
  18. data/smoke/arguments2.rb +1 -1
  19. data/smoke/array-each3.rb +1 -4
  20. data/smoke/array12.rb +1 -1
  21. data/smoke/array6.rb +1 -0
  22. data/smoke/block-ambiguous.rb +36 -0
  23. data/smoke/block-args1-rest.rb +62 -0
  24. data/smoke/block-args1.rb +59 -0
  25. data/smoke/block-args2-rest.rb +62 -0
  26. data/smoke/block-args2.rb +59 -0
  27. data/smoke/block-args3-rest.rb +73 -0
  28. data/smoke/block-args3.rb +70 -0
  29. data/smoke/block-blockarg.rb +27 -0
  30. data/smoke/block-kwarg.rb +52 -0
  31. data/smoke/block11.rb +1 -1
  32. data/smoke/block14.rb +17 -0
  33. data/smoke/block4.rb +2 -2
  34. data/smoke/block5.rb +1 -0
  35. data/smoke/block6.rb +1 -1
  36. data/smoke/block7.rb +0 -2
  37. data/smoke/block8.rb +2 -2
  38. data/smoke/block9.rb +1 -1
  39. data/smoke/blown.rb +1 -1
  40. data/smoke/class-hierarchy.rb +54 -0
  41. data/smoke/class-hierarchy2.rb +27 -0
  42. data/smoke/constant1.rb +11 -6
  43. data/smoke/constant2.rb +2 -0
  44. data/smoke/cvar.rb +1 -0
  45. data/smoke/demo10.rb +1 -1
  46. data/smoke/demo8.rb +2 -2
  47. data/smoke/demo9.rb +1 -3
  48. data/smoke/flow7.rb +1 -7
  49. data/smoke/flow8.rb +13 -0
  50. data/smoke/instance_eval.rb +1 -1
  51. data/smoke/int_times.rb +1 -1
  52. data/smoke/multiple-superclass.rb +4 -0
  53. data/smoke/next2.rb +1 -1
  54. data/smoke/optional3.rb +10 -0
  55. data/smoke/proc4.rb +1 -1
  56. data/smoke/rbs-proc1.rb +9 -0
  57. data/smoke/rbs-proc1.rbs +3 -0
  58. data/smoke/rbs-proc2.rb +20 -0
  59. data/smoke/rbs-proc2.rbs +3 -0
  60. data/smoke/rbs-proc3.rb +13 -0
  61. data/smoke/rbs-proc3.rbs +4 -0
  62. data/smoke/rbs-record.rb +17 -0
  63. data/smoke/rbs-record.rbs +4 -0
  64. data/smoke/rbs-tyvar3.rb +25 -0
  65. data/smoke/rbs-tyvar3.rbs +4 -0
  66. data/smoke/rest2.rb +1 -1
  67. data/smoke/rest5.rb +1 -1
  68. data/smoke/return.rb +1 -1
  69. data/smoke/singleton_method.rb +3 -0
  70. data/smoke/struct.rb +4 -3
  71. data/smoke/struct3.rb +14 -0
  72. data/smoke/symbol-proc.rb +24 -0
  73. metadata +31 -3
  74. data/smoke/variadic1.rb.notyet +0 -5
@@ -148,7 +148,7 @@ module TypeProf
148
148
  # invariant check
149
149
  local = nil
150
150
  tys.each do |ty|
151
- raise unless ty.is_a?(Type)
151
+ raise ty.inspect unless ty.is_a?(Type)
152
152
  local = true if ty.is_a?(LocalArray) || ty.is_a?(LocalHash)
153
153
  end
154
154
  raise if local && elems
@@ -226,12 +226,15 @@ module TypeProf
226
226
  bool = true
227
227
  end
228
228
  types.delete(Type.any) unless Config.options[:pedantic_output]
229
+ proc_tys, types = types.partition {|ty| ty.is_a?(Proc) }
229
230
  types = types.map {|ty| ty.screen_name(scratch) }
231
+ types << scratch.show_proc_signature(proc_tys) unless proc_tys.empty?
230
232
  types << "bool" if bool
231
233
  types = types.sort
232
234
  if optional
233
- if types.size == 1
234
- types.first + "?"
235
+ case types.size
236
+ when 0 then "nil"
237
+ when 1 then types.first + "?"
235
238
  else
236
239
  "(#{ types.join (" | ") })?"
237
240
  end
@@ -516,56 +519,51 @@ module TypeProf
516
519
  end
517
520
  end
518
521
 
519
- class ISeqProc < Type
520
- def initialize(iseq, ep, type)
521
- @iseq = iseq
522
- @ep = ep
523
- @type = type
522
+ class Proc < Type
523
+ def initialize(block_body, type)
524
+ @block_body, @type = block_body, type
524
525
  end
525
526
 
526
- attr_reader :iseq, :ep, :type
527
-
528
- def inspect
529
- "#<ISeqProc>"
530
- end
527
+ attr_reader :block_body, :type
531
528
 
532
- def screen_name(scratch)
533
- "Proc[#{ scratch.proc_screen_name(self) }]" # TODO: use RBS syntax
529
+ def consistent?(other, subst)
530
+ case other
531
+ when Type::Any then true
532
+ when Type::Var then other.add_subst!(self, subst)
533
+ when Type::Union
534
+ other.types.each do |ty2|
535
+ return true if consistent?(ty2, subst)
536
+ end
537
+ when Type::Proc
538
+ @block_body.consistent?(other.block_body)
539
+ else
540
+ self == other
541
+ end
534
542
  end
535
543
 
536
544
  def get_method(mid, scratch)
537
545
  @type.get_method(mid, scratch)
538
546
  end
539
547
 
540
- def substitute(_subst, _depth)
541
- self # XXX
542
- end
543
- end
544
-
545
- class TypedProc < Type
546
- def initialize(fargs, ret_ty, type)
547
- @fargs = fargs
548
- @ret_ty = ret_ty
549
- @type = type
548
+ def substitute(subst, depth)
549
+ Proc.new(@block_body.substitute(subst, depth), @type)
550
550
  end
551
551
 
552
- attr_reader :fargs, :ret_ty
553
-
554
552
  def screen_name(scratch)
555
- "TypedProc[...]" # TODO: use RBS syntax
553
+ scratch.show_proc_signature([self])
556
554
  end
557
555
  end
558
556
 
559
557
  class Symbol < Type
560
- def initialize(sym, type)
558
+ def initialize(sym, base_type)
561
559
  @sym = sym
562
- @type = type
560
+ @base_type = base_type
563
561
  end
564
562
 
565
- attr_reader :sym, :type
563
+ attr_reader :sym, :base_type
566
564
 
567
565
  def inspect
568
- "Type::Symbol[#{ @sym ? @sym.inspect : "(dynamic symbol)" }, #{ @type.inspect }]"
566
+ "Type::Symbol[#{ @sym ? @sym.inspect : "(dynamic symbol)" }, #{ @base_type.inspect }]"
569
567
  end
570
568
 
571
569
  def consistent?(other, subst)
@@ -575,7 +573,7 @@ module TypeProf
575
573
  when Symbol
576
574
  @sym == other.sym
577
575
  else
578
- @type.consistent?(other, subst)
576
+ @base_type.consistent?(other, subst)
579
577
  end
580
578
  end
581
579
 
@@ -583,12 +581,12 @@ module TypeProf
583
581
  if @sym
584
582
  @sym.inspect
585
583
  else
586
- @type.screen_name(scratch)
584
+ @base_type.screen_name(scratch)
587
585
  end
588
586
  end
589
587
 
590
588
  def get_method(mid, scratch)
591
- @type.get_method(mid, scratch)
589
+ @base_type.get_method(mid, scratch)
592
590
  end
593
591
 
594
592
  def substitute(_subst, _depth)
@@ -747,66 +745,74 @@ module TypeProf
747
745
  end
748
746
  end
749
747
 
750
- # Arguments for callee side
751
- class FormalArguments
748
+ class Signature
752
749
  include Utils::StructuralEquality
753
750
 
754
- def initialize(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
755
- @lead_tys = lead_tys
756
- @opt_tys = opt_tys
757
- @rest_ty = rest_ty
758
- @post_tys = post_tys
759
- @kw_tys = kw_tys
760
- kw_tys.each {|a| raise if a.size != 3 } if kw_tys
761
- @kw_rest_ty = kw_rest_ty
762
- @blk_ty = blk_ty
763
- end
764
-
765
- attr_reader :lead_tys, :opt_tys, :rest_ty, :post_tys, :kw_tys, :kw_rest_ty, :blk_ty
766
-
767
- def consistent?(fargs, subst)
768
- warn "used?"
769
- return false if @lead_tys.size != fargs.lead_tys.size
770
- return false unless @lead_tys.zip(fargs.lead_tys).all? {|ty1, ty2| ty1.consistent?(ty2, subst) }
771
- return false if (@opt_tys || []) != (fargs.opt_tys || []) # ??
772
- if @rest_ty
773
- return false unless @rest_ty.consistent?(fargs.rest_ty, subst)
774
- end
775
- if @post_tys
776
- return false if @post_tys.size != fargs.post_tys.size
777
- return false unless @post_tys.zip(fargs.post_tys).all? {|ty1, ty2| ty1.consistent?(ty2, subst) }
778
- end
779
- return false if @kw_tys.size != fargs.kw_tys.size
780
- return false unless @kw_tys.zip(fargs.kw_tys).all? {|(_, ty1), (_, ty2)| ty1.consistent?(ty2, subst) }
781
- if @kw_rest_ty
782
- return false unless @kw_rest_ty.consistent?(fargs.kw_rest_ty, subst)
783
- end
784
- # intentionally skip blk_ty
785
- true
786
- end
787
-
788
751
  def screen_name(scratch)
789
- fargs = @lead_tys.map {|ty| ty.screen_name(scratch) }
752
+ str = @lead_tys.map {|ty| ty.screen_name(scratch) }
790
753
  if @opt_tys
791
- fargs += @opt_tys.map {|ty| "?" + ty.screen_name(scratch) }
754
+ str += @opt_tys.map {|ty| "?" + ty.screen_name(scratch) }
792
755
  end
793
756
  if @rest_ty
794
- fargs << ("*" + @rest_ty.screen_name(scratch))
757
+ str << ("*" + @rest_ty.screen_name(scratch))
795
758
  end
796
759
  if @post_tys
797
- fargs += @post_tys.map {|ty| ty.screen_name(scratch) }
760
+ str += @post_tys.map {|ty| ty.screen_name(scratch) }
798
761
  end
799
762
  if @kw_tys
800
763
  @kw_tys.each do |req, sym, ty|
801
764
  opt = req ? "" : "?"
802
- fargs << "#{ opt }#{ sym }: #{ ty.screen_name(scratch) }"
765
+ str << "#{ opt }#{ sym }: #{ ty.screen_name(scratch) }"
803
766
  end
804
767
  end
805
768
  if @kw_rest_ty
806
- fargs << ("**" + @kw_rest_ty.screen_name(scratch))
769
+ str << ("**" + @kw_rest_ty.screen_name(scratch))
770
+ end
771
+ str = str.empty? ? "" : "(#{ str.join(", ") })"
772
+
773
+ optional = false
774
+ blks = []
775
+ @blk_ty.each_child_global do |ty|
776
+ if ty.is_a?(Type::Proc)
777
+ blks << ty
778
+ else
779
+ # XXX: how should we handle types other than Type.nil
780
+ optional = true
781
+ end
807
782
  end
808
- # intentionally skip blk_ty
809
- fargs
783
+ if blks != []
784
+ str << " " if str != ""
785
+ str << "?" if optional
786
+ str << scratch.show_block_signature(blks)
787
+ end
788
+
789
+ str
790
+ end
791
+ end
792
+
793
+ class MethodSignature < Signature
794
+ def initialize(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
795
+ @lead_tys = lead_tys
796
+ @opt_tys = opt_tys
797
+ @rest_ty = rest_ty
798
+ @post_tys = post_tys
799
+ @kw_tys = kw_tys
800
+ kw_tys.each {|a| raise if a.size != 3 } if kw_tys
801
+ @kw_rest_ty = kw_rest_ty
802
+ @blk_ty = blk_ty
803
+ end
804
+
805
+ attr_reader :lead_tys, :opt_tys, :rest_ty, :post_tys, :kw_tys, :kw_rest_ty, :blk_ty
806
+
807
+ def substitute(subst, depth)
808
+ lead_tys = @lead_tys.map {|ty| ty.substitute(subst, depth - 1) }
809
+ opt_tys = @opt_tys.map {|ty| ty.substitute(subst, depth - 1) }
810
+ rest_ty = @rest_ty&.substitute(subst, depth - 1)
811
+ post_tys = @post_tys.map {|ty| ty.substitute(subst, depth - 1) }
812
+ kw_tys = @kw_tys.map {|req, key, ty| [req, key, ty.substitute(subst, depth - 1)] }
813
+ kw_rest_ty = @kw_rest_ty&.substitute(subst, depth - 1)
814
+ blk_ty = @blk_ty.substitute(subst, depth - 1)
815
+ MethodSignature.new(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
810
816
  end
811
817
 
812
818
  def merge(other)
@@ -868,250 +874,60 @@ module TypeProf
868
874
  end
869
875
  end
870
876
  blk_ty = @blk_ty.union(other.blk_ty) if @blk_ty
871
- FormalArguments.new(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
877
+ MethodSignature.new(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
872
878
  end
873
879
  end
874
880
 
875
- # Arguments from caller side
876
- class ActualArguments
877
- def initialize(lead_tys, rest_ty, kw_tys, blk_ty)
881
+ class BlockSignature < Signature
882
+ def initialize(lead_tys, opt_tys, rest_ty, blk_ty)
878
883
  @lead_tys = lead_tys
884
+ @opt_tys = opt_tys
879
885
  @rest_ty = rest_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)
882
886
  @blk_ty = blk_ty
883
- raise unless blk_ty
884
- end
885
-
886
- attr_reader :lead_tys, :rest_ty, :kw_tys, :blk_ty
887
-
888
- def merge(aargs)
889
- len = [@lead_tys.size, aargs.lead_tys.size].min
890
- lead_tys = @lead_tys[0, len].zip(aargs.lead_tys[0, len]).map do |ty1, ty2|
891
- ty1.union(ty2)
892
- end
893
- rest_ty = @rest_ty || Type.bot
894
- rest_ty = rest_ty.union(aargs.rest_ty) if aargs.rest_ty
895
- (@lead_tys[len..] + aargs.lead_tys[len..]).each do |ty|
896
- rest_ty = rest_ty.union(ty)
897
- end
898
- rest_ty = nil if rest_ty == Type.bot
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
907
- blk_ty = @blk_ty.union(aargs.blk_ty)
908
- ActualArguments.new(lead_tys, rest_ty, kw_tys, blk_ty)
909
- end
910
-
911
- def globalize(caller_env, visited, depth)
912
- lead_tys = @lead_tys.map {|ty| ty.globalize(caller_env, visited, depth) }
913
- rest_ty = @rest_ty.globalize(caller_env, visited, depth) if @rest_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)
918
- end
919
-
920
- def limit_size(limit)
921
- self
922
- end
923
-
924
- def each_formal_arguments(fargs_format)
925
- lead_num = fargs_format[:lead_num] || 0
926
- post_num = fargs_format[:post_num] || 0
927
- rest_acceptable = !!fargs_format[:rest_start]
928
- keyword = fargs_format[:keyword]
929
- kw_rest_acceptable = !!fargs_format[:kwrest]
930
- opt = fargs_format[:opt]
931
- #p fargs_format
932
-
933
- # TODO: expand tuples to normal arguments
934
-
935
- # check number of arguments
936
- if !@rest_ty && lead_num + post_num > @lead_tys.size
937
- # too less
938
- yield "wrong number of arguments (given #{ @lead_tys.size }, expected #{ lead_num + post_num })"
939
- return
940
- end
941
- if !rest_acceptable
942
- # too many
943
- if opt
944
- if lead_num + post_num + opt.size - 1 < @lead_tys.size
945
- yield "wrong number of arguments (given #{ @lead_tys.size }, expected #{ lead_num + post_num }..#{ lead_num + post_num + opt.size - 1})"
946
- return
947
- end
948
- else
949
- if lead_num + post_num < @lead_tys.size
950
- yield "wrong number of arguments (given #{ @lead_tys.size }, expected #{ lead_num + post_num })"
951
- return
952
- end
953
- end
954
- end
955
-
956
- if @rest_ty
957
- lower_bound = [lead_num + post_num - @lead_tys.size, 0].max
958
- upper_bound = lead_num + post_num - @lead_tys.size + (opt ? opt.size - 1 : 0) + (rest_acceptable ? 1 : 0)
959
- rest_elem = @rest_ty.is_a?(Type::Array) ? @rest_ty.elems.squash : Type.any
960
- else
961
- lower_bound = upper_bound = 0
962
- end
963
-
964
- a_kw_tys = @kw_tys.dup
965
- if keyword
966
- kw_tys = []
967
- keyword.each do |kw|
968
- case
969
- when kw.is_a?(Symbol) # required keyword
970
- key = kw
971
- req = true
972
- when kw.size == 2 # optional keyword (default value is a literal)
973
- key, default_ty = *kw
974
- default_ty = Type.guess_literal_type(default_ty)
975
- default_ty = default_ty.type if default_ty.is_a?(Type::Literal)
976
- req = false
977
- else # optional keyword (default value is an expression)
978
- key, = kw
979
- req = false
980
- end
981
-
982
- if a_kw_tys.key?(key)
983
- ty = a_kw_tys.delete(key)
887
+ # TODO: kw_tys
888
+ end
889
+
890
+ attr_reader :lead_tys, :opt_tys, :rest_ty, :blk_ty
891
+
892
+ def merge(bsig)
893
+ if @rest_ty && bsig.rest_ty
894
+ rest_ty = @rest_ty.union(bsig.rest_ty)
895
+ BlockSignature.new(@lead_tys, [], rest_ty, @blk_ty.union(bsig.blk_ty))
896
+ elsif @rest_ty || bsig.rest_ty
897
+ rest_ty = @rest_ty || bsig.rest_ty
898
+ rest_ty = @opt_tys.inject(rest_ty, &:union)
899
+ rest_ty = bsig.opt_tys.inject(rest_ty, &:union)
900
+
901
+ lead_tys = []
902
+ [@lead_tys.size, bsig.lead_tys.size].max.times do |i|
903
+ ty1 = @lead_tys[i]
904
+ ty2 = bsig.lead_tys[i]
905
+ if ty1 && ty2
906
+ lead_tys << ty1.union(ty2)
984
907
  else
985
- ty = a_kw_tys[nil] || Type.bot
986
- end
987
- if ty == Type.bot && req
988
- yield "no argument for required keywords"
989
- return
990
- end
991
- ty = ty.union(default_ty) if default_ty
992
- kw_tys << [req, key, ty]
993
- end
994
- end
995
- if kw_rest_acceptable
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
908
+ rest_ty = rest_ty.union(ty1 || ty2)
1004
909
  end
1005
910
  end
1006
- end
1007
- #if @kw_tys
1008
- # yield "passed a keyword to non-keyword method"
1009
- #end
1010
-
1011
- (lower_bound .. upper_bound).each do |rest_len|
1012
- aargs = @lead_tys + [rest_elem] * rest_len
1013
- lead_tys = aargs.shift(lead_num)
1014
- lead_tys << rest_elem until lead_tys.size == lead_num
1015
- post_tys = aargs.pop(post_num)
1016
- post_tys.unshift(rest_elem) until post_tys.size == post_num
1017
- start_pc = 0
1018
- if opt
1019
- tmp_opt = opt[1..]
1020
- opt_tys = []
1021
- until aargs.empty? || tmp_opt.empty?
1022
- opt_tys << aargs.shift
1023
- start_pc = tmp_opt.shift
1024
- end
1025
- end
1026
- if rest_acceptable
1027
- acc = aargs.inject {|acc, ty| acc.union(ty) }
1028
- acc = acc ? acc.union(rest_elem) : rest_elem if rest_elem
1029
- acc ||= Type.bot
1030
- rest_ty = acc
1031
- aargs.clear
1032
- end
1033
- if !aargs.empty?
1034
- yield "wrong number of arguments (given #{ @lead_tys.size }, expected #{ lead_num + post_num })"
1035
- return
1036
- end
1037
- yield FormalArguments.new(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, @blk_ty), start_pc
1038
- end
1039
- end
1040
-
1041
- def consistent_with_formal_arguments?(fargs, subst)
1042
- aargs = @lead_tys.dup
1043
911
 
1044
- # aargs: lead_tys, rest_ty
1045
- # fargs: lead_tys, opt_tys, rest_ty, post_tys
1046
- if @rest_ty
1047
- lower_bound = [0, fargs.lead_tys.size + fargs.post_tys.size - aargs.size].max
1048
- upper_bound = [0, lower_bound + fargs.opt_tys.size].max
1049
- (lower_bound..upper_bound).each do |n|
1050
- tmp_aargs = ActualArguments.new(@lead_tys + [@rest_ty] * n, nil, @kw_tys, @blk_ty)
1051
- if tmp_aargs.consistent_with_formal_arguments?(fargs, subst)
1052
- return true
1053
- end
1054
- end
1055
- return false
1056
- end
1057
-
1058
- if fargs.rest_ty
1059
- return false if aargs.size < fargs.lead_tys.size + fargs.post_tys.size
1060
- aargs.shift(fargs.lead_tys.size).zip(fargs.lead_tys) do |aarg, farg|
1061
- return false unless aarg.consistent?(farg, subst)
1062
- end
1063
- aargs.pop(fargs.post_tys.size).zip(fargs.post_tys) do |aarg, farg|
1064
- return false unless aarg.consistent?(farg, subst)
1065
- end
1066
- fargs.opt_tys.each do |farg|
1067
- aarg = aargs.shift
1068
- return false unless aarg.consistent?(farg, subst)
1069
- end
1070
- aargs.each do |aarg|
1071
- return false unless aarg.consistent?(fargs.rest_ty, subst)
1072
- end
912
+ BlockSignature.new(lead_tys, [], rest_ty, @blk_ty.union(bsig.blk_ty))
1073
913
  else
1074
- return false if aargs.size < fargs.lead_tys.size + fargs.post_tys.size
1075
- return false if aargs.size > fargs.lead_tys.size + fargs.post_tys.size + fargs.opt_tys.size
1076
- aargs.shift(fargs.lead_tys.size).zip(fargs.lead_tys) do |aarg, farg|
1077
- return false unless aarg.consistent?(farg, subst)
1078
- end
1079
- aargs.pop(fargs.post_tys.size).zip(fargs.post_tys) do |aarg, farg|
1080
- return false unless aarg.consistent?(farg, subst)
914
+ lead_tys = []
915
+ n = [@lead_tys.size, bsig.lead_tys.size].min
916
+ n.times do |i|
917
+ lead_tys << @lead_tys[i].union(bsig.lead_tys[i])
1081
918
  end
1082
- aargs.zip(fargs.opt_tys) do |aarg, farg|
1083
- return false unless aarg.consistent?(farg, subst)
1084
- end
1085
- end
1086
- # XXX: fargs.keyword_tys
1087
-
1088
- case fargs.blk_ty
1089
- when Type::TypedProc
1090
- return false if @blk_ty == Type.nil
1091
- when Type.nil
1092
- return false if @blk_ty != Type.nil
1093
- when Type::Any
1094
- else
1095
- raise "unknown typo of formal block signature"
1096
- end
1097
- true
1098
- end
1099
-
1100
- def screen_name(scratch)
1101
- aargs = @lead_tys.map {|ty| ty.screen_name(scratch) }
1102
- if @rest_ty
1103
- aargs << ("*" + @rest_ty.screen_name(scratch))
1104
- end
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) }"
919
+ opt_tys1 = @lead_tys[n..] + @opt_tys
920
+ opt_tys2 = bsig.lead_tys[n..] + bsig.opt_tys
921
+ opt_tys = []
922
+ [opt_tys1.size, opt_tys2.size].max.times do |i|
923
+ if opt_tys1[i] && opt_tys2[i]
924
+ opt_tys << opt_tys1[i].union(opt_tys2[i])
925
+ else
926
+ opt_tys << (opt_tys1[i] || opt_tys2[i])
927
+ end
1110
928
  end
929
+ BlockSignature.new(lead_tys, opt_tys, nil, @blk_ty.union(bsig.blk_ty))
1111
930
  end
1112
- s = "(#{ aargs.join(", ") })"
1113
- s << " { #{ scratch.proc_screen_name(@blk_ty) } }" if @blk_ty != Type.nil
1114
- s
1115
931
  end
1116
932
  end
1117
933
  end