typeprof 0.4.1 → 0.5.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7e8caeb25445b59db3abd2709deaf1e5395d5e5584ff8ce667e7b19ec5981da
4
- data.tar.gz: b2bbe7c5c3d0218989c3f2f87a33d4c5c5e61355035dbe57b511a49eb9bc5879
3
+ metadata.gz: b1281ceb7a6a28b6dec33aad740d0fa52429a17ca29d57747717247fdb449c79
4
+ data.tar.gz: 3ad79ab67ba6080e0c1da2b46671012e4db2f886020a11772158449ffd85717b
5
5
  SHA512:
6
- metadata.gz: b33bf9cb6c4ea92ddd0e7721693060bfce646873833603c18386039de90e8a6a51b8a2a6a146d401d51c0d066d4ba42f6c88ae11dc10e21b978f3bd04591a8a9
7
- data.tar.gz: f6ae89fc7879efa8d06445a2c1efc04dcc76defae0a789978c14a786aa0d30ddacab5578fdde2d91bcfe5bd91a5022d6594bc9cf1971dceae8215cbc70b5fd36
6
+ metadata.gz: c0e888c0c1cc871b23592f29d138f7c9c8ca5370fa98699c9b504aa29c79796f58d97653fac98cef2df1d8e7f5c961942ee28d385a95695e4ce7f1ff3c8d24f5
7
+ data.tar.gz: 3ee4de72a8e26aed401b1879575ef82c0b1215fe9ccb87ee2c781a8138becc9ab948aea00e07e8e344ca4f96610ebfefdc540f175253cfe32dca1f721c232e7f
@@ -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.0)
5
- rbs (>= 0.16.0)
4
+ typeprof (0.5.2)
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
@@ -293,20 +296,11 @@ module TypeProf
293
296
  attr_reader :kind, :superclass, :modules, :consts, :methods, :ivars, :cvars, :absolute_path
294
297
  attr_accessor :name, :klass_obj
295
298
 
296
- def include_module(mod, absolute_path)
299
+ def include_module(mod, singleton, absolute_path)
297
300
  # XXX: need to check if mod is already included by the ancestors?
298
- absolute_paths = @modules[false][mod]
301
+ absolute_paths = @modules[singleton][mod]
299
302
  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)
306
- # XXX: need to check if mod is already included by the ancestors?
307
- absolute_paths = @modules[true][mod]
308
- unless absolute_paths
309
- @modules[true][mod] = absolute_paths = Utils::MutableSet.new
303
+ @modules[singleton][mod] = absolute_paths = Utils::MutableSet.new
310
304
  end
311
305
  absolute_paths << absolute_path
312
306
  end
@@ -353,7 +347,7 @@ module TypeProf
353
347
  end
354
348
  end
355
349
 
356
- def include_module(including_mod, included_mod, absolute_path)
350
+ def include_module(including_mod, included_mod, singleton, absolute_path)
357
351
  return if included_mod == Type.any
358
352
 
359
353
  including_mod = @class_defs[including_mod.idx]
@@ -361,7 +355,7 @@ module TypeProf
361
355
  if included_mod.is_a?(Type::Class)
362
356
  included_mod = @class_defs[included_mod.idx]
363
357
  if included_mod && included_mod.kind == :module
364
- including_mod.include_module(included_mod, absolute_path)
358
+ including_mod.include_module(included_mod, singleton, absolute_path)
365
359
  else
366
360
  warn "including something that is not a module"
367
361
  end
@@ -369,20 +363,6 @@ module TypeProf
369
363
  end
370
364
  end
371
365
 
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
366
  def cbase_path(cbase)
387
367
  cbase && cbase.idx != 1 ? @class_defs[cbase.idx].name : []
388
368
  end
@@ -572,9 +552,7 @@ module TypeProf
572
552
 
573
553
  ret_ty = @return_values[callee_ctx] ||= Type.bot
574
554
  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
555
+ ctn[ret_ty, caller_ep, @return_envs[caller_ep]]
578
556
  end
579
557
  end
580
558
 
@@ -632,7 +610,7 @@ module TypeProf
632
610
  entry = @tbl[site] ||= Entry.new(!ep, {}, Type.bot, Utils::MutableSet.new)
633
611
  if ep
634
612
  if entry.rbs_declared
635
- if !entry.type.consistent?(ty, {})
613
+ unless Type.match?(ty, entry.type)
636
614
  scratch.warn(ep, "inconsistent assignment to RBS-declared global variable")
637
615
  return
638
616
  end
@@ -651,6 +629,7 @@ module TypeProf
651
629
  end
652
630
 
653
631
  def get_ivar(recv)
632
+ recv = recv.base_type while recv.respond_to?(:base_type)
654
633
  case recv
655
634
  when Type::Class
656
635
  [@class_defs[recv.idx], true]
@@ -884,26 +863,41 @@ module TypeProf
884
863
  def pend_method_execution(iseq, meth, recv, mid, cref)
885
864
  ctx = Context.new(iseq, cref, mid)
