typeprof 0.5.4 → 0.9.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/Gemfile.lock +7 -5
- data/doc/doc.ja.md +3 -4
- data/doc/doc.md +3 -4
- data/lib/typeprof/analyzer.rb +308 -171
- data/lib/typeprof/arguments.rb +14 -6
- data/lib/typeprof/block.rb +6 -2
- data/lib/typeprof/builtin.rb +230 -67
- data/lib/typeprof/cli.rb +33 -34
- data/lib/typeprof/config.rb +6 -4
- data/lib/typeprof/container-type.rb +159 -104
- data/lib/typeprof/export.rb +28 -22
- data/lib/typeprof/import.rb +70 -53
- data/lib/typeprof/iseq.rb +23 -7
- data/lib/typeprof/method.rb +71 -138
- data/lib/typeprof/type.rb +73 -15
- data/lib/typeprof/version.rb +1 -1
- data/smoke/alias.rb +5 -4
- data/smoke/alias2.rb +4 -4
- data/smoke/any1.rb +2 -1
- data/smoke/any2.rb +3 -2
- data/smoke/arguments.rb +3 -2
- data/smoke/arguments2.rb +11 -10
- data/smoke/array-each.rb +2 -1
- data/smoke/array-each2.rb +2 -1
- data/smoke/array-each3.rb +2 -1
- data/smoke/array-ltlt.rb +2 -1
- data/smoke/array-ltlt2.rb +2 -1
- data/smoke/array-map.rb +2 -1
- data/smoke/array-map2.rb +2 -1
- data/smoke/array-map3.rb +4 -3
- data/smoke/array-mul.rb +3 -2
- data/smoke/array-plus1.rb +2 -1
- data/smoke/array-plus2.rb +2 -2
- data/smoke/array-pop.rb +2 -1
- data/smoke/array-range-aref.rb +71 -0
- data/smoke/array-replace.rb +2 -1
- data/smoke/array-s-aref.rb +2 -1
- data/smoke/array1.rb +6 -5
- data/smoke/array10.rb +2 -1
- data/smoke/array11.rb +2 -1
- data/smoke/array12.rb +4 -3
- data/smoke/array13.rb +5 -4
- data/smoke/array14.rb +2 -1
- data/smoke/array15.rb +16 -0
- data/smoke/array2.rb +4 -3
- data/smoke/array3.rb +4 -4
- data/smoke/array4.rb +2 -1
- data/smoke/array5.rb +2 -1
- data/smoke/array6.rb +3 -2
- data/smoke/array7.rb +2 -1
- data/smoke/array8.rb +1 -1
- data/smoke/array9.rb +2 -1
- data/smoke/attr-module.rb +26 -0
- data/smoke/attr.rb +5 -5
- data/smoke/autoload.rb +14 -0
- data/smoke/backtrace.rb +4 -3
- data/smoke/block-ambiguous.rb +9 -8
- data/smoke/block-args1-rest.rb +12 -11
- data/smoke/block-args1.rb +11 -10
- data/smoke/block-args2-rest.rb +12 -11
- data/smoke/block-args2.rb +11 -10
- data/smoke/block-args3-rest.rb +14 -13
- data/smoke/block-args3.rb +13 -12
- data/smoke/block-blockarg.rb +5 -4
- data/smoke/block-kwarg.rb +11 -10
- data/smoke/block1.rb +2 -1
- data/smoke/block10.rb +2 -1
- data/smoke/block11.rb +6 -5
- data/smoke/block12.rb +3 -2
- data/smoke/block14.rb +3 -2
- data/smoke/block2.rb +2 -1
- data/smoke/block3.rb +3 -3
- data/smoke/block4.rb +3 -2
- data/smoke/block5.rb +3 -2
- data/smoke/block6.rb +3 -2
- data/smoke/block7.rb +2 -1
- data/smoke/block8.rb +4 -3
- data/smoke/block9.rb +2 -1
- data/smoke/blown.rb +2 -1
- data/smoke/break1.rb +3 -2
- data/smoke/break2.rb +2 -1
- data/smoke/break3.rb +13 -0
- data/smoke/case.rb +2 -1
- data/smoke/case2.rb +2 -1
- data/smoke/case3.rb +17 -0
- data/smoke/class-hierarchy.rb +5 -5
- data/smoke/class-hierarchy2.rb +3 -3
- data/smoke/class-new.rb +15 -0
- data/smoke/class_instance_var.rb +1 -1
- data/smoke/class_method.rb +2 -2
- data/smoke/class_method2.rb +2 -2
- data/smoke/class_method3.rb +4 -2
- data/smoke/constant1.rb +6 -6
- data/smoke/constant2.rb +5 -4
- data/smoke/constant3.rb +2 -1
- data/smoke/constant4.rb +2 -1
- data/smoke/context-sensitive1.rb +2 -1
- data/smoke/cvar.rb +6 -5
- data/smoke/cvar2.rb +2 -2
- data/smoke/define_method.rb +16 -0
- data/smoke/define_method2.rb +18 -0
- data/smoke/define_method3.rb +13 -0
- data/smoke/define_method3.rbs +3 -0
- data/smoke/define_method4.rb +15 -0
- data/smoke/define_method4.rbs +3 -0
- data/smoke/define_method5.rb +12 -0
- data/smoke/demo.rb +7 -6
- data/smoke/demo1.rb +2 -1
- data/smoke/demo10.rb +3 -2
- data/smoke/demo11.rb +2 -1
- data/smoke/demo2.rb +2 -1
- data/smoke/demo3.rb +2 -1
- data/smoke/demo4.rb +3 -3
- data/smoke/demo5.rb +1 -1
- data/smoke/demo6.rb +3 -3
- data/smoke/demo7.rb +2 -1
- data/smoke/demo8.rb +3 -2
- data/smoke/demo9.rb +3 -2
- data/smoke/dummy-execution1.rb +3 -2
- data/smoke/dummy-execution2.rb +2 -2
- data/smoke/dummy_element.rb +14 -0
- data/smoke/ensure1.rb +3 -2
- data/smoke/enumerator.rb +3 -2
- data/smoke/expandarray1.rb +2 -1
- data/smoke/expandarray2.rb +2 -1
- data/smoke/fib.rb +2 -2
- data/smoke/flip-flop.rb +28 -0
- data/smoke/flow1.rb +2 -1
- data/smoke/flow2.rb +2 -1
- data/smoke/flow3.rb +2 -1
- data/smoke/flow5.rb +2 -1
- data/smoke/flow6.rb +2 -1
- data/smoke/flow7.rb +2 -1
- data/smoke/flow8.rb +2 -1
- data/smoke/flow9.rb +12 -0
- data/smoke/freeze.rb +2 -1
- data/smoke/function.rb +3 -2
- data/smoke/gvar.rb +3 -2
- data/smoke/gvar2.rb +3 -2
- data/smoke/hash-bot.rb +12 -0
- data/smoke/hash-fetch.rb +4 -3
- data/smoke/hash-merge-bang.rb +2 -1
- data/smoke/hash1.rb +3 -2
- data/smoke/hash2.rb +2 -1
- data/smoke/hash3.rb +2 -1
- data/smoke/hash4.rb +2 -1
- data/smoke/hash5.rb +1 -1
- data/smoke/inheritance.rb +4 -4
- data/smoke/inheritance2.rb +2 -2
- data/smoke/initialize.rb +6 -5
- data/smoke/instance_eval.rb +2 -2
- data/smoke/instance_eval2.rb +10 -0
- data/smoke/instance_eval3.rb +25 -0
- data/smoke/int_times.rb +2 -1
- data/smoke/integer.rb +2 -1
- data/smoke/ivar.rb +5 -4
- data/smoke/ivar2.rb +4 -4
- data/smoke/ivar3.rb +2 -2
- data/smoke/kernel-class.rb +2 -1
- data/smoke/keyword1.rb +2 -1
- data/smoke/keyword2.rb +2 -1
- data/smoke/keyword3.rb +2 -1
- data/smoke/keyword4.rb +2 -1
- data/smoke/keyword5.rb +2 -1
- data/smoke/kwrest.rb +12 -0
- data/smoke/kwrest.rbs +3 -0
- data/smoke/kwsplat1.rb +5 -4
- data/smoke/kwsplat2.rb +2 -1
- data/smoke/lit-complex.rb +10 -0
- data/smoke/lit-encoding.rb +10 -0
- data/smoke/manual-rbs.rb +4 -3
- data/smoke/manual-rbs2.rb +2 -1
- data/smoke/manual-rbs3.rb +2 -2
- data/smoke/masgn1.rb +2 -1
- data/smoke/masgn2.rb +3 -2
- data/smoke/masgn3.rb +2 -1
- data/smoke/method_in_branch.rb +3 -2
- data/smoke/method_missing.rb +28 -0
- data/smoke/module1.rb +2 -2
- data/smoke/module2.rb +1 -1
- data/smoke/module3.rb +2 -2
- data/smoke/module4.rb +2 -2
- data/smoke/module5.rb +17 -0
- data/smoke/module6.rb +40 -0
- data/smoke/module_function1.rb +3 -3
- data/smoke/module_function2.rb +3 -3
- data/smoke/multiple-include.rb +1 -1
- data/smoke/multiple-superclass.rb +1 -1
- data/smoke/next1.rb +3 -2
- data/smoke/next2.rb +2 -1
- data/smoke/object-send1.rb +4 -3
- data/smoke/object-send2.rb +10 -0
- data/smoke/object-send3.rb +18 -0
- data/smoke/once.rb +2 -1
- data/smoke/optional1.rb +2 -1
- data/smoke/optional2.rb +2 -1
- data/smoke/optional3.rb +2 -1
- data/smoke/parameterizedd-self.rb +3 -2
- data/smoke/parameterizedd-self2.rb +15 -0
- data/smoke/pathname1.rb +2 -1
- data/smoke/pathname2.rb +2 -1
- data/smoke/pattern-match1.rb +2 -1
- data/smoke/pattern-match2.rb +2 -1
- data/smoke/printf.rb +2 -2
- data/smoke/proc.rb +3 -2
- data/smoke/proc2.rb +2 -1
- data/smoke/proc3.rb +2 -1
- data/smoke/proc4.rb +2 -1
- data/smoke/proc5.rb +19 -0
- data/smoke/public.rb +34 -0
- data/smoke/range.rb +2 -1
- data/smoke/rbs-alias.rb +2 -1
- data/smoke/rbs-attr.rb +6 -5
- data/smoke/rbs-attr2.rb +11 -0
- data/smoke/rbs-attr2.rbs +3 -0
- data/smoke/rbs-extend.rb +2 -1
- data/smoke/rbs-interface.rb +5 -4
- data/smoke/rbs-module.rb +26 -0
- data/smoke/rbs-module.rbs +4 -0
- data/smoke/rbs-opt-and-rest.rb +10 -0
- data/smoke/rbs-opt-and-rest.rbs +3 -0
- data/smoke/rbs-proc1.rb +2 -1
- data/smoke/rbs-proc2.rb +3 -2
- data/smoke/rbs-proc3.rb +2 -1
- data/smoke/rbs-record.rb +3 -2
- data/smoke/rbs-tyvar.rb +3 -2
- data/smoke/rbs-tyvar2.rb +3 -2
- data/smoke/rbs-tyvar3.rb +3 -2
- data/smoke/rbs-tyvar4.rb +3 -3
- data/smoke/rbs-tyvar5.rb +2 -1
- data/smoke/rbs-tyvar6.rb +18 -0
- data/smoke/rbs-tyvar6.rbs +12 -0
- data/smoke/rbs-tyvar7.rb +12 -0
- data/smoke/rbs-tyvar7.rbs +7 -0
- data/smoke/rbs-vars.rb +7 -8
- data/smoke/redo1.rb +3 -2
- data/smoke/redo2.rb +3 -2
- data/smoke/req-keyword.rb +2 -1
- data/smoke/rescue1.rb +3 -2
- data/smoke/rescue2.rb +3 -2
- data/smoke/rescue3.rb +19 -0
- data/smoke/rescue4.rb +17 -0
- data/smoke/respond_to.rb +2 -1
- data/smoke/rest-farg.rb +2 -1
- data/smoke/rest1.rb +3 -2
- data/smoke/rest2.rb +2 -1
- data/smoke/rest3.rb +7 -6
- data/smoke/rest4.rb +3 -2
- data/smoke/rest5.rb +2 -1
- data/smoke/rest6.rb +2 -1
- data/smoke/retry1.rb +3 -2
- data/smoke/return.rb +2 -1
- data/smoke/singleton_method.rb +1 -1
- data/smoke/step.rb +4 -3
- data/smoke/string-split.rb +2 -1
- data/smoke/struct-keyword_init.rb +20 -0
- data/smoke/struct.rb +1 -1
- data/smoke/struct2.rb +5 -4
- data/smoke/struct3.rb +2 -2
- data/smoke/struct4.rb +7 -0
- data/smoke/struct5.rb +16 -0
- data/smoke/struct6.rb +15 -0
- data/smoke/struct7.rb +17 -0
- data/smoke/stub-keyword.rb +10 -0
- data/smoke/super1.rb +5 -4
- data/smoke/super2.rb +1 -1
- data/smoke/super3.rb +3 -3
- data/smoke/super4.rb +43 -0
- data/smoke/super5.rb +36 -0
- data/smoke/svar1.rb +2 -1
- data/smoke/symbol-proc-attr.rb +22 -0
- data/smoke/symbol-proc-attr2.rb +15 -0
- data/smoke/symbol-proc-bot.rb +13 -0
- data/smoke/symbol-proc.rb +4 -3
- data/smoke/tap1.rb +3 -2
- data/smoke/toplevel.rb +2 -1
- data/smoke/two-map.rb +3 -2
- data/smoke/type_var.rb +2 -1
- data/smoke/typed_method.rb +2 -1
- data/smoke/uninitialize-var.rb +2 -1
- data/smoke/union-recv.rb +2 -2
- data/smoke/user-demo.rb +3 -3
- data/smoke/wrong-extend.rb +2 -2
- data/smoke/wrong-include.rb +2 -2
- data/smoke/wrong-include2.rb +17 -0
- data/typeprof.gemspec +1 -1
- metadata +61 -6
- data/tools/stackprof-wrapper.rb +0 -10
data/lib/typeprof/cli.rb
CHANGED
@@ -7,60 +7,59 @@ module TypeProf
|
|
7
7
|
def parse(argv)
|
8
8
|
opt = OptionParser.new
|
9
9
|
|
10
|
+
opt.banner = "Usage: #{ opt.program_name } [options] files..."
|
11
|
+
|
10
12
|
output = nil
|
11
13
|
|
12
14
|
# Verbose level:
|
13
|
-
# * 0:
|
14
|
-
# * 1:
|
15
|
-
# * 2:
|
15
|
+
# * 0: none
|
16
|
+
# * 1: default level
|
17
|
+
# * 2: debugging level
|
16
18
|
verbose = 1
|
17
19
|
|
18
20
|
options = {}
|
19
21
|
dir_filter = nil
|
20
22
|
gem_rbs_features = []
|
21
|
-
|
23
|
+
show_version = false
|
22
24
|
max_sec = max_iter = nil
|
23
25
|
|
24
|
-
opt.
|
25
|
-
opt.
|
26
|
-
opt.on("-
|
27
|
-
opt.on("--
|
28
|
-
opt.on("-
|
29
|
-
opt.on("
|
30
|
-
opt.on("-
|
31
|
-
opt.on("
|
32
|
-
opt.on("--max-iteration TIMES", Integer) {|v| max_iter = v }
|
26
|
+
opt.separator ""
|
27
|
+
opt.separator "Options:"
|
28
|
+
opt.on("-o OUTFILE", "Output to OUTFILE instead of stdout") {|v| output = v }
|
29
|
+
opt.on("-q", "--quiet", "Do not display progress indicator") { options[:show_indicator] = false }
|
30
|
+
opt.on("-v", "--verbose", "Alias to --show-errors") { options[:show_errors] = true }
|
31
|
+
opt.on("--version", "Display typeprof version") { show_version = true }
|
32
|
+
opt.on("-I DIR", "Add DIR to the load/require path") {|v| $LOAD_PATH << v }
|
33
|
+
opt.on("-r FEATURE", "Require RBS of the FEATURE gem") {|v| gem_rbs_features << v }
|
33
34
|
|
34
|
-
opt.
|
35
|
+
opt.separator ""
|
36
|
+
opt.separator "Analysis output options:"
|
37
|
+
opt.on("--include-dir DIR", "Include the analysis result of .rb file in DIR") do |dir|
|
35
38
|
# When `--include-dir` option is specified as the first directory option,
|
36
39
|
# typeprof will exclude any files by default unless a file path matches the explicit option
|
37
40
|
dir_filter ||= [[:exclude]]
|
38
41
|
dir_filter << [:include, File.expand_path(dir)]
|
39
42
|
end
|
40
|
-
opt.on("--exclude-dir DIR") do |dir|
|
43
|
+
opt.on("--exclude-dir DIR", "Exclude the analysis result of .rb file in DIR") do |dir|
|
41
44
|
# When `--exclude-dir` option is specified as the first directory option,
|
42
45
|
# typeprof will include any files by default, except Ruby's install directory and Gem directories
|
43
46
|
dir_filter ||= ConfigData::DEFAULT_DIR_FILTER
|
44
47
|
dir_filter << [:exclude, File.expand_path(dir)]
|
45
48
|
end
|
49
|
+
opt.on("--[no-]show-errors", "Display possible errors found during the analysis") {|v| options[:show_errors] = v }
|
50
|
+
opt.on("--[no-]show-untyped", "Display \"Foo | untyped\" instead of \"Foo\"") {|v| options[:show_untyped] = v }
|
46
51
|
|
47
|
-
opt.
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
when "stackprof"
|
59
|
-
options[:stackprof] = args ? args.to_sym : :cpu
|
60
|
-
else
|
61
|
-
raise OptionParser::InvalidOption.new("unknown option: #{ key }")
|
62
|
-
end
|
63
|
-
end
|
52
|
+
opt.separator ""
|
53
|
+
opt.separator "Analysis limit options:"
|
54
|
+
opt.on("--max-second SECOND", Float, "Limit the maxium time of analysis (in second)") {|v| max_sec = v }
|
55
|
+
opt.on("--max-iteration TIMES", Integer, "Limit the maxium instruction count of analysis") {|v| max_iter = v }
|
56
|
+
|
57
|
+
opt.separator ""
|
58
|
+
opt.separator "Advanced options:"
|
59
|
+
opt.on("--[no-]stub-execution", "Force to call all unreachable methods with \"untyped\" arguments") {|v| options[:stub_execution] = v }
|
60
|
+
opt.on("--type-depth-limit DEPTH", Integer, "Limit the maximum depth of nested types") {|v| options[:type_depth_limit] = v }
|
61
|
+
opt.on("--debug", "Display analysis log (for debugging purpose)") { verbose = 2 }
|
62
|
+
opt.on("--[no-]stackprof MODE", /\Acpu|wall|object\z/, "Enable stackprof (for debugging purpose)") {|v| options[:stackprof] = v.to_sym }
|
64
63
|
|
65
64
|
opt.parse!(argv)
|
66
65
|
|
@@ -75,9 +74,9 @@ module TypeProf
|
|
75
74
|
end
|
76
75
|
end
|
77
76
|
|
78
|
-
puts "typeprof #{ VERSION }" if
|
77
|
+
puts "typeprof #{ VERSION }" if show_version
|
79
78
|
if rb_files.empty?
|
80
|
-
exit if
|
79
|
+
exit if show_version
|
81
80
|
raise OptionParser::InvalidOption.new("no input files")
|
82
81
|
end
|
83
82
|
|
data/lib/typeprof/config.rb
CHANGED
@@ -22,9 +22,11 @@ module TypeProf
|
|
22
22
|
opt[:verbose] ||= 0
|
23
23
|
opt[:options] ||= {}
|
24
24
|
opt[:options] = {
|
25
|
-
|
26
|
-
|
25
|
+
show_indicator: true,
|
26
|
+
show_untyped: false,
|
27
27
|
show_errors: false,
|
28
|
+
stub_execution: true,
|
29
|
+
type_depth_limit: 5,
|
28
30
|
stackprof: nil,
|
29
31
|
}.merge(opt[:options])
|
30
32
|
super(**opt)
|
@@ -67,7 +69,7 @@ module TypeProf
|
|
67
69
|
|
68
70
|
prologue_ctx = Context.new(nil, nil, nil)
|
69
71
|
prologue_ep = ExecutionPoint.new(prologue_ctx, -1, nil)
|
70
|
-
prologue_env = Env.new(StaticEnv.new(:top, Type.nil, false), [], [], Utils::HashWrapper.new({}))
|
72
|
+
prologue_env = Env.new(StaticEnv.new(:top, Type.nil, false, true), [], [], Utils::HashWrapper.new({}))
|
71
73
|
|
72
74
|
Config.rb_files.each do |rb|
|
73
75
|
if rb.is_a?(Array) # [String name, String content]
|
@@ -111,7 +113,7 @@ module TypeProf
|
|
111
113
|
ctx = Context.new(iseq, cref, nil)
|
112
114
|
ep = ExecutionPoint.new(ctx, 0, nil)
|
113
115
|
locals = [Type.nil] * iseq.locals.size
|
114
|
-
env = Env.new(StaticEnv.new(recv, Type.nil, false), locals, [], Utils::HashWrapper.new({}))
|
116
|
+
env = Env.new(StaticEnv.new(recv, Type.nil, false, false), locals, [], Utils::HashWrapper.new({}))
|
115
117
|
|
116
118
|
return ep, env
|
117
119
|
end
|
@@ -77,7 +77,9 @@ module TypeProf
|
|
77
77
|
return env, Type.any if depth <= 0
|
78
78
|
alloc_site = alloc_site.add_id(:cell).add_id(@base_type)
|
79
79
|
env, elems = @elems.localize(env, alloc_site, depth)
|
80
|
-
|
80
|
+
ty = Local.new(Cell, alloc_site, @base_type)
|
81
|
+
env = env.deploy_type(alloc_site, elems)
|
82
|
+
return env, ty
|
81
83
|
end
|
82
84
|
|
83
85
|
def limit_size(limit)
|
@@ -85,7 +87,7 @@ module TypeProf
|
|
85
87
|
Cell.new(@elems.limit_size(limit - 1), @base_type)
|
86
88
|
end
|
87
89
|
|
88
|
-
def
|
90
|
+
def method_dispatch_info
|
89
91
|
raise
|
90
92
|
end
|
91
93
|
|
@@ -95,6 +97,19 @@ module TypeProf
|
|
95
97
|
Cell.new(elems, @base_type)
|
96
98
|
end
|
97
99
|
|
100
|
+
def generate_substitution
|
101
|
+
subst = {}
|
102
|
+
tyvars = @base_type.klass.type_params.map {|name,| Type::Var.new(name) }
|
103
|
+
tyvars.zip(@elems.elems) do |tyvar, elem|
|
104
|
+
if subst[tyvar]
|
105
|
+
subst[tyvar] = subst[tyvar].union(elem)
|
106
|
+
else
|
107
|
+
subst[tyvar] = elem
|
108
|
+
end
|
109
|
+
end
|
110
|
+
subst
|
111
|
+
end
|
112
|
+
|
98
113
|
class Elements # Cell
|
99
114
|
include Utils::StructuralEquality
|
100
115
|
|
@@ -102,10 +117,14 @@ module TypeProf
|
|
102
117
|
@elems = elems
|
103
118
|
end
|
104
119
|
|
120
|
+
def self.dummy_elements
|
121
|
+
Elements.new([]) # XXX
|
122
|
+
end
|
123
|
+
|
105
124
|
attr_reader :elems
|
106
125
|
|
107
126
|
def to_local_type(id, base_ty)
|
108
|
-
Type::
|
127
|
+
Type::Local.new(Cell, id, base_ty)
|
109
128
|
end
|
110
129
|
|
111
130
|
def globalize(env, visited, depth)
|
@@ -180,45 +199,6 @@ module TypeProf
|
|
180
199
|
end
|
181
200
|
end
|
182
201
|
|
183
|
-
class LocalCell < ContainerType
|
184
|
-
def initialize(id, base_type)
|
185
|
-
@id = id
|
186
|
-
raise unless base_type
|
187
|
-
@base_type = base_type
|
188
|
-
end
|
189
|
-
|
190
|
-
attr_reader :id, :base_type
|
191
|
-
|
192
|
-
def inspect
|
193
|
-
"Type::LocalCell[#{ @id }, base_type: #{ @base_type.inspect }]"
|
194
|
-
end
|
195
|
-
|
196
|
-
def screen_name(scratch)
|
197
|
-
#raise "LocalArray must not be included in signature"
|
198
|
-
"LocalCell!"
|
199
|
-
end
|
200
|
-
|
201
|
-
def globalize(env, visited, depth)
|
202
|
-
if visited[self] || depth <= 0
|
203
|
-
Type.any
|
204
|
-
else
|
205
|
-
visited[self] = true
|
206
|
-
elems = env.get_container_elem_types(@id)
|
207
|
-
if elems
|
208
|
-
elems = elems.globalize(env, visited, depth - 1)
|
209
|
-
else
|
210
|
-
elems = Cell::Elements.new([]) # XXX
|
211
|
-
end
|
212
|
-
visited.delete(self)
|
213
|
-
Cell.new(elems, @base_type)
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def get_method(mid, scratch)
|
218
|
-
@base_type.get_method(mid, scratch)
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
202
|
# Do not insert Array type to local environment, stack, etc.
|
223
203
|
class Array < ContainerType
|
224
204
|
def initialize(elems, base_type)
|
@@ -247,7 +227,9 @@ module TypeProf
|
|
247
227
|
return env, Type.any if depth <= 0
|
248
228
|
alloc_site = alloc_site.add_id(:ary).add_id(@base_type)
|
249
229
|
env, elems = @elems.localize(env, alloc_site, depth - 1)
|
250
|
-
|
230
|
+
ty = Local.new(Array, alloc_site, @base_type)
|
231
|
+
env = env.deploy_type(alloc_site, elems)
|
232
|
+
return env, ty
|
251
233
|
end
|
252
234
|
|
253
235
|
def limit_size(limit)
|
@@ -255,7 +237,7 @@ module TypeProf
|
|
255
237
|
Array.new(@elems.limit_size(limit - 1), @base_type)
|
256
238
|
end
|
257
239
|
|
258
|
-
def
|
240
|
+
def method_dispatch_info
|
259
241
|
raise
|
260
242
|
end
|
261
243
|
|
@@ -265,6 +247,10 @@ module TypeProf
|
|
265
247
|
Array.new(elems, @base_type)
|
266
248
|
end
|
267
249
|
|
250
|
+
def generate_substitution
|
251
|
+
{ Type::Var.new(:Elem) => @elems.squash }
|
252
|
+
end
|
253
|
+
|
268
254
|
class Elements # Array
|
269
255
|
include Utils::StructuralEquality
|
270
256
|
|
@@ -274,10 +260,14 @@ module TypeProf
|
|
274
260
|
@lead_tys, @rest_ty = lead_tys, rest_ty
|
275
261
|
end
|
276
262
|
|
263
|
+
def self.dummy_elements
|
264
|
+
Elements.new([], Type.any)
|
265
|
+
end
|
266
|
+
|
277
267
|
attr_reader :lead_tys, :rest_ty
|
278
268
|
|
279
269
|
def to_local_type(id, base_ty)
|
280
|
-
Type::
|
270
|
+
Type::Local.new(Array, id, base_ty)
|
281
271
|
end
|
282
272
|
|
283
273
|
def globalize(env, visited, depth)
|
@@ -305,7 +295,7 @@ module TypeProf
|
|
305
295
|
end
|
306
296
|
|
307
297
|
def screen_name(scratch)
|
308
|
-
if
|
298
|
+
if @rest_ty == Type.bot
|
309
299
|
if @lead_tys.empty?
|
310
300
|
return "Array[bot]" # RBS does not allow an empty tuple "[]"
|
311
301
|
end
|
@@ -363,7 +353,57 @@ module TypeProf
|
|
363
353
|
end
|
364
354
|
|
365
355
|
def [](idx)
|
366
|
-
if idx
|
356
|
+
if idx.is_a?(Range)
|
357
|
+
if @rest_ty == Type.bot
|
358
|
+
lead_tys = @lead_tys[idx]
|
359
|
+
if lead_tys
|
360
|
+
rest_ty = Type.bot
|
361
|
+
else
|
362
|
+
return Type.nil
|
363
|
+
end
|
364
|
+
else
|
365
|
+
b, e = idx.begin, idx.end
|
366
|
+
b = 0 if !b
|
367
|
+
if !e
|
368
|
+
lead_tys = @lead_tys[idx] || []
|
369
|
+
rest_ty = @rest_ty
|
370
|
+
elsif b >= 0
|
371
|
+
if e >= 0
|
372
|
+
if b <= e
|
373
|
+
if e < @lead_tys.size
|
374
|
+
lead_tys = @lead_tys[idx]
|
375
|
+
rest_ty = Type.bot
|
376
|
+
else
|
377
|
+
lead_tys = @lead_tys[idx] || []
|
378
|
+
rest_ty = @rest_ty
|
379
|
+
end
|
380
|
+
else
|
381
|
+
return Type.nil
|
382
|
+
end
|
383
|
+
else
|
384
|
+
lead_tys = @lead_tys[idx] || []
|
385
|
+
e = idx.exclude_end? ? e : e == -1 ? @lead_tys.size : e + 1
|
386
|
+
rest_ty = (@lead_tys[e + 1..] || []).inject(@rest_ty) {|ty0, ty1| ty0.union(ty1) }
|
387
|
+
end
|
388
|
+
else
|
389
|
+
lead_tys = []
|
390
|
+
if e >= 0
|
391
|
+
rest_ty = e < @lead_tys.size ? Type.bot : @rest_ty
|
392
|
+
range = [0, @lead_tys.size + b].max .. (idx.exclude_end? ? e - 1 : e)
|
393
|
+
rest_ty = @lead_tys[range].inject(rest_ty) {|ty0, ty1| ty0.union(ty1) }
|
394
|
+
else
|
395
|
+
if b <= e
|
396
|
+
range = [0, @lead_tys.size + b].max .. (idx.exclude_end? ? e - 1 : e)
|
397
|
+
rest_ty = @lead_tys[range].inject(@rest_ty) {|ty0, ty1| ty0.union(ty1) }
|
398
|
+
else
|
399
|
+
return Type.nil
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
base_ty = Type::Instance.new(Type::Builtin[:ary])
|
405
|
+
Array.new(Elements.new(lead_tys, rest_ty), base_ty)
|
406
|
+
elsif idx >= 0
|
367
407
|
if idx < @lead_tys.size
|
368
408
|
@lead_tys[idx]
|
369
409
|
elsif @rest_ty == Type.bot
|
@@ -494,48 +534,6 @@ module TypeProf
|
|
494
534
|
end
|
495
535
|
end
|
496
536
|
|
497
|
-
# Do not insert Array type to local environment, stack, etc.
|
498
|
-
class LocalArray < ContainerType
|
499
|
-
def initialize(id, base_type)
|
500
|
-
@id = id
|
501
|
-
raise unless base_type
|
502
|
-
@base_type = base_type
|
503
|
-
end
|
504
|
-
|
505
|
-
attr_reader :id, :base_type
|
506
|
-
|
507
|
-
def inspect
|
508
|
-
"Type::LocalArray[#{ @id }, base_type: #{ @base_type.inspect }]"
|
509
|
-
end
|
510
|
-
|
511
|
-
def screen_name(scratch)
|
512
|
-
#raise "LocalArray must not be included in signature"
|
513
|
-
"LocalArray!"
|
514
|
-
end
|
515
|
-
|
516
|
-
def globalize(env, visited, depth)
|
517
|
-
if visited[self] || depth <= 0
|
518
|
-
Type.any
|
519
|
-
else
|
520
|
-
visited[self] = true
|
521
|
-
elems = env.get_container_elem_types(@id)
|
522
|
-
if elems
|
523
|
-
elems = elems.globalize(env, visited, depth - 1)
|
524
|
-
else
|
525
|
-
# TODO: currently out-of-scope array cannot be accessed
|
526
|
-
elems = Array::Elements.new([], Type.any)
|
527
|
-
end
|
528
|
-
visited.delete(self)
|
529
|
-
Array.new(elems, @base_type)
|
530
|
-
end
|
531
|
-
end
|
532
|
-
|
533
|
-
def get_method(mid, scratch)
|
534
|
-
@base_type.get_method(mid, scratch)
|
535
|
-
end
|
536
|
-
end
|
537
|
-
|
538
|
-
|
539
537
|
class Hash < ContainerType
|
540
538
|
def initialize(elems, base_type)
|
541
539
|
@elems = elems
|
@@ -557,7 +555,9 @@ module TypeProf
|
|
557
555
|
return env, Type.any if depth <= 0
|
558
556
|
alloc_site = alloc_site.add_id(:hash).add_id(@base_type)
|
559
557
|
env, elems = @elems.localize(env, alloc_site, depth - 1)
|
560
|
-
|
558
|
+
ty = Local.new(Hash, alloc_site, @base_type)
|
559
|
+
env = env.deploy_type(alloc_site, elems)
|
560
|
+
return env, ty
|
561
561
|
end
|
562
562
|
|
563
563
|
def limit_size(limit)
|
@@ -565,7 +565,7 @@ module TypeProf
|
|
565
565
|
Hash.new(@elems.limit_size(limit - 1), @base_type)
|
566
566
|
end
|
567
567
|
|
568
|
-
def
|
568
|
+
def method_dispatch_info
|
569
569
|
raise
|
570
570
|
end
|
571
571
|
|
@@ -575,6 +575,14 @@ module TypeProf
|
|
575
575
|
Hash.new(elems, @base_type)
|
576
576
|
end
|
577
577
|
|
578
|
+
def generate_substitution
|
579
|
+
tyvar_k = Type::Var.new(:K)
|
580
|
+
tyvar_v = Type::Var.new(:V)
|
581
|
+
k_ty0, v_ty0 = @elems.squash
|
582
|
+
# XXX: need to heuristically replace ret type Hash[K, V] with self, instead of conversative type?
|
583
|
+
{ tyvar_k => k_ty0, tyvar_v => v_ty0 }
|
584
|
+
end
|
585
|
+
|
578
586
|
class Elements # Hash
|
579
587
|
include Utils::StructuralEquality
|
580
588
|
|
@@ -583,18 +591,21 @@ module TypeProf
|
|
583
591
|
raise unless k_ty.is_a?(Type)
|
584
592
|
raise unless v_ty.is_a?(Type)
|
585
593
|
raise if k_ty.is_a?(Type::Union)
|
586
|
-
raise if k_ty.is_a?(Type::
|
587
|
-
raise if k_ty.is_a?(Type::LocalHash)
|
594
|
+
raise if k_ty.is_a?(Type::Local)
|
588
595
|
raise if k_ty.is_a?(Type::Array)
|
589
596
|
raise if k_ty.is_a?(Type::Hash)
|
590
597
|
end
|
591
598
|
@map_tys = map_tys
|
592
599
|
end
|
593
600
|
|
601
|
+
def self.dummy_elements
|
602
|
+
Elements.new({Type.any => Type.any})
|
603
|
+
end
|
604
|
+
|
594
605
|
attr_reader :map_tys
|
595
606
|
|
596
607
|
def to_local_type(id, base_ty)
|
597
|
-
Type::
|
608
|
+
Type::Local.new(Hash, id, base_ty)
|
598
609
|
end
|
599
610
|
|
600
611
|
def globalize(env, visited, depth)
|
@@ -782,21 +793,24 @@ module TypeProf
|
|
782
793
|
end
|
783
794
|
end
|
784
795
|
|
785
|
-
class
|
786
|
-
def initialize(id, base_type)
|
796
|
+
class Local < ContainerType
|
797
|
+
def initialize(kind, id, base_type)
|
798
|
+
@kind = kind
|
799
|
+
raise if @kind != Cell && @kind != Array && @kind != Hash
|
787
800
|
@id = id
|
801
|
+
raise unless base_type
|
788
802
|
@base_type = base_type
|
789
803
|
end
|
790
804
|
|
791
|
-
attr_reader :id, :base_type
|
805
|
+
attr_reader :kind, :id, :base_type
|
792
806
|
|
793
807
|
def inspect
|
794
|
-
"Type::
|
808
|
+
"Type::Local[#{ @kind }, #{ @id }, base_type: #{ @base_type.inspect }]"
|
795
809
|
end
|
796
810
|
|
797
811
|
def screen_name(scratch)
|
798
|
-
#raise "
|
799
|
-
"
|
812
|
+
#raise "Local type must not be included in signature"
|
813
|
+
"Local[#{ @kind }]"
|
800
814
|
end
|
801
815
|
|
802
816
|
def globalize(env, visited, depth)
|
@@ -808,15 +822,56 @@ module TypeProf
|
|
808
822
|
if elems
|
809
823
|
elems = elems.globalize(env, visited, depth - 1)
|
810
824
|
else
|
811
|
-
|
825
|
+
# TODO: currently out-of-scope array cannot be accessed
|
826
|
+
elems = @kind::Elements.dummy_elements
|
812
827
|
end
|
813
828
|
visited.delete(self)
|
814
|
-
|
829
|
+
@kind.new(elems, @base_type)
|
815
830
|
end
|
816
831
|
end
|
817
832
|
|
818
|
-
def
|
819
|
-
@base_type.
|
833
|
+
def method_dispatch_info
|
834
|
+
@base_type.method_dispatch_info
|
835
|
+
end
|
836
|
+
|
837
|
+
def update_container_elem_type(subst, env, caller_ep, scratch)
|
838
|
+
case
|
839
|
+
when @kind == Cell
|
840
|
+
tyvars = @base_type.klass.type_params.map {|name,| Type::Var.new(name) }
|
841
|
+
# XXX: This should be skipped when the called methods belongs to superclass
|
842
|
+
tyvars.each_with_index do |tyvar, idx|
|
843
|
+
ty = subst[tyvar]
|
844
|
+
if ty
|
845
|
+
env, ty = scratch.localize_type(ty, env, caller_ep)
|
846
|
+
env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
|
847
|
+
elems.update(idx, ty)
|
848
|
+
end
|
849
|
+
end
|
850
|
+
end
|
851
|
+
when @kind == Array
|
852
|
+
tyvar_elem = Type::Var.new(:Elem)
|
853
|
+
if subst[tyvar_elem]
|
854
|
+
ty = subst[tyvar_elem]
|
855
|
+
env, ty = scratch.localize_type(ty, env, caller_ep)
|
856
|
+
env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
|
857
|
+
elems.update(nil, ty)
|
858
|
+
end
|
859
|
+
end
|
860
|
+
when @kind == Hash
|
861
|
+
tyvar_k = Type::Var.new(:K)
|
862
|
+
tyvar_v = Type::Var.new(:V)
|
863
|
+
if subst[tyvar_k] && subst[tyvar_v]
|
864
|
+
k_ty = subst[tyvar_k]
|
865
|
+
v_ty = subst[tyvar_v]
|
866
|
+
alloc_site = AllocationSite.new(caller_ep)
|
867
|
+
env, k_ty = scratch.localize_type(k_ty, env, caller_ep, alloc_site.add_id(:k))
|
868
|
+
env, v_ty = scratch.localize_type(v_ty, env, caller_ep, alloc_site.add_id(:v))
|
869
|
+
env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
|
870
|
+
elems.update(k_ty, v_ty)
|
871
|
+
end
|
872
|
+
end
|
873
|
+
end
|
874
|
+
env
|
820
875
|
end
|
821
876
|
end
|
822
877
|
end
|