typeprof 0.4.1 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
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))