886
865
  ep = ExecutionPoint.new(ctx, 0, nil)
887
- locals = [Type.any] * iseq.locals.size
888
-
889
- keyword = iseq.fargs_format[:keyword]
866
+ locals = [Type.nil] * iseq.locals.size
867
+
868
+ fargs_format = iseq.fargs_format
869
+ lead_num = fargs_format[:lead_num] || 0
870
+ post_num = fargs_format[:post_num] || 0
871
+ post_index = fargs_format[:post_start]
872
+ rest_index = fargs_format[:rest_start]
873
+ keyword = fargs_format[:keyword]
874
+ kw_index = fargs_format[:kwbits] - keyword.size if keyword
875
+ kwrest_index = fargs_format[:kwrest]
876
+ block_index = fargs_format[:block_start]
877
+ opt = fargs_format[:opt] || [0]
878
+
879
+ (lead_num + opt.size - 1).times {|i| locals[i] = Type.any }
880
+ post_num.times {|i| locals[i + post_index] = Type.any } if post_index
881
+ locals[rest_index] = Type.any if rest_index
890
882
  if keyword
891
- kw_start = iseq.fargs_format[:kwbits]
892
- kw_start -= iseq.fargs_format[:keyword].size if kw_start
893
883
  keyword.each_with_index do |kw, i|
894
884
  case
895
885
  when kw.is_a?(Symbol) # required keyword
886
+ locals[kw_index + i] = Type.any
896
887
  when kw.size == 2 # optional keyword (default value is a literal)
897
888
  _key, default_ty = *kw
898
889
  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)
890
+ default_ty = default_ty.base_type if default_ty.is_a?(Type::Literal)
891
+ locals[kw_index + i] = default_ty.union(Type.any)
901
892
  else # optional keyword (default value is an expression)
893
+ locals[kw_index + i] = Type.any
902
894
  end
903
895
  end
904
896
  end
897
+ locals[kwrest_index] = Type.any if kwrest_index
898
+ locals[block_index] = Type.nil if block_index
905
899
 
906
- env = Env.new(StaticEnv.new(recv, Type.any, false), locals, [], Utils::HashWrapper.new({}))
900
+ env = Env.new(StaticEnv.new(recv, Type.nil, false), locals, [], Utils::HashWrapper.new({}))
907
901
 
908
902
  @pending_execution[iseq] ||= [:method, [meth, ep, env]]
909
903
  end
@@ -986,7 +980,7 @@ module TypeProf
986
980
  when kw.size == 2 # optional keyword (default value is a literal)
987
981
  key, default_ty = *kw
988
982
  default_ty = Type.guess_literal_type(default_ty)
989
- default_ty = default_ty.type if default_ty.is_a?(Type::Literal)
983
+ default_ty = default_ty.base_type if default_ty.is_a?(Type::Literal)
990
984
  req = false
991
985
  else # optional keyword (default value is an expression)
992
986
  key, = kw
@@ -1029,7 +1023,17 @@ module TypeProf
1029
1023
  ty = Type::Literal.new(str, Type::Instance.new(Type::Builtin[:str]))
1030
1024
  env = env.push(ty)
1031
1025
  when :putself
1032
- env, ty = localize_type(env.static_env.recv_ty, env, ep)
1026
+ ty = env.static_env.recv_ty
1027
+ if ty.is_a?(Type::Instance)
1028
+ klass = ty.klass
1029
+ if klass.type_params.size >= 1
1030
+ ty = Type::ContainerType.create_empty_instance(klass)
1031
+ env, ty = localize_type(ty, env, ep, AllocationSite.new(ep))
1032
+ else
1033
+ ty = Type::Instance.new(klass)
1034
+ end
1035
+ env, ty = localize_type(ty, env, ep)
1036
+ end
1033
1037
  env = env.push(ty)
1034
1038
  when :newarray, :newarraykwsplat
1035
1039
  len, = operands
@@ -1700,15 +1704,27 @@ module TypeProf
1700
1704
  end
1701
1705
 
1702
1706
  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])
1707
+ kind, = operands
1708
+ case kind
1709
+ when 5 then klass = :str # T_STRING
1710
+ when 7 then klass = :ary # T_ARRAY
1711
+ when 8 then klass = :hash # T_HASH
1710
1712
  else
1711
- ty = Type::Instance.new(Type::Builtin[:false])
1713
+ raise NotImplementedError
1714
+ end
1715
+ env, (val,) = env.pop(1)
1716
+ ty = Type.bot
1717
+ val.each_child do |val|
1718
+ #globalize_type(val, env, ep).each_child_global do |val|
1719
+ val = val.base_type while val.respond_to?(:base_type)
1720
+ case val
1721
+ when Type::Instance.new(Type::Builtin[klass])
1722
+ ty = ty.union(Type::Instance.new(Type::Builtin[:true]))
1723
+ when Type.any
1724
+ ty = Type.bool
1725
+ else
1726
+ ty = ty.union(Type::Instance.new(Type::Builtin[:false]))
1727
+ end
1712
1728
  end
1713
1729
  env = env.push(ty)
