typeprof 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +26 -0
- data/.gitignore +7 -0
- data/.gitmodules +6 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +41 -0
- data/README.md +53 -0
- data/Rakefile +10 -0
- data/doc/doc.ja.md +415 -0
- data/doc/doc.md +429 -0
- data/doc/ppl2019.pdf +0 -0
- data/exe/typeprof +5 -0
- data/lib/typeprof.rb +13 -0
- data/lib/typeprof/analyzer.rb +1911 -0
- data/lib/typeprof/builtin.rb +554 -0
- data/lib/typeprof/cli.rb +110 -0
- data/lib/typeprof/container-type.rb +626 -0
- data/lib/typeprof/export.rb +203 -0
- data/lib/typeprof/import.rb +546 -0
- data/lib/typeprof/insns-def.rb +61 -0
- data/lib/typeprof/iseq.rb +387 -0
- data/lib/typeprof/method.rb +267 -0
- data/lib/typeprof/type.rb +1092 -0
- data/lib/typeprof/utils.rb +209 -0
- data/run.sh +3 -0
- data/smoke/alias.rb +30 -0
- data/smoke/alias2.rb +19 -0
- data/smoke/any-cbase.rb +5 -0
- data/smoke/any1.rb +15 -0
- data/smoke/any2.rb +17 -0
- data/smoke/arguments.rb +16 -0
- data/smoke/array-each.rb +14 -0
- data/smoke/array-each2.rb +15 -0
- data/smoke/array-each3.rb +15 -0
- data/smoke/array-ltlt.rb +13 -0
- data/smoke/array-ltlt2.rb +16 -0
- data/smoke/array-map.rb +11 -0
- data/smoke/array-map2.rb +10 -0
- data/smoke/array-map3.rb +22 -0
- data/smoke/array-mul.rb +17 -0
- data/smoke/array-plus1.rb +10 -0
- data/smoke/array-plus2.rb +15 -0
- data/smoke/array-pop.rb +11 -0
- data/smoke/array-replace.rb +12 -0
- data/smoke/array-s-aref.rb +11 -0
- data/smoke/array1.rb +26 -0
- data/smoke/array10.rb +14 -0
- data/smoke/array11.rb +13 -0
- data/smoke/array12.rb +24 -0
- data/smoke/array13.rb +30 -0
- data/smoke/array14.rb +13 -0
- data/smoke/array2.rb +27 -0
- data/smoke/array3.rb +25 -0
- data/smoke/array4.rb +14 -0
- data/smoke/array5.rb +13 -0
- data/smoke/array6.rb +14 -0
- data/smoke/array7.rb +13 -0
- data/smoke/array8.rb +13 -0
- data/smoke/array9.rb +12 -0
- data/smoke/attr.rb +28 -0
- data/smoke/backtrace.rb +32 -0
- data/smoke/block1.rb +22 -0
- data/smoke/block10.rb +14 -0
- data/smoke/block11.rb +39 -0
- data/smoke/block12.rb +22 -0
- data/smoke/block2.rb +14 -0
- data/smoke/block3.rb +38 -0
- data/smoke/block4.rb +18 -0
- data/smoke/block5.rb +18 -0
- data/smoke/block6.rb +20 -0
- data/smoke/block7.rb +20 -0
- data/smoke/block8.rb +27 -0
- data/smoke/block9.rb +12 -0
- data/smoke/blown.rb +12 -0
- data/smoke/break1.rb +18 -0
- data/smoke/break2.rb +15 -0
- data/smoke/case.rb +16 -0
- data/smoke/case2.rb +17 -0
- data/smoke/class.rb +5 -0
- data/smoke/class_instance_var.rb +9 -0
- data/smoke/class_method.rb +25 -0
- data/smoke/class_method2.rb +21 -0
- data/smoke/class_method3.rb +27 -0
- data/smoke/constant1.rb +38 -0
- data/smoke/constant2.rb +33 -0
- data/smoke/constant3.rb +9 -0
- data/smoke/constant4.rb +11 -0
- data/smoke/context-sensitive1.rb +12 -0
- data/smoke/cvar.rb +28 -0
- data/smoke/cvar2.rb +17 -0
- data/smoke/demo.rb +80 -0
- data/smoke/demo1.rb +16 -0
- data/smoke/demo10.rb +20 -0
- data/smoke/demo11.rb +11 -0
- data/smoke/demo2.rb +14 -0
- data/smoke/demo3.rb +16 -0
- data/smoke/demo4.rb +27 -0
- data/smoke/demo5.rb +13 -0
- data/smoke/demo6.rb +21 -0
- data/smoke/demo7.rb +14 -0
- data/smoke/demo8.rb +18 -0
- data/smoke/demo9.rb +18 -0
- data/smoke/dummy-execution1.rb +14 -0
- data/smoke/dummy-execution2.rb +16 -0
- data/smoke/ensure1.rb +20 -0
- data/smoke/enumerator.rb +15 -0
- data/smoke/expandarray1.rb +22 -0
- data/smoke/expandarray2.rb +23 -0
- data/smoke/fib.rb +28 -0
- data/smoke/flow1.rb +16 -0
- data/smoke/flow2.rb +14 -0
- data/smoke/flow3.rb +14 -0
- data/smoke/flow4.rb +5 -0
- data/smoke/flow5.rb +19 -0
- data/smoke/flow6.rb +19 -0
- data/smoke/flow7.rb +26 -0
- data/smoke/for.rb +9 -0
- data/smoke/freeze.rb +11 -0
- data/smoke/function.rb +16 -0
- data/smoke/gvar.rb +13 -0
- data/smoke/hash-fetch.rb +27 -0
- data/smoke/hash1.rb +18 -0
- data/smoke/hash2.rb +12 -0
- data/smoke/hash3.rb +13 -0
- data/smoke/hash4.rb +10 -0
- data/smoke/hash5.rb +14 -0
- data/smoke/inheritance.rb +34 -0
- data/smoke/inheritance2.rb +29 -0
- data/smoke/initialize.rb +26 -0
- data/smoke/instance_eval.rb +18 -0
- data/smoke/int_times.rb +14 -0
- data/smoke/integer.rb +10 -0
- data/smoke/ivar.rb +29 -0
- data/smoke/ivar2.rb +30 -0
- data/smoke/kernel-class.rb +12 -0
- data/smoke/keyword1.rb +11 -0
- data/smoke/keyword2.rb +11 -0
- data/smoke/keyword3.rb +12 -0
- data/smoke/keyword4.rb +11 -0
- data/smoke/keyword5.rb +15 -0
- data/smoke/kwsplat1.rb +42 -0
- data/smoke/kwsplat2.rb +12 -0
- data/smoke/manual-rbs.rb +27 -0
- data/smoke/manual-rbs.rbs +3 -0
- data/smoke/manual-rbs2.rb +20 -0
- data/smoke/manual-rbs2.rbs +8 -0
- data/smoke/masgn1.rb +13 -0
- data/smoke/masgn2.rb +17 -0
- data/smoke/masgn3.rb +12 -0
- data/smoke/method_in_branch.rb +22 -0
- data/smoke/module1.rb +29 -0
- data/smoke/module2.rb +28 -0
- data/smoke/module3.rb +33 -0
- data/smoke/module4.rb +29 -0
- data/smoke/module_function1.rb +28 -0
- data/smoke/module_function2.rb +28 -0
- data/smoke/multiple-include.rb +14 -0
- data/smoke/multiple-superclass.rb +16 -0
- data/smoke/next1.rb +20 -0
- data/smoke/next2.rb +16 -0
- data/smoke/object-send1.rb +22 -0
- data/smoke/once.rb +12 -0
- data/smoke/optional1.rb +13 -0
- data/smoke/optional2.rb +15 -0
- data/smoke/parameterizedd-self.rb +18 -0
- data/smoke/pathname1.rb +13 -0
- data/smoke/pathname2.rb +13 -0
- data/smoke/printf.rb +20 -0
- data/smoke/proc.rb +19 -0
- data/smoke/proc2.rb +16 -0
- data/smoke/proc3.rb +14 -0
- data/smoke/proc4.rb +11 -0
- data/smoke/range.rb +13 -0
- data/smoke/redo1.rb +21 -0
- data/smoke/redo2.rb +22 -0
- data/smoke/req-keyword.rb +12 -0
- data/smoke/rescue1.rb +20 -0
- data/smoke/rescue2.rb +22 -0
- data/smoke/respond_to.rb +22 -0
- data/smoke/rest-farg.rb +10 -0
- data/smoke/rest1.rb +25 -0
- data/smoke/rest2.rb +30 -0
- data/smoke/rest3.rb +36 -0
- data/smoke/rest4.rb +18 -0
- data/smoke/rest5.rb +10 -0
- data/smoke/rest6.rb +11 -0
- data/smoke/retry1.rb +20 -0
- data/smoke/return.rb +13 -0
- data/smoke/reveal.rb +13 -0
- data/smoke/singleton_class.rb +8 -0
- data/smoke/singleton_method.rb +9 -0
- data/smoke/step.rb +17 -0
- data/smoke/string-split.rb +11 -0
- data/smoke/struct.rb +9 -0
- data/smoke/struct2.rb +24 -0
- data/smoke/super1.rb +50 -0
- data/smoke/super2.rb +16 -0
- data/smoke/super3.rb +19 -0
- data/smoke/svar1.rb +12 -0
- data/smoke/tap1.rb +17 -0
- data/smoke/toplevel.rb +12 -0
- data/smoke/two-map.rb +17 -0
- data/smoke/type_var.rb +10 -0
- data/smoke/typed_method.rb +15 -0
- data/smoke/union-recv.rb +29 -0
- data/smoke/variadic1.rb.notyet +5 -0
- data/smoke/wrong-extend.rb +25 -0
- data/smoke/wrong-include.rb +26 -0
- data/smoke/wrong-rbs.rb +15 -0
- data/smoke/wrong-rbs.rbs +7 -0
- data/testbed/ao.rb +297 -0
- data/testbed/diff-lcs-entrypoint.rb +4 -0
- data/testbed/goodcheck-Gemfile.lock +51 -0
- data/tools/coverage.rb +14 -0
- data/tools/setup-insns-def.rb +30 -0
- data/tools/stackprof-wrapper.rb +10 -0
- data/typeprof.gemspec +24 -0
- metadata +262 -0
@@ -0,0 +1,203 @@
|
|
1
|
+
module TypeProf
|
2
|
+
module Reporters
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def generate_analysis_trace(state, visited, backward_edge)
|
6
|
+
return nil if visited[state]
|
7
|
+
visited[state] = true
|
8
|
+
prev_states = backward_edges[state]
|
9
|
+
if prev_states
|
10
|
+
prev_states.each_key do |pstate|
|
11
|
+
trace = generate_analysis_trace(pstate, visited, backward_edge)
|
12
|
+
return [state] + trace if trace
|
13
|
+
end
|
14
|
+
nil
|
15
|
+
else
|
16
|
+
[]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def filter_backtrace(trace)
|
21
|
+
ntrace = [trace.first]
|
22
|
+
trace.each_cons(2) do |ep1, ep2|
|
23
|
+
ntrace << ep2 if ep1.ctx != ep2.ctx
|
24
|
+
end
|
25
|
+
ntrace
|
26
|
+
end
|
27
|
+
|
28
|
+
def show_error(errors, backward_edge, output)
|
29
|
+
return if errors.empty?
|
30
|
+
return unless Config.options[:show_errors]
|
31
|
+
|
32
|
+
output.puts "# Errors"
|
33
|
+
errors.each do |ep, msg|
|
34
|
+
if ENV["TYPE_PROFILER_DETAIL"]
|
35
|
+
backtrace = filter_backtrace(generate_analysis_trace(ep, {}, backward_edge))
|
36
|
+
else
|
37
|
+
backtrace = [ep]
|
38
|
+
end
|
39
|
+
loc, *backtrace = backtrace.map do |ep|
|
40
|
+
ep.source_location
|
41
|
+
end
|
42
|
+
output.puts "#{ loc }: #{ msg }"
|
43
|
+
backtrace.each do |loc|
|
44
|
+
output.puts " from #{ loc }"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
output.puts
|
48
|
+
end
|
49
|
+
|
50
|
+
def show_reveal_types(scratch, reveal_types, output)
|
51
|
+
return if reveal_types.empty?
|
52
|
+
|
53
|
+
output.puts "# Revealed types"
|
54
|
+
reveal_types.each do |source_location, ty|
|
55
|
+
output.puts "# #{ source_location } #=> #{ ty.screen_name(scratch) }"
|
56
|
+
end
|
57
|
+
output.puts
|
58
|
+
end
|
59
|
+
|
60
|
+
def show_gvars(scratch, gvar_write, output)
|
61
|
+
# A signature for global variables is not supported in RBS
|
62
|
+
return if gvar_write.empty?
|
63
|
+
|
64
|
+
output.puts "# Global variables"
|
65
|
+
gvar_write.each do |gvar_name, ty|
|
66
|
+
output.puts "# #{ gvar_name } : #{ ty.screen_name(scratch) }"
|
67
|
+
end
|
68
|
+
output.puts
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class RubySignatureExporter
|
73
|
+
def initialize(
|
74
|
+
scratch,
|
75
|
+
class_defs, iseq_method_to_ctxs, sig_fargs, sig_ret, yields
|
76
|
+
)
|
77
|
+
@scratch = scratch
|
78
|
+
@class_defs = class_defs
|
79
|
+
@iseq_method_to_ctxs = iseq_method_to_ctxs
|
80
|
+
@sig_fargs = sig_fargs
|
81
|
+
@sig_ret = sig_ret
|
82
|
+
@yields = yields
|
83
|
+
end
|
84
|
+
|
85
|
+
def show(stat_eps, output)
|
86
|
+
output.puts "# Classes" # and Modules
|
87
|
+
|
88
|
+
stat_classes = {}
|
89
|
+
stat_methods = {}
|
90
|
+
first = true
|
91
|
+
@class_defs.each_value do |class_def|
|
92
|
+
included_mods = class_def.modules[false].filter_map do |visible, mod_def|
|
93
|
+
mod_def.name if visible
|
94
|
+
end
|
95
|
+
|
96
|
+
explicit_methods = {}
|
97
|
+
iseq_methods = {}
|
98
|
+
attr_methods = {}
|
99
|
+
class_def.methods.each do |(singleton, mid), mdefs|
|
100
|
+
mdefs.each do |mdef|
|
101
|
+
case mdef
|
102
|
+
when ISeqMethodDef
|
103
|
+
ctxs = @iseq_method_to_ctxs[mdef]
|
104
|
+
next unless ctxs
|
105
|
+
|
106
|
+
ctxs.each do |ctx|
|
107
|
+
next if mid != ctx.mid
|
108
|
+
|
109
|
+
method_name = ctx.mid
|
110
|
+
method_name = "self.#{ method_name }" if singleton
|
111
|
+
|
112
|
+
fargs = @sig_fargs[ctx]
|
113
|
+
ret_tys = @sig_ret[ctx]
|
114
|
+
|
115
|
+
iseq_methods[method_name] ||= []
|
116
|
+
iseq_methods[method_name] << @scratch.show_signature(fargs, @yields[ctx], ret_tys)
|
117
|
+
end
|
118
|
+
when AttrMethodDef
|
119
|
+
mid = mid.to_s[0..-2].to_sym if mid.to_s.end_with?("=")
|
120
|
+
method_name = mid
|
121
|
+
method_name = "self.#{ mid }" if singleton
|
122
|
+
method_name = [method_name, :"@#{ mid }" != mdef.ivar]
|
123
|
+
if attr_methods[method_name]
|
124
|
+
if attr_methods[method_name][0] != mdef.kind
|
125
|
+
attr_methods[method_name][0] = :accessor
|
126
|
+
end
|
127
|
+
else
|
128
|
+
ty = class_def.ivars.write[[singleton, mdef.ivar]] || Type.any
|
129
|
+
attr_methods[method_name] = [mdef.kind, ty.screen_name(@scratch)]
|
130
|
+
end
|
131
|
+
when TypedMethodDef
|
132
|
+
if mdef.rbs_source
|
133
|
+
method_name, sigs = mdef.rbs_source
|
134
|
+
explicit_methods[method_name] = sigs
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
ivars = class_def.ivars.write.map do |(singleton, var), ty|
|
141
|
+
next unless var.to_s.start_with?("@")
|
142
|
+
var = "self.#{ var }" if singleton
|
143
|
+
next if attr_methods[[singleton ? "self.#{ var.to_s[1..] }" : var.to_s[1..].to_sym, false]]
|
144
|
+
[var, ty.screen_name(@scratch)]
|
145
|
+
end.compact
|
146
|
+
|
147
|
+
cvars = class_def.cvars.write.map do |var, ty|
|
148
|
+
[var, ty.screen_name(@scratch)]
|
149
|
+
end
|
150
|
+
|
151
|
+
next if included_mods.empty? && ivars.empty? && cvars.empty? && iseq_methods.empty? && attr_methods.empty?
|
152
|
+
|
153
|
+
output.puts unless first
|
154
|
+
first = false
|
155
|
+
|
156
|
+
if class_def.superclass
|
157
|
+
object = @class_defs[class_def.superclass].klass_obj == Type::Builtin[:obj]
|
158
|
+
superclass = object ? "" : " < #{ @class_defs[class_def.superclass].name }"
|
159
|
+
end
|
160
|
+
|
161
|
+
output.puts "#{ class_def.kind } #{ class_def.name }#{ superclass }"
|
162
|
+
included_mods.sort.each do |ty|
|
163
|
+
output.puts " include #{ ty }"
|
164
|
+
end
|
165
|
+
ivars.each do |var, ty|
|
166
|
+
output.puts " #{ var } : #{ ty }" unless var.start_with?("_")
|
167
|
+
end
|
168
|
+
cvars.each do |var, ty|
|
169
|
+
output.puts " #{ var } : #{ ty }"
|
170
|
+
end
|
171
|
+
attr_methods.each do |(method_name, hidden), (kind, ty)|
|
172
|
+
output.puts " attr_#{ kind } #{ method_name }#{ hidden ? "()" : "" } : #{ ty }"
|
173
|
+
end
|
174
|
+
explicit_methods.each do |method_name, sigs|
|
175
|
+
sigs = sigs.sort.join("\n" + "#" + " " * (method_name.size + 6) + "| ")
|
176
|
+
output.puts "# def #{ method_name } : #{ sigs }"
|
177
|
+
end
|
178
|
+
iseq_methods.each do |method_name, sigs|
|
179
|
+
sigs = sigs.sort.join("\n" + " " * (method_name.size + 7) + "| ")
|
180
|
+
output.puts " def #{ method_name } : #{ sigs }"
|
181
|
+
end
|
182
|
+
output.puts "end"
|
183
|
+
end
|
184
|
+
|
185
|
+
if ENV["TP_STAT"]
|
186
|
+
output.puts "statistics:"
|
187
|
+
output.puts " %d execution points" % stat_eps.size
|
188
|
+
output.puts " %d classes" % stat_classes.size
|
189
|
+
output.puts " %d methods (in total)" % stat_methods.size
|
190
|
+
end
|
191
|
+
if ENV["TP_COVERAGE"]
|
192
|
+
coverage = {}
|
193
|
+
stat_eps.each do |ep|
|
194
|
+
path = ep.ctx.iseq.path
|
195
|
+
lineno = ep.ctx.iseq.linenos[ep.pc] - 1
|
196
|
+
(coverage[path] ||= [])[lineno] ||= 0
|
197
|
+
(coverage[path] ||= [])[lineno] += 1
|
198
|
+
end
|
199
|
+
File.binwrite("coverage.dump", Marshal.dump(coverage))
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,546 @@
|
|
1
|
+
require "rbs"
|
2
|
+
|
3
|
+
module TypeProf
|
4
|
+
class RBSReader
|
5
|
+
def initialize
|
6
|
+
@env, @builtin_env_dump = RBSReader.builtin_env
|
7
|
+
end
|
8
|
+
|
9
|
+
@builtin_env = nil
|
10
|
+
def self.builtin_env
|
11
|
+
return @builtin_env.dup, @builtin_env_dump if @builtin_env
|
12
|
+
|
13
|
+
loader = RBS::EnvironmentLoader.new
|
14
|
+
env = RBS::Environment.new
|
15
|
+
decls = loader.load(env: env)
|
16
|
+
@builtin_env = env
|
17
|
+
@builtin_env_dump = RBS2JSON.new(env, decls).dump
|
18
|
+
return env.dup, @builtin_env_dump
|
19
|
+
end
|
20
|
+
|
21
|
+
def load_builtin
|
22
|
+
@builtin_env_dump
|
23
|
+
end
|
24
|
+
|
25
|
+
def load_library(lib)
|
26
|
+
loader = RBS::EnvironmentLoader.new
|
27
|
+
loader.no_builtin!
|
28
|
+
loader.add(library: lib)
|
29
|
+
new_decls = loader.load(env: @env)
|
30
|
+
RBS2JSON.new(@env, new_decls).dump
|
31
|
+
end
|
32
|
+
|
33
|
+
def load_path(path)
|
34
|
+
loader = RBS::EnvironmentLoader.new
|
35
|
+
loader.no_builtin!
|
36
|
+
loader.add(path: path)
|
37
|
+
new_decls = loader.load(env: @env)
|
38
|
+
RBS2JSON.new(@env, new_decls).dump
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class RBS2JSON
|
43
|
+
def initialize(env, new_decls)
|
44
|
+
@all_env = env.resolve_type_names
|
45
|
+
|
46
|
+
resolver = RBS::TypeNameResolver.from_env(env)
|
47
|
+
@current_env = RBS::Environment.new()
|
48
|
+
|
49
|
+
new_decls.each do |decl,|
|
50
|
+
@current_env << env.resolve_declaration(resolver, decl, outer: [], prefix: RBS::Namespace.root)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def dump
|
55
|
+
[import_rbs_classes, import_rbs_constants]
|
56
|
+
end
|
57
|
+
|
58
|
+
# constant_name = [Symbol]
|
59
|
+
#
|
60
|
+
# { constant_name => type }
|
61
|
+
def import_rbs_constants
|
62
|
+
constants = {}
|
63
|
+
@current_env.constant_decls.each do |name, decl|
|
64
|
+
#constants[name] = decl
|
65
|
+
klass = name.namespace.path + [name.name]
|
66
|
+
constants[klass] = convert_type(decl.decl.type)
|
67
|
+
end
|
68
|
+
constants
|
69
|
+
end
|
70
|
+
|
71
|
+
# class_name = [Symbol]
|
72
|
+
# method_name = [singleton: true|false, Symbol}
|
73
|
+
# method_def = [...]
|
74
|
+
#
|
75
|
+
# { class_name =>
|
76
|
+
# [ super_class: class_name,
|
77
|
+
# included_modules: [class_name],
|
78
|
+
# methods: { method_name => [method_def] },
|
79
|
+
# ]
|
80
|
+
# }
|
81
|
+
def import_rbs_classes
|
82
|
+
class2super = {}
|
83
|
+
# XXX: @env.each_global {|a| p a }
|
84
|
+
@current_env.class_decls.each do |name, decl|
|
85
|
+
decl.decls.each do |decl|
|
86
|
+
decl = decl.decl
|
87
|
+
if decl.is_a?(RBS::AST::Declarations::Class) && name != RBS::Factory.new.type_name("::Object")
|
88
|
+
#next unless decl.super_class
|
89
|
+
class2super[name] ||= decl.super_class&.name || RBS::BuiltinNames::Object.name
|
90
|
+
else
|
91
|
+
class2super[name] ||= nil
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
classes = []
|
97
|
+
|
98
|
+
# topological sort
|
99
|
+
queue = class2super.keys.map {|name| [:visit, name] }
|
100
|
+
visited = {}
|
101
|
+
until queue.empty?
|
102
|
+
#p queue.map {|ev, name| [ev, name.to_s] }
|
103
|
+
event, name = queue.pop
|
104
|
+
case event
|
105
|
+
when :visit
|
106
|
+
if !visited[name]
|
107
|
+
visited[name] = true
|
108
|
+
queue << [:new, name]
|
109
|
+
decl = @all_env.class_decls[name]
|
110
|
+
decl.decls.each do |decl|
|
111
|
+
decl = decl.decl
|
112
|
+
next if decl.is_a?(RBS::AST::Declarations::Module)
|
113
|
+
until RBS::BuiltinNames::Object.name == decl.name
|
114
|
+
super_class = decl.super_class
|
115
|
+
break unless super_class
|
116
|
+
decls = @all_env.class_decls[super_class.name].decls
|
117
|
+
raise if decls.size >= 2 # no need to check
|
118
|
+
decl = decls.first.decl
|
119
|
+
queue << [:visit, decl.name]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
if !name.namespace.empty?
|
123
|
+
queue << [:visit, name.namespace.to_type_name]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
when :new
|
127
|
+
super_class_name = class2super[name]
|
128
|
+
klass = name.namespace.path + [name.name]
|
129
|
+
if super_class_name
|
130
|
+
superclass = super_class_name.namespace.path + [super_class_name.name]
|
131
|
+
else
|
132
|
+
superclass = nil
|
133
|
+
end
|
134
|
+
classes << [name, klass, superclass]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
result = {}
|
139
|
+
classes.each do |type_name, klass, superclass|
|
140
|
+
next unless @current_env.class_decls[type_name]
|
141
|
+
|
142
|
+
included_modules = []
|
143
|
+
methods = {}
|
144
|
+
rbs_sources = {}
|
145
|
+
type_params = nil
|
146
|
+
|
147
|
+
@current_env.class_decls[type_name].decls.each do |decl|
|
148
|
+
decl = decl.decl
|
149
|
+
raise NotImplementedError if decl.is_a?(RBS::AST::Declarations::Interface)
|
150
|
+
type_params2 = decl.type_params.params.map {|param| [param.name, param.variance] }
|
151
|
+
if type_params
|
152
|
+
raise if type_params != type_params2
|
153
|
+
else
|
154
|
+
type_params = type_params2
|
155
|
+
end
|
156
|
+
|
157
|
+
decl.members.each do |member|
|
158
|
+
case member
|
159
|
+
when RBS::AST::Members::MethodDefinition
|
160
|
+
name = member.name
|
161
|
+
|
162
|
+
# ad-hoc filter
|
163
|
+
if member.instance?
|
164
|
+
case type_name.name
|
165
|
+
when :Object
|
166
|
+
next if name == :class
|
167
|
+
next if name == :send
|
168
|
+
next if name == :is_a?
|
169
|
+
next if name == :respond_to?
|
170
|
+
when :Array
|
171
|
+
next if name == :[]
|
172
|
+
next if name == :[]=
|
173
|
+
next if name == :pop
|
174
|
+
when :Enumerable
|
175
|
+
when :Enumerator
|
176
|
+
when :Hash
|
177
|
+
next if name == :[]
|
178
|
+
next if name == :[]=
|
179
|
+
next if name == :to_proc
|
180
|
+
#next unless [:empty?, :size].include?(name)
|
181
|
+
when :Struct
|
182
|
+
next if name == :initialize
|
183
|
+
when :Module
|
184
|
+
next if name == :include
|
185
|
+
next if name == :module_function
|
186
|
+
when :Proc
|
187
|
+
next if name == :call || name == :[]
|
188
|
+
when :Kernel
|
189
|
+
next if name == :Array
|
190
|
+
end
|
191
|
+
end
|
192
|
+
if member.singleton?
|
193
|
+
case type_name.name
|
194
|
+
when :Array
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
method_types = member.types.map do |method_type|
|
199
|
+
case method_type
|
200
|
+
when RBS::MethodType
|
201
|
+
method_type
|
202
|
+
when :super
|
203
|
+
raise NotImplementedError
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
method_def = translate_typed_method_def(method_types)
|
208
|
+
rbs_source = [(member.kind == :singleton ? "self." : "") + member.name.to_s, member.types.map {|type| type.location.source }]
|
209
|
+
if member.instance?
|
210
|
+
methods[[false, name]] = method_def
|
211
|
+
rbs_sources[[false, name]] = rbs_source
|
212
|
+
end
|
213
|
+
if member.singleton?
|
214
|
+
methods[[true, name]] = method_def
|
215
|
+
rbs_sources[[true, name]] = rbs_source
|
216
|
+
end
|
217
|
+
#when RBS::AST::Members::AttrReader, RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrWriter
|
218
|
+
#raise NotImplementedError
|
219
|
+
when RBS::AST::Members::Alias
|
220
|
+
if member.instance?
|
221
|
+
method_def = methods[[false, member.old_name]]
|
222
|
+
methods[[false, member.new_name]] = method_def if method_def
|
223
|
+
end
|
224
|
+
if member.singleton?
|
225
|
+
method_def = methods[[true, member.old_name]]
|
226
|
+
methods[[true, member.new_name]] = method_def if method_def
|
227
|
+
end
|
228
|
+
when RBS::AST::Members::Include
|
229
|
+
name = member.name
|
230
|
+
mod = name.namespace.path + [name.name]
|
231
|
+
included_modules << mod
|
232
|
+
when RBS::AST::Members::InstanceVariable
|
233
|
+
when RBS::AST::Members::ClassVariable
|
234
|
+
when RBS::AST::Members::Public, RBS::AST::Members::Private
|
235
|
+
when RBS::AST::Declarations::Constant
|
236
|
+
when RBS::AST::Declarations::Alias
|
237
|
+
else
|
238
|
+
warn "Importing #{ member.class.name } is not supported yet"
|
239
|
+
#p member
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
result[klass] = [type_params, superclass, included_modules, methods, rbs_sources]
|
245
|
+
end.compact
|
246
|
+
|
247
|
+
result
|
248
|
+
end
|
249
|
+
|
250
|
+
def translate_typed_method_def(rs_method_types)
|
251
|
+
rs_method_types.map do |type|
|
252
|
+
if type.block
|
253
|
+
blk = translate_typed_block(type.block)
|
254
|
+
else
|
255
|
+
blk = nil
|
256
|
+
end
|
257
|
+
type_params = type.type_params
|
258
|
+
|
259
|
+
begin
|
260
|
+
lead_tys = type.type.required_positionals.map do |type|
|
261
|
+
convert_type(type.type)
|
262
|
+
end
|
263
|
+
opt_tys = type.type.optional_positionals.map do |type|
|
264
|
+
convert_type(type.type)
|
265
|
+
end
|
266
|
+
rest_ty = type.type.rest_positionals
|
267
|
+
rest_ty = convert_type(rest_ty.type) if rest_ty
|
268
|
+
opt_kw_tys = type.type.optional_keywords.to_h do |key, type|
|
269
|
+
[key, convert_type(type.type)]
|
270
|
+
end
|
271
|
+
req_kw_tys = type.type.required_keywords.to_h do |key, type|
|
272
|
+
[key, convert_type(type.type)]
|
273
|
+
end
|
274
|
+
rest_kw_ty = type.type.rest_keywords
|
275
|
+
raise NotImplementedError if rest_kw_ty
|
276
|
+
|
277
|
+
ret_ty = convert_type(type.type.return_type)
|
278
|
+
[type_params, lead_tys, opt_tys, rest_ty, req_kw_tys, opt_kw_tys, rest_kw_ty, blk, ret_ty]
|
279
|
+
rescue UnsupportedType
|
280
|
+
nil
|
281
|
+
end
|
282
|
+
end.compact
|
283
|
+
end
|
284
|
+
|
285
|
+
def translate_typed_block(rs_block)
|
286
|
+
type = rs_block.type
|
287
|
+
raise NotImplementedError unless type.optional_keywords.empty?
|
288
|
+
raise NotImplementedError unless type.required_keywords.empty?
|
289
|
+
raise NotImplementedError unless type.optional_positionals.empty?
|
290
|
+
raise NotImplementedError if type.rest_keywords
|
291
|
+
lead_tys = type.required_positionals.map do |type|
|
292
|
+
convert_type(type.type)
|
293
|
+
end
|
294
|
+
ret_ty = convert_type(type.return_type)
|
295
|
+
[lead_tys, ret_ty]
|
296
|
+
end
|
297
|
+
|
298
|
+
class UnsupportedType < StandardError
|
299
|
+
end
|
300
|
+
|
301
|
+
def convert_type(ty)
|
302
|
+
case ty
|
303
|
+
when RBS::Types::ClassSingleton
|
304
|
+
klass = ty.name.namespace.path + [ty.name.name]
|
305
|
+
[:class, klass]
|
306
|
+
when RBS::Types::ClassInstance
|
307
|
+
klass = ty.name.namespace.path + [ty.name.name]
|
308
|
+
case klass
|
309
|
+
when [:Array]
|
310
|
+
raise if ty.args.size != 1
|
311
|
+
[:array, :Array, [], convert_type(ty.args.first)]
|
312
|
+
when [:Hash]
|
313
|
+
raise if ty.args.size != 2
|
314
|
+
key, val = ty.args
|
315
|
+
[:hash, :Hash, [convert_type(key), convert_type(val)]]
|
316
|
+
when [:Enumerator]
|
317
|
+
raise if ty.args.size != 2
|
318
|
+
[:array, :Enumerator, [], convert_type(ty.args.first)]
|
319
|
+
else
|
320
|
+
[:instance, klass]
|
321
|
+
end
|
322
|
+
when RBS::Types::Bases::Bool
|
323
|
+
[:bool]
|
324
|
+
when RBS::Types::Bases::Any
|
325
|
+
[:any]
|
326
|
+
when RBS::Types::Bases::Void
|
327
|
+
[:any]
|
328
|
+
when RBS::Types::Bases::Self
|
329
|
+
[:self]
|
330
|
+
when RBS::Types::Bases::Nil
|
331
|
+
[:nil]
|
332
|
+
when RBS::Types::Bases::Bottom
|
333
|
+
[:union, []]
|
334
|
+
when RBS::Types::Variable
|
335
|
+
[:var, ty.name]
|
336
|
+
when RBS::Types::Tuple
|
337
|
+
tys = ty.types.map {|ty2| convert_type(ty2) }
|
338
|
+
[:array, :Array, tys, [:union, []]]
|
339
|
+
when RBS::Types::Literal
|
340
|
+
case ty.literal
|
341
|
+
when Integer
|
342
|
+
[:int]
|
343
|
+
when String
|
344
|
+
[:str]
|
345
|
+
when true
|
346
|
+
[:true]
|
347
|
+
when false
|
348
|
+
[:false]
|
349
|
+
when Symbol
|
350
|
+
[:sym, ty.literal]
|
351
|
+
else
|
352
|
+
p ty.literal
|
353
|
+
raise NotImplementedError
|
354
|
+
end
|
355
|
+
when RBS::Types::Alias
|
356
|
+
alias_decl = @all_env.alias_decls[ty.name]
|
357
|
+
alias_decl ? convert_type(alias_decl.decl.type) : [:any]
|
358
|
+
when RBS::Types::Union
|
359
|
+
[:union, ty.types.map {|ty2| begin convert_type(ty2); rescue UnsupportedType; end }.compact]
|
360
|
+
when RBS::Types::Optional
|
361
|
+
[:optional, convert_type(ty.type)]
|
362
|
+
when RBS::Types::Record
|
363
|
+
[:any]
|
364
|
+
when RBS::Types::Interface
|
365
|
+
raise UnsupportedType if ty.to_s == "::_ToStr" # XXX
|
366
|
+
raise UnsupportedType if ty.to_s == "::_ToInt" # XXX
|
367
|
+
if ty.to_s == "::_ToAry[U]" # XXX
|
368
|
+
return [:array, :Array, [], [:var, :U]]
|
369
|
+
end
|
370
|
+
[:any]
|
371
|
+
else
|
372
|
+
pp ty
|
373
|
+
raise NotImplementedError
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
module RubySignatureImporter
|
379
|
+
module_function
|
380
|
+
|
381
|
+
def path_to_klass(scratch, path)
|
382
|
+
klass = Type::Builtin[:obj]
|
383
|
+
path.each do |name|
|
384
|
+
klass = scratch.get_constant(klass, name)
|
385
|
+
raise if klass == Type.any
|
386
|
+
end
|
387
|
+
klass
|
388
|
+
end
|
389
|
+
|
390
|
+
CACHE = {}
|
391
|
+
|
392
|
+
def import_builtin(scratch)
|
393
|
+
import_ruby_signature(scratch, scratch.rbs_reader.load_builtin)
|
394
|
+
end
|
395
|
+
|
396
|
+
def import_library(scratch, feature)
|
397
|
+
# need cache?
|
398
|
+
import_ruby_signature(scratch, scratch.rbs_reader.load_library(feature))
|
399
|
+
rescue RBS::EnvironmentLoader::UnknownLibraryNameError
|
400
|
+
false
|
401
|
+
end
|
402
|
+
|
403
|
+
def import_rbs_file(scratch, rbs_path)
|
404
|
+
import_ruby_signature(scratch, scratch.rbs_reader.load_path(Pathname(rbs_path)), true)
|
405
|
+
end
|
406
|
+
|
407
|
+
def import_ruby_signature(scratch, dump, explicit = false)
|
408
|
+
rbs_classes, rbs_constants = dump
|
409
|
+
classes = []
|
410
|
+
rbs_classes.each do |classpath, (type_params, superclass, included_modules, methods, rbs_sources)|
|
411
|
+
if classpath == [:Object]
|
412
|
+
klass = Type::Builtin[:obj]
|
413
|
+
else
|
414
|
+
name = classpath.last
|
415
|
+
base_klass = path_to_klass(scratch, classpath[0..-2])
|
416
|
+
superclass = path_to_klass(scratch, superclass) if superclass
|
417
|
+
klass = scratch.get_constant(base_klass, name)
|
418
|
+
if klass.is_a?(Type::Any)
|
419
|
+
klass = scratch.new_class(base_klass, name, type_params, superclass)
|
420
|
+
case classpath
|
421
|
+
when [:NilClass] then Type::Builtin[:nil] = klass
|
422
|
+
when [:Integer] then Type::Builtin[:int] = klass
|
423
|
+
when [:String] then Type::Builtin[:str] = klass
|
424
|
+
when [:Symbol] then Type::Builtin[:sym] = klass
|
425
|
+
when [:Array] then Type::Builtin[:ary] = klass
|
426
|
+
when [:Hash] then Type::Builtin[:hash] = klass
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
classes << [klass, included_modules, methods, rbs_sources]
|
431
|
+
end
|
432
|
+
|
433
|
+
classes.each do |klass, included_modules, methods, rbs_sources|
|
434
|
+
included_modules.each do |mod|
|
435
|
+
mod = path_to_klass(scratch, mod)
|
436
|
+
scratch.include_module(klass, mod, false)
|
437
|
+
end
|
438
|
+
methods.each do |(singleton, method_name), mdef|
|
439
|
+
rbs_source = nil
|
440
|
+
rbs_source = rbs_sources[[singleton, method_name]] if explicit
|
441
|
+
mdef = translate_typed_method_def(scratch, method_name, mdef, rbs_source)
|
442
|
+
scratch.add_method(klass, method_name, singleton, mdef)
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
rbs_constants.each do |classpath, value|
|
447
|
+
base_klass = path_to_klass(scratch, classpath[0..-2])
|
448
|
+
value = convert_type(scratch, value)
|
449
|
+
scratch.add_constant(base_klass, classpath[-1], value)
|
450
|
+
end
|
451
|
+
|
452
|
+
true
|
453
|
+
end
|
454
|
+
|
455
|
+
def translate_typed_method_def(scratch, method_name, mdef, rbs_source)
|
456
|
+
sig_rets = mdef.map do |type_params, lead_tys, opt_tys, rest_ty, req_kw_tys, opt_kw_tys, rest_kw_ty, blk, ret_ty|
|
457
|
+
if blk
|
458
|
+
blk = translate_typed_block(scratch, blk)
|
459
|
+
else
|
460
|
+
blk = Type::Instance.new(scratch.get_constant(Type::Builtin[:obj], :NilClass))
|
461
|
+
end
|
462
|
+
|
463
|
+
begin
|
464
|
+
lead_tys = lead_tys.map {|ty| convert_type(scratch, ty) }
|
465
|
+
opt_tys = opt_tys.map {|ty| convert_type(scratch, ty) }
|
466
|
+
rest_ty = convert_type(scratch, rest_ty) if rest_ty
|
467
|
+
kw_tys = []
|
468
|
+
req_kw_tys.each {|key, ty| kw_tys << [true, key, convert_type(scratch, ty)] }
|
469
|
+
opt_kw_tys.each {|key, ty| kw_tys << [false, key, convert_type(scratch, ty)] }
|
470
|
+
kw_rest_ty = convert_type(scratch, rest_kw_ty) if rest_kw_ty
|
471
|
+
fargs = FormalArguments.new(lead_tys, opt_tys, rest_ty, [], kw_tys, kw_rest_ty, blk)
|
472
|
+
ret_ty = convert_type(scratch, ret_ty)
|
473
|
+
[fargs, ret_ty]
|
474
|
+
rescue UnsupportedType
|
475
|
+
nil
|
476
|
+
end
|
477
|
+
end.compact
|
478
|
+
|
479
|
+
TypedMethodDef.new(sig_rets, rbs_source)
|
480
|
+
end
|
481
|
+
|
482
|
+
def translate_typed_block(scratch, blk)
|
483
|
+
lead_tys, ret_ty = blk
|
484
|
+
lead_tys = lead_tys.map {|ty| convert_type(scratch, ty) }
|
485
|
+
ret_ty = convert_type(scratch, ret_ty)
|
486
|
+
Type::TypedProc.new(lead_tys, ret_ty, Type::Builtin[:proc])
|
487
|
+
end
|
488
|
+
|
489
|
+
class UnsupportedType < StandardError
|
490
|
+
end
|
491
|
+
|
492
|
+
def convert_type(scratch, ty)
|
493
|
+
case ty.first
|
494
|
+
when :class
|
495
|
+
path_to_klass(scratch, ty[1])
|
496
|
+
when :instance
|
497
|
+
begin
|
498
|
+
Type::Instance.new(path_to_klass(scratch, ty[1]))
|
499
|
+
rescue
|
500
|
+
raise UnsupportedType
|
501
|
+
end
|
502
|
+
when :bool
|
503
|
+
Type.bool
|
504
|
+
when :any
|
505
|
+
Type.any
|
506
|
+
when :self
|
507
|
+
Type::Var.new(:self)
|
508
|
+
when :int
|
509
|
+
Type::Instance.new(Type::Builtin[:int])
|
510
|
+
when :str
|
511
|
+
Type::Instance.new(Type::Builtin[:str])
|
512
|
+
when :sym
|
513
|
+
Type::Symbol.new(ty.last, Type::Instance.new(Type::Builtin[:sym]))
|
514
|
+
when :nil
|
515
|
+
Type.nil
|
516
|
+
when :true
|
517
|
+
Type::Instance.new(Type::Builtin[:true])
|
518
|
+
when :false
|
519
|
+
Type::Instance.new(Type::Builtin[:false])
|
520
|
+
when :array
|
521
|
+
_, klass, lead_tys, rest_ty = ty
|
522
|
+
lead_tys = lead_tys.map {|ty| convert_type(scratch, ty) }
|
523
|
+
rest_ty = convert_type(scratch, rest_ty)
|
524
|
+
base_type = Type::Instance.new(scratch.get_constant(Type::Builtin[:obj], klass))
|
525
|
+
Type::Array.new(Type::Array::Elements.new(lead_tys, rest_ty), base_type)
|
526
|
+
when :hash
|
527
|
+
_, _klass, (k, v) = ty
|
528
|
+
Type.gen_hash do |h|
|
529
|
+
k_ty = convert_type(scratch, k)
|
530
|
+
v_ty = convert_type(scratch, v)
|
531
|
+
h[k_ty] = v_ty
|
532
|
+
end
|
533
|
+
when :union
|
534
|
+
tys = ty[1].reject {|ty2| ty2[1] == [:BigDecimal] } # XXX
|
535
|
+
Type::Union.new(Utils::Set[*tys.map {|ty2| convert_type(scratch, ty2) }], nil) # Array support
|
536
|
+
when :optional
|
537
|
+
Type.optional(convert_type(scratch, ty[1]))
|
538
|
+
when :var
|
539
|
+
Type::Var.new(ty[1]) # Currently, only for Array#* : (int | string) -> Array[Elem]
|
540
|
+
else
|
541
|
+
pp ty
|
542
|
+
raise NotImplementedError
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
546
|
+
end
|