typeprof 0.2.0 → 0.3.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.
- 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
|
|