1714
1730
  else
@@ -1857,7 +1873,7 @@ module TypeProf
1857
1873
  kw_tys = ty.elems.to_keywords
1858
1874
  when Type::Union
1859
1875
  hash_elems = nil
1860
- ty.elems.each do |(container_kind, base_type), elems|
1876
+ ty.elems&.each do |(container_kind, base_type), elems|
1861
1877
  if container_kind == Type::Hash
1862
1878
  hash_elems = hash_elems ? hash_elems.union(elems) : elems
1863
1879
  end
@@ -1946,7 +1962,7 @@ module TypeProf
1946
1962
  end
1947
1963
  end
1948
1964
 
1949
- @block_to_ctx[blk.block_body].each do |blk_ctx|
1965
+ @block_to_ctx[blk.block_body]&.each do |blk_ctx|
1950
1966
  ret_ty = ret_ty.union(@return_values[blk_ctx]) if @return_values[blk_ctx]
1951
1967
  end
1952
1968
  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
@@ -85,10 +85,13 @@ module TypeProf
85
85
  end
86
86
 
87
87
  def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, &ctn)
88
- subst = { Type::Var.new(:self) => caller_env.static_env.recv_ty } # XXX: support other type variables
89
- unless aargs.consistent_with_method_signature?(@msig, subst)
88
+ aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
89
+ subst = aargs.consistent_with_method_signature?(@msig)
90
+ unless subst
90
91
  scratch.warn(caller_ep, "The arguments is not compatibile to RBS block")
91
92
  end
93
+ # check?
94
+ #subst = { Type::Var.new(:self) => caller_env.static_env.recv_ty }
92
95
  # XXX: Update type vars
93
96
  ctn[@ret_ty, caller_ep, caller_env]
94
97
  end
@@ -54,6 +54,10 @@ module TypeProf
54
54
  ctn[ret_ty, ep, env]
55
55
  end
56
56
 
57
+ def vmcore_raise(recv, mid, aargs, ep, env, scratch, &ctn)
58
+ # no-op
59
+ end
60
+
57
61
  def lambda(recv, mid, aargs, ep, env, scratch, &ctn)
58
62
  ctn[aargs.blk_ty, ep, env]
59
63
  end
@@ -63,10 +67,11 @@ module TypeProf
63
67
  end
64
68
 
65
69
  def object_s_new(recv, mid, aargs, ep, env, scratch, &ctn)
66
- ty = Type::Instance.new(recv)
67
70
  if recv.type_params.size >= 1
68
- ty = Type::Cell.new(Type::Cell::Elements.new([Type.bot] * recv.type_params.size), ty)
71
+ ty = Type::ContainerType.create_empty_instance(recv)
69
72
  env, ty = scratch.localize_type(ty, env, ep, AllocationSite.new(ep).add_id(:object_s_new))
73
+ else
74
+ ty = Type::Instance.new(recv)
70
75
  end
71
76
  meths = scratch.get_method(recv, false, :initialize)
72
77
  meths.flat_map do |meth|
@@ -149,7 +154,11 @@ module TypeProf
149
154
 
150
155
  def module_include(recv, mid, aargs, ep, env, scratch, &ctn)
151
156
  arg = aargs.lead_tys[0]
152
- scratch.include_module(recv, arg, ep.ctx.iseq.absolute_path)
157
+ arg.each_child do |arg|
158
+ if arg.is_a?(Type::Class)
159
+ scratch.include_module(recv, arg, false, ep.ctx.iseq.absolute_path)
160
+ end
161
+ end
153
162
  ctn[recv, ep, env]
154
163
  end
155
164
 
@@ -157,7 +166,7 @@ module TypeProf
157
166
  arg = aargs.lead_tys[0]
158
167
  arg.each_child do |arg|
159
168
  if arg.is_a?(Type::Class)
160
- scratch.extend_module(recv, arg, ep.ctx.iseq.absolute_path)
169
+ scratch.include_module(recv, arg, true, ep.ctx.iseq.absolute_path)
161
170
  end
162
171
  end
163
172
  ctn[recv, ep, env]
@@ -520,6 +529,7 @@ module TypeProf
520
529
  scratch.set_custom_method(klass_vmcore, :"core#set_method_alias", Builtin.method(:vmcore_set_method_alias))
521
530
  scratch.set_custom_method(klass_vmcore, :"core#undef_method", Builtin.method(:vmcore_undef_method))
522
531
  scratch.set_custom_method(klass_vmcore, :"core#hash_merge_kwd", Builtin.method(:vmcore_hash_merge_kwd))
532
+ scratch.set_custom_method(klass_vmcore, :"core#raise", Builtin.method(:vmcore_raise))
523
533
  scratch.set_custom_method(klass_vmcore, :lambda, Builtin.method(:lambda))
524
534
  scratch.set_singleton_custom_method(klass_obj, :"new", Builtin.method(:object_s_new))
525
535
  scratch.set_singleton_custom_method(klass_obj, :"attr_accessor", Builtin.method(:module_attr_accessor))