typeprof 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +9 -20
- data/LICENSE +21 -0
- data/doc/doc.ja.md +2 -1
- data/doc/doc.md +3 -2
- data/exe/typeprof +2 -1
- data/lib/typeprof.rb +1 -0
- data/lib/typeprof/analyzer.rb +163 -84
- data/lib/typeprof/builtin.rb +20 -19
- data/lib/typeprof/cli.rb +51 -98
- data/lib/typeprof/config.rb +114 -0
- data/lib/typeprof/container-type.rb +125 -21
- data/lib/typeprof/export.rb +20 -8
- data/lib/typeprof/import.rb +43 -20
- data/lib/typeprof/iseq.rb +17 -1
- data/lib/typeprof/method.rb +33 -9
- data/lib/typeprof/type.rb +52 -24
- data/lib/typeprof/utils.rb +4 -18
- data/lib/typeprof/version.rb +3 -0
- data/smoke/arguments2.rb +55 -0
- data/smoke/hash4.rb +1 -1
- data/smoke/keyword3.rb +1 -2
- data/smoke/keyword4.rb +1 -1
- data/smoke/module4.rb +2 -0
- data/smoke/optional1.rb +1 -1
- data/smoke/optional2.rb +1 -1
- data/smoke/rbs-extend.rb +9 -0
- data/smoke/rbs-extend.rbs +7 -0
- data/smoke/rbs-interface.rb +24 -0
- data/smoke/rbs-interface.rbs +12 -0
- data/smoke/rbs-tyvar.rb +18 -0
- data/smoke/rbs-tyvar.rbs +5 -0
- data/smoke/rbs-tyvar2.rb +20 -0
- data/smoke/rbs-tyvar2.rbs +9 -0
- data/smoke/rest1.rb +1 -1
- data/smoke/rest3.rb +1 -1
- data/smoke/rest6.rb +1 -1
- data/smoke/retry1.rb +1 -1
- data/smoke/step.rb +1 -1
- data/smoke/user-demo.rb +15 -0
- data/smoke/wrong-extend.rb +1 -0
- data/typeprof.gemspec +4 -2
- metadata +17 -5
- data/run.sh +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a0f0b09ed34d40d00fc280008ae562863d6cb3e19bd0a421e1fc5ac5023a5ea
|
4
|
+
data.tar.gz: dd7ee377c5dee6d2ad7bbd274844a5136c59f7fab5f7491cde11fcac628d44c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66e931b5f52fb1436707623ad1fba698bed0cf6e922971fbd0b5c99e28e4c14f5737e5f92406a457c5b96205ef8ad58f31aa739465f3aa57ca8149695c1bda42
|
7
|
+
data.tar.gz: 679c4b14a7bad664ba17f2aa27aa999a27584d7b9fdbe40bbb82fc4ea836ef867621a34077de5931c6c26fc9e9c9a2908bb4901914fa587f1b84cdd75dcde0ea
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -7,7 +7,7 @@ group :development do
|
|
7
7
|
gem "rake"
|
8
8
|
gem "stackprof"
|
9
9
|
gem "test-unit"
|
10
|
-
gem "simplecov"
|
11
|
-
gem "simplecov-html"
|
10
|
+
gem "simplecov"
|
11
|
+
gem "simplecov-html"
|
12
12
|
gem "coverage-helpers"
|
13
13
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,23 +1,8 @@
|
|
1
|
-
GIT
|
2
|
-
remote: https://github.com/simplecov-ruby/simplecov-html.git
|
3
|
-
revision: 6567856c6940e285bbb70cce98edca60c7dfefdd
|
4
|
-
ref: 6567856c6940e285bbb70cce98edca60c7dfefdd
|
5
|
-
specs:
|
6
|
-
simplecov-html (0.12.2)
|
7
|
-
|
8
|
-
GIT
|
9
|
-
remote: https://github.com/simplecov-ruby/simplecov.git
|
10
|
-
revision: 80700ec9f9b5ae426c22d06f62620f7e7b71ff42
|
11
|
-
specs:
|
12
|
-
simplecov (0.18.5)
|
13
|
-
docile (~> 1.1)
|
14
|
-
simplecov-html (~> 0.11)
|
15
|
-
|
16
1
|
PATH
|
17
2
|
remote: .
|
18
3
|
specs:
|
19
|
-
typeprof (0.
|
20
|
-
rbs (>= 0.
|
4
|
+
typeprof (0.3.0)
|
5
|
+
rbs (>= 0.13.1)
|
21
6
|
|
22
7
|
GEM
|
23
8
|
remote: https://rubygems.org/
|
@@ -27,7 +12,11 @@ GEM
|
|
27
12
|
power_assert (1.2.0)
|
28
13
|
rake (13.0.1)
|
29
14
|
rbs (0.14.0)
|
30
|
-
|
15
|
+
simplecov (0.19.1)
|
16
|
+
docile (~> 1.1)
|
17
|
+
simplecov-html (~> 0.11)
|
18
|
+
simplecov-html (0.12.3)
|
19
|
+
stackprof (0.2.16)
|
31
20
|
test-unit (3.3.6)
|
32
21
|
power_assert
|
33
22
|
|
@@ -37,8 +26,8 @@ PLATFORMS
|
|
37
26
|
DEPENDENCIES
|
38
27
|
coverage-helpers
|
39
28
|
rake
|
40
|
-
simplecov
|
41
|
-
simplecov-html
|
29
|
+
simplecov
|
30
|
+
simplecov-html
|
42
31
|
stackprof
|
43
32
|
test-unit
|
44
33
|
typeprof!
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Yusuke Endoh
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/doc/doc.ja.md
CHANGED
@@ -24,7 +24,8 @@ $ typeprof sig/app.rbs app.rb -o sig/app.gen.rbs
|
|
24
24
|
|
25
25
|
* `-o OUTFILE`: 標準出力ではなく、指定ファイル名に出力する
|
26
26
|
* `-q`: 解析の進捗を表示しない
|
27
|
-
* `-v`:
|
27
|
+
* `-v`: `-fshow-errors`の別名
|
28
|
+
* `-d`: 解析の詳細ログを表示する(現状ではデバッグ用出力に近い)
|
28
29
|
* `-I DIR`: `require`のファイル探索ディレクトリを追加する
|
29
30
|
* `-r GEMNAME`: `GEMNAME`に対応するRBSをロードする
|
30
31
|
* `--exclude-dir DIR`: `DIR`以下のファイルの解析結果を出力から省略する。後に指定されているほうが優先される(`--include-dir foo --exclude-dir foo/bar`の場合う、foo/bar/baz.rbの結果は出力されず、foo/baz.rbの結果は出力される)。
|
data/doc/doc.md
CHANGED
@@ -24,7 +24,8 @@ Here is a list of currently avaiable options:
|
|
24
24
|
|
25
25
|
* `-o OUTFILE`: Write the analyze result to OUTFILE instead of standard output
|
26
26
|
* `-q`: Hide the progress indicator
|
27
|
-
* `-v`:
|
27
|
+
* `-v`: Alias to `-fshow-errors`
|
28
|
+
* `-d`: Show the analysis log (Currently, the log is just for debugging and may become very huge)
|
28
29
|
* `-I DIR`: Add `DIR` to the file search path of `require`
|
29
30
|
* `-r GEMNAME`: Load the RBS files of `GEMNAME`
|
30
31
|
* `--exclude-dir DIR`: Omit the result of files that are placed under the directory `DIR`. If there are some directory specifications, the latter one is stronger. (Assuming that `--include-dir foo --exclude-dir foo/bar` is specified, the analysis result of foo/bar/baz.rb is omitted, but foo/baz.rb is shown.)
|
@@ -234,7 +235,7 @@ If a method returns different abstract values, it can lead to retrospective exec
|
|
234
235
|
Even after TypeProf traced all programs as possible, there may be methods or blocks that aren't executed.
|
235
236
|
For example, a method is not executed if it is called from nowhere; this is typical for library method that has no test.
|
236
237
|
(Basically, when you use TypeProf, it is recommended to invoke all methods with supposed argument types.)
|
237
|
-
TypeProf forcibly calls these unreachable methods and blocks with `untyped` as
|
238
|
+
TypeProf forcibly calls these unreachable methods and blocks with `untyped` as arguments.
|
238
239
|
|
239
240
|
```
|
240
241
|
def foo(n)
|
data/exe/typeprof
CHANGED
data/lib/typeprof.rb
CHANGED
data/lib/typeprof/analyzer.rb
CHANGED
@@ -128,7 +128,13 @@ module TypeProf
|
|
128
128
|
other.type_params.internal_hash.each do |id, elems|
|
129
129
|
elems2 = type_params[id]
|
130
130
|
if elems2
|
131
|
-
|
131
|
+
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
|
+
end
|
132
138
|
else
|
133
139
|
type_params[id] = elems
|
134
140
|
end
|
@@ -176,6 +182,13 @@ module TypeProf
|
|
176
182
|
Env.new(@static_env, Utils.array_update(@locals, idx, ty), @stack, @type_params)
|
177
183
|
end
|
178
184
|
|
185
|
+
def deploy_cell_type(alloc_site, elems, base_ty)
|
186
|
+
local_ty = Type::LocalCell.new(alloc_site, base_ty)
|
187
|
+
type_params = Utils::HashWrapper.new(@type_params.internal_hash.merge({ alloc_site => elems }))
|
188
|
+
nenv = Env.new(@static_env, @locals, @stack, type_params)
|
189
|
+
return nenv, local_ty
|
190
|
+
end
|
191
|
+
|
179
192
|
def deploy_array_type(alloc_site, elems, base_ty)
|
180
193
|
local_ty = Type::LocalArray.new(alloc_site, base_ty)
|
181
194
|
type_params = Utils::HashWrapper.new(@type_params.internal_hash.merge({ alloc_site => elems }))
|
@@ -245,6 +258,8 @@ module TypeProf
|
|
245
258
|
@loaded_features = {}
|
246
259
|
|
247
260
|
@rbs_reader = RBSReader.new
|
261
|
+
|
262
|
+
@terminated = false
|
248
263
|
end
|
249
264
|
|
250
265
|
attr_reader :return_envs, :loaded_features, :rbs_reader
|
@@ -259,7 +274,7 @@ module TypeProf
|
|
259
274
|
env2 = @ep2env[ep]
|
260
275
|
if env2
|
261
276
|
nenv = env2.merge(env)
|
262
|
-
if
|
277
|
+
if nenv != env2 && !@worklist.member?(ep)
|
263
278
|
@worklist.insert(ep.key, ep)
|
264
279
|
end
|
265
280
|
@ep2env[ep] = nenv
|
@@ -550,26 +565,29 @@ module TypeProf
|
|
550
565
|
@iseq_method_to_ctxs[iseq_mdef] << ctx
|
551
566
|
end
|
552
567
|
|
553
|
-
def add_callsite!(callee_ctx,
|
568
|
+
def add_callsite!(callee_ctx, caller_ep, caller_env, &ctn)
|
554
569
|
@executed_iseqs << callee_ctx.iseq if callee_ctx.is_a?(Context)
|
555
570
|
|
556
571
|
@callsites[callee_ctx] ||= {}
|
557
572
|
@callsites[callee_ctx][caller_ep] = ctn
|
558
573
|
merge_return_env(caller_ep) {|env| env ? env.merge(caller_env) : caller_env }
|
559
574
|
|
560
|
-
if @sig_fargs[callee_ctx]
|
561
|
-
@sig_fargs[callee_ctx] = @sig_fargs[callee_ctx].merge(fargs)
|
562
|
-
else
|
563
|
-
@sig_fargs[callee_ctx] = fargs
|
564
|
-
end
|
565
575
|
ret_ty = @sig_ret[callee_ctx] ||= Type.bot
|
566
|
-
|
576
|
+
if ret_ty != Type.bot
|
567
577
|
@callsites[callee_ctx].each do |caller_ep, ctn|
|
568
578
|
ctn[ret_ty, caller_ep, @return_envs[caller_ep]]
|
569
579
|
end
|
570
580
|
end
|
571
581
|
end
|
572
582
|
|
583
|
+
def add_signature!(callee_ctx, fargs)
|
584
|
+
if @sig_fargs[callee_ctx]
|
585
|
+
@sig_fargs[callee_ctx] = @sig_fargs[callee_ctx].merge(fargs)
|
586
|
+
else
|
587
|
+
@sig_fargs[callee_ctx] = fargs
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
573
591
|
def merge_return_env(caller_ep)
|
574
592
|
@return_envs[caller_ep] = yield @return_envs[caller_ep]
|
575
593
|
end
|
@@ -769,27 +787,35 @@ module TypeProf
|
|
769
787
|
end
|
770
788
|
|
771
789
|
def type_profile
|
772
|
-
|
773
|
-
|
790
|
+
start_time = tick = Time.now
|
791
|
+
iter_counter = 0
|
774
792
|
stat_eps = Utils::MutableSet.new
|
793
|
+
|
775
794
|
while true
|
776
795
|
until @worklist.empty?
|
777
|
-
|
796
|
+
ep = @worklist.deletemin
|
778
797
|
|
779
|
-
|
798
|
+
iter_counter += 1
|
780
799
|
if Config.verbose >= 1
|
781
|
-
|
782
|
-
if
|
783
|
-
|
784
|
-
$stderr << "\rType Profiling... (%d steps @ %s)\e[K" % [
|
800
|
+
tick2 = Time.now
|
801
|
+
if tick2 - tick >= 1
|
802
|
+
tick = tick2
|
803
|
+
$stderr << "\rType Profiling... (%d steps @ %s)\e[K" % [iter_counter, ep.source_location]
|
785
804
|
$stderr.flush
|
786
805
|
end
|
787
806
|
end
|
788
807
|
|
789
|
-
|
790
|
-
|
808
|
+
if (Config.max_sec && Time.now - start_time >= Config.max_sec) || (Config.max_iter && Config.max_iter <= iter_counter)
|
809
|
+
@terminated = true
|
810
|
+
break
|
811
|
+
end
|
812
|
+
|
813
|
+
stat_eps << ep
|
814
|
+
step(ep)
|
791
815
|
end
|
792
816
|
|
817
|
+
break if @terminated
|
818
|
+
|
793
819
|
# XXX: it would be good to provide no-dummy-execution mode.
|
794
820
|
# It should work as a bit smarter "rbs prototype rb";
|
795
821
|
# show all method definitions as "untyped" arguments and return values
|
@@ -809,37 +835,6 @@ module TypeProf
|
|
809
835
|
merge_env(ep, env)
|
810
836
|
add_iseq_method_call!(meth, ep.ctx)
|
811
837
|
|
812
|
-
fargs_format = iseq.fargs_format
|
813
|
-
lead_tys = [Type.any] * (fargs_format[:lead_num] || 0)
|
814
|
-
opt_tys = fargs_format[:opt] ? [] : nil
|
815
|
-
post_tys = [Type.any] * (fargs_format[:post_num] || 0)
|
816
|
-
if fargs_format[:kwbits]
|
817
|
-
kw_tys = []
|
818
|
-
fargs_format[:keyword].each do |kw|
|
819
|
-
case
|
820
|
-
when kw.is_a?(Symbol) # required keyword
|
821
|
-
key = kw
|
822
|
-
req = true
|
823
|
-
ty = Type.any
|
824
|
-
when kw.size == 2 # optional keyword (default value is a literal)
|
825
|
-
key, ty = *kw
|
826
|
-
ty = Type.guess_literal_type(ty)
|
827
|
-
ty = ty.type if ty.is_a?(Type::Literal)
|
828
|
-
else # optional keyword
|
829
|
-
key, = kw
|
830
|
-
req = false
|
831
|
-
ty = Type.any
|
832
|
-
end
|
833
|
-
kw_tys << [req, key, ty]
|
834
|
-
end
|
835
|
-
else
|
836
|
-
kw_tys = nil
|
837
|
-
end
|
838
|
-
fargs = FormalArguments.new(lead_tys, opt_tys, nil, post_tys, kw_tys, nil, nil)
|
839
|
-
add_callsite!(ep.ctx, fargs, nil, nil) do |_ret_ty, _ep, _env|
|
840
|
-
# ignore
|
841
|
-
end
|
842
|
-
|
843
838
|
when :block
|
844
839
|
epenvs = dummy_continuation
|
845
840
|
epenvs.each do |ep, env|
|
@@ -853,6 +848,8 @@ module TypeProf
|
|
853
848
|
end
|
854
849
|
|
855
850
|
def report(stat_eps, output)
|
851
|
+
Reporters.show_message(@terminated, output)
|
852
|
+
|
856
853
|
Reporters.show_error(@errors, @backward_edges, output)
|
857
854
|
|
858
855
|
Reporters.show_reveal_types(self, @reveal_types, output)
|
@@ -895,6 +892,24 @@ module TypeProf
|
|
895
892
|
ctx = Context.new(iseq, cref, mid)
|
896
893
|
ep = ExecutionPoint.new(ctx, 0, nil)
|
897
894
|
locals = [Type.any] * iseq.locals.size
|
895
|
+
|
896
|
+
keyword = iseq.fargs_format[:keyword]
|
897
|
+
if keyword
|
898
|
+
kw_start = iseq.fargs_format[:kwbits]
|
899
|
+
kw_start -= iseq.fargs_format[:keyword].size if kw_start
|
900
|
+
keyword.each_with_index do |kw, i|
|
901
|
+
case
|
902
|
+
when kw.is_a?(Symbol) # required keyword
|
903
|
+
when kw.size == 2 # optional keyword (default value is a literal)
|
904
|
+
_key, default_ty = *kw
|
905
|
+
default_ty = Type.guess_literal_type(default_ty)
|
906
|
+
default_ty = default_ty.type if default_ty.is_a?(Type::Literal)
|
907
|
+
locals[kw_start + i] = default_ty.union(Type.any)
|
908
|
+
else # optional keyword (default value is an expression)
|
909
|
+
end
|
910
|
+
end
|
911
|
+
end
|
912
|
+
|
898
913
|
env = Env.new(StaticEnv.new(recv, Type.any, false), locals, [], Utils::HashWrapper.new({}))
|
899
914
|
|
900
915
|
@pending_execution[iseq] ||= [:method, [meth, ep, env]]
|
@@ -939,6 +954,61 @@ module TypeProf
|
|
939
954
|
end
|
940
955
|
|
941
956
|
case insn
|
957
|
+
when :_method_body
|
958
|
+
# XXX: reconstruct and record the method signature
|
959
|
+
iseq = ep.ctx.iseq
|
960
|
+
lead_num = iseq.fargs_format[:lead_num] || 0
|
961
|
+
opt = iseq.fargs_format[:opt] || [0]
|
962
|
+
rest_start = iseq.fargs_format[:rest_start]
|
963
|
+
post_start = iseq.fargs_format[:post_start]
|
964
|
+
post_num = iseq.fargs_format[:post_num] || 0
|
965
|
+
kw_start = iseq.fargs_format[:kwbits]
|
966
|
+
keyword = iseq.fargs_format[:keyword]
|
967
|
+
kw_start -= keyword.size if kw_start
|
968
|
+
kw_rest = iseq.fargs_format[:kwrest]
|
969
|
+
block_start = iseq.fargs_format[:block_start]
|
970
|
+
|
971
|
+
lead_tys = env.locals[0, lead_num].map {|ty| globalize_type(ty, env, ep) }
|
972
|
+
opt_tys = opt.size > 1 ? env.locals[lead_num, opt.size - 1].map {|ty| globalize_type(ty, env, ep) } : nil
|
973
|
+
if rest_start # XXX:squash
|
974
|
+
ty = globalize_type(env.locals[lead_num + opt.size - 1], env, ep)
|
975
|
+
rest_ty = Type.bot
|
976
|
+
ty.each_child_global do |ty|
|
977
|
+
if ty.is_a?(Type::Array)
|
978
|
+
rest_ty = rest_ty.union(ty.elems.squash)
|
979
|
+
else
|
980
|
+
# XXX: to_ary?
|
981
|
+
rest_ty = rest_ty.union(ty)
|
982
|
+
end
|
983
|
+
end
|
984
|
+
end
|
985
|
+
post_tys = (post_start ? env.locals[post_start, post_num] : []).map {|ty| globalize_type(ty, env, ep) }
|
986
|
+
if keyword
|
987
|
+
kw_tys = []
|
988
|
+
keyword.each_with_index do |kw, i|
|
989
|
+
case
|
990
|
+
when kw.is_a?(Symbol) # required keyword
|
991
|
+
key = kw
|
992
|
+
req = true
|
993
|
+
when kw.size == 2 # optional keyword (default value is a literal)
|
994
|
+
key, default_ty = *kw
|
995
|
+
default_ty = Type.guess_literal_type(default_ty)
|
996
|
+
default_ty = default_ty.type if default_ty.is_a?(Type::Literal)
|
997
|
+
req = false
|
998
|
+
else # optional keyword (default value is an expression)
|
999
|
+
key, = kw
|
1000
|
+
req = false
|
1001
|
+
end
|
1002
|
+
ty = env.locals[kw_start + i]
|
1003
|
+
ty = ty.union(default_ty) if default_ty
|
1004
|
+
ty = globalize_type(ty, env, ep)
|
1005
|
+
kw_tys << [req, key, ty]
|
1006
|
+
end
|
1007
|
+
end
|
1008
|
+
kw_rest_ty = globalize_type(env.locals[kw_rest], env, ep) if kw_rest
|
1009
|
+
blk_ty = block_start ? globalize_type(env.locals[block_start], env, ep) : Type.nil
|
1010
|
+
fargs = FormalArguments.new(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
|
1011
|
+
add_signature!(ep.ctx, fargs)
|
942
1012
|
when :putspecialobject
|
943
1013
|
kind, = operands
|
944
1014
|
ty = case kind
|
@@ -1071,7 +1141,7 @@ module TypeProf
|
|
1071
1141
|
elsif superclass == Type.any
|
1072
1142
|
warn(ep, "superclass is any; Object is used instead")
|
1073
1143
|
superclass = Type::Builtin[:obj]
|
1074
|
-
elsif superclass
|
1144
|
+
elsif superclass == Type.nil
|
1075
1145
|
superclass = Type::Builtin[:obj]
|
1076
1146
|
elsif superclass.is_a?(Type::Instance)
|
1077
1147
|
warn(ep, "superclass is an instance; Object is used instead")
|
@@ -1111,7 +1181,7 @@ module TypeProf
|
|
1111
1181
|
locals = [Type.nil] * iseq.locals.size
|
1112
1182
|
nenv = Env.new(StaticEnv.new(recv, blk, false), locals, [], Utils::HashWrapper.new({}))
|
1113
1183
|
merge_env(nep, nenv)
|
1114
|
-
add_callsite!(nep.ctx,
|
1184
|
+
add_callsite!(nep.ctx, ep, env) do |ret_ty, ep, env|
|
1115
1185
|
nenv, ret_ty = localize_type(ret_ty, env, ep)
|
1116
1186
|
nenv = nenv.push(ret_ty)
|
1117
1187
|
merge_env(ep.next, nenv)
|
@@ -1164,15 +1234,15 @@ module TypeProf
|
|
1164
1234
|
env, aargs = env.pop(orig_argc)
|
1165
1235
|
blk = env.static_env.blk_ty
|
1166
1236
|
case
|
1167
|
-
when blk
|
1237
|
+
when blk == Type.nil
|
1168
1238
|
env = env.push(Type.any)
|
1169
|
-
when blk
|
1239
|
+
when blk == Type.any
|
1170
1240
|
#warn(ep, "block is any")
|
1171
1241
|
env = env.push(Type.any)
|
1172
1242
|
else # Proc
|
1173
1243
|
blk_nil = Type.nil
|
1174
1244
|
#
|
1175
|
-
aargs = ActualArguments.new(aargs, nil,
|
1245
|
+
aargs = ActualArguments.new(aargs, nil, {}, blk_nil)
|
1176
1246
|
do_invoke_block(true, env.static_env.blk_ty, aargs, ep, env) do |ret_ty, ep, env|
|
1177
1247
|
nenv, ret_ty, = localize_type(ret_ty, env, ep)
|
1178
1248
|
nenv = nenv.push(ret_ty)
|
@@ -1266,7 +1336,7 @@ module TypeProf
|
|
1266
1336
|
raise if iseq.locals != []
|
1267
1337
|
nenv = Env.new(env.static_env, [], [], nil)
|
1268
1338
|
merge_env(nep, nenv)
|
1269
|
-
add_callsite!(nep.ctx,
|
1339
|
+
add_callsite!(nep.ctx, ep, env) do |ret_ty, ep, env|
|
1270
1340
|
nenv, ret_ty = localize_type(ret_ty, env, ep)
|
1271
1341
|
nenv = nenv.push(ret_ty)
|
1272
1342
|
merge_env(ep.next, nenv)
|
@@ -1282,7 +1352,7 @@ module TypeProf
|
|
1282
1352
|
|
1283
1353
|
# TODO: it works for only simple cases: `x = nil; x || 1`
|
1284
1354
|
# It would be good to merge "dup; branchif" to make it context-sensitive-like
|
1285
|
-
falsy = ty
|
1355
|
+
falsy = ty == Type.nil
|
1286
1356
|
|
1287
1357
|
merge_env(ep_then, env)
|
1288
1358
|
merge_env(ep_else, env) unless branchtype == :if && falsy
|
@@ -1428,11 +1498,11 @@ module TypeProf
|
|
1428
1498
|
when :getconstant
|
1429
1499
|
name, = operands
|
1430
1500
|
env, (cbase, _allow_nil,) = env.pop(2)
|
1431
|
-
if cbase
|
1501
|
+
if cbase == Type.nil
|
1432
1502
|
ty = search_constant(ep.ctx.cref, name)
|
1433
1503
|
env, ty = localize_type(ty, env, ep)
|
1434
1504
|
env = env.push(ty)
|
1435
|
-
elsif cbase
|
1505
|
+
elsif cbase == Type.any
|
1436
1506
|
env = env.push(Type.any) # XXX: warning needed?
|
1437
1507
|
else
|
1438
1508
|
ty = get_constant(cbase, name)
|
@@ -1612,7 +1682,7 @@ module TypeProf
|
|
1612
1682
|
locals = [Type.nil] * iseq.locals.size
|
1613
1683
|
nenv = Env.new(env.static_env, locals, [], Utils::HashWrapper.new({}))
|
1614
1684
|
merge_env(nep, nenv)
|
1615
|
-
add_callsite!(nep.ctx,
|
1685
|
+
add_callsite!(nep.ctx, cont_ep, cont_env) do |ret_ty, ep, env|
|
1616
1686
|
nenv, ret_ty = localize_type(ret_ty, env, ep)
|
1617
1687
|
nenv = nenv.push(ret_ty)
|
1618
1688
|
merge_env(ep.jump(cont), nenv)
|
@@ -1699,33 +1769,38 @@ module TypeProf
|
|
1699
1769
|
_, (ty,) = ty.elems.take_last(1)
|
1700
1770
|
case ty
|
1701
1771
|
when Type::Hash
|
1702
|
-
|
1772
|
+
kw_tys = ty.elems.to_keywords
|
1703
1773
|
when Type::Union
|
1704
1774
|
hash_elems = nil
|
1705
1775
|
ty.elems&.each do |(container_kind, base_type), elems|
|
1706
1776
|
if container_kind == Type::Hash
|
1777
|
+
elems.to_keywords
|
1707
1778
|
hash_elems = hash_elems ? hash_elems.union(elems) : elems
|
1708
1779
|
end
|
1709
1780
|
end
|
1710
|
-
hash_elems
|
1711
|
-
|
1781
|
+
if hash_elems
|
1782
|
+
kw_tys = hash_elems.to_keywords
|
1783
|
+
else
|
1784
|
+
kw_tys = { nil => Type.any }
|
1785
|
+
end
|
1712
1786
|
else
|
1713
1787
|
warn(ep, "non hash is passed to **kwarg?") unless ty == Type.any
|
1714
|
-
|
1788
|
+
kw_tys = { nil => Type.any }
|
1715
1789
|
end
|
1716
1790
|
else
|
1717
1791
|
raise NotImplementedError
|
1718
1792
|
end
|
1719
|
-
|
1793
|
+
else
|
1794
|
+
kw_tys = {}
|
1720
1795
|
end
|
1721
|
-
aargs = ActualArguments.new(aargs, rest_ty,
|
1796
|
+
aargs = ActualArguments.new(aargs, rest_ty, kw_tys, blk_ty)
|
1722
1797
|
elsif flag_args_kw_splat
|
1723
1798
|
last = aargs.last
|
1724
1799
|
ty = globalize_type(last, env, ep)
|
1725
1800
|
case ty
|
1726
1801
|
when Type::Hash
|
1727
1802
|
aargs = aargs[0..-2]
|
1728
|
-
|
1803
|
+
kw_tys = ty.elems.to_keywords
|
1729
1804
|
when Type::Union
|
1730
1805
|
hash_elems = nil
|
1731
1806
|
ty.elems.each do |(container_kind, base_type), elems|
|
@@ -1733,31 +1808,30 @@ module TypeProf
|
|
1733
1808
|
hash_elems = hash_elems ? hash_elems.union(elems) : elems
|
1734
1809
|
end
|
1735
1810
|
end
|
1736
|
-
hash_elems
|
1737
|
-
|
1811
|
+
if hash_elems
|
1812
|
+
kw_tys = hash_elems.to_keywords
|
1813
|
+
else
|
1814
|
+
kw_tys = { nil => Type.any }
|
1815
|
+
end
|
1738
1816
|
when Type::Any
|
1739
1817
|
aargs = aargs[0..-2]
|
1740
|
-
|
1818
|
+
kw_tys = { nil => Type.any }
|
1741
1819
|
else
|
1742
1820
|
warn(ep, "non hash is passed to **kwarg?")
|
1743
|
-
|
1821
|
+
kw_tys = { nil => Type.any }
|
1744
1822
|
end
|
1745
|
-
aargs = ActualArguments.new(aargs, nil,
|
1823
|
+
aargs = ActualArguments.new(aargs, nil, kw_tys, blk_ty)
|
1746
1824
|
elsif flag_args_kwarg
|
1747
1825
|
kw_vals = aargs.pop(kw_arg.size)
|
1748
1826
|
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
1752
|
-
h[k_ty] = v_ty
|
1753
|
-
end
|
1827
|
+
kw_tys = {}
|
1828
|
+
kw_arg.zip(kw_vals) do |key, v_ty|
|
1829
|
+
kw_tys[key] = v_ty
|
1754
1830
|
end
|
1755
1831
|
|
1756
|
-
|
1757
|
-
|
1758
|
-
aargs = ActualArguments.new(aargs, nil, kw_ty, blk_ty)
|
1832
|
+
aargs = ActualArguments.new(aargs, nil, kw_tys, blk_ty)
|
1759
1833
|
else
|
1760
|
-
aargs = ActualArguments.new(aargs, nil,
|
1834
|
+
aargs = ActualArguments.new(aargs, nil, {}, blk_ty)
|
1761
1835
|
end
|
1762
1836
|
|
1763
1837
|
if blk_iseq
|
@@ -1781,7 +1855,11 @@ module TypeProf
|
|
1781
1855
|
meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
|
1782
1856
|
end
|
1783
1857
|
else
|
1784
|
-
|
1858
|
+
case recv
|
1859
|
+
when Type::Void
|
1860
|
+
error(ep, "void's method is called: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
|
1861
|
+
when Type::Any
|
1862
|
+
else
|
1785
1863
|
error(ep, "undefined method: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
|
1786
1864
|
end
|
1787
1865
|
ctn[Type.any, ep, env]
|
@@ -1800,7 +1878,7 @@ module TypeProf
|
|
1800
1878
|
blk_env = blk_env.replace_recv_ty(replace_recv_ty) if replace_recv_ty
|
1801
1879
|
arg_blk = aargs.blk_ty
|
1802
1880
|
aargs_ = aargs.lead_tys.map {|aarg| globalize_type(aarg, env, ep) }
|
1803
|
-
# XXX: aargs.opt_tys and aargs.
|
1881
|
+
# XXX: aargs.opt_tys and aargs.kw_tys
|
1804
1882
|
argc = blk_iseq.fargs_format[:lead_num] || 0
|
1805
1883
|
# actual argc == 1, not array, formal argc == 1: yield 42 => do |x| : x=42
|
1806
1884
|
# actual argc == 1, array, formal argc == 1: yield [42,43,44] => do |x| : x=[42,43,44]
|
@@ -1879,7 +1957,8 @@ module TypeProf
|
|
1879
1957
|
|
1880
1958
|
add_yield!(ep.ctx, globalize_type(aargs, env, ep), nep.ctx) if given_block
|
1881
1959
|
add_block_to_ctx!(blk, nep.ctx)
|
1882
|
-
add_callsite!(nep.ctx,
|
1960
|
+
add_callsite!(nep.ctx, ep, env, &ctn)
|
1961
|
+
add_signature!(nep.ctx, nfargs)
|
1883
1962
|
end
|
1884
1963
|
end
|
1885
1964
|
|