typeprof 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +26 -0
  3. data/.gitignore +7 -0
  4. data/.gitmodules +6 -0
  5. data/Gemfile +12 -0
  6. data/Gemfile.lock +41 -0
  7. data/README.md +53 -0
  8. data/Rakefile +10 -0
  9. data/doc/doc.ja.md +415 -0
  10. data/doc/doc.md +429 -0
  11. data/doc/ppl2019.pdf +0 -0
  12. data/exe/typeprof +5 -0
  13. data/lib/typeprof.rb +13 -0
  14. data/lib/typeprof/analyzer.rb +1911 -0
  15. data/lib/typeprof/builtin.rb +554 -0
  16. data/lib/typeprof/cli.rb +110 -0
  17. data/lib/typeprof/container-type.rb +626 -0
  18. data/lib/typeprof/export.rb +203 -0
  19. data/lib/typeprof/import.rb +546 -0
  20. data/lib/typeprof/insns-def.rb +61 -0
  21. data/lib/typeprof/iseq.rb +387 -0
  22. data/lib/typeprof/method.rb +267 -0
  23. data/lib/typeprof/type.rb +1092 -0
  24. data/lib/typeprof/utils.rb +209 -0
  25. data/run.sh +3 -0
  26. data/smoke/alias.rb +30 -0
  27. data/smoke/alias2.rb +19 -0
  28. data/smoke/any-cbase.rb +5 -0
  29. data/smoke/any1.rb +15 -0
  30. data/smoke/any2.rb +17 -0
  31. data/smoke/arguments.rb +16 -0
  32. data/smoke/array-each.rb +14 -0
  33. data/smoke/array-each2.rb +15 -0
  34. data/smoke/array-each3.rb +15 -0
  35. data/smoke/array-ltlt.rb +13 -0
  36. data/smoke/array-ltlt2.rb +16 -0
  37. data/smoke/array-map.rb +11 -0
  38. data/smoke/array-map2.rb +10 -0
  39. data/smoke/array-map3.rb +22 -0
  40. data/smoke/array-mul.rb +17 -0
  41. data/smoke/array-plus1.rb +10 -0
  42. data/smoke/array-plus2.rb +15 -0
  43. data/smoke/array-pop.rb +11 -0
  44. data/smoke/array-replace.rb +12 -0
  45. data/smoke/array-s-aref.rb +11 -0
  46. data/smoke/array1.rb +26 -0
  47. data/smoke/array10.rb +14 -0
  48. data/smoke/array11.rb +13 -0
  49. data/smoke/array12.rb +24 -0
  50. data/smoke/array13.rb +30 -0
  51. data/smoke/array14.rb +13 -0
  52. data/smoke/array2.rb +27 -0
  53. data/smoke/array3.rb +25 -0
  54. data/smoke/array4.rb +14 -0
  55. data/smoke/array5.rb +13 -0
  56. data/smoke/array6.rb +14 -0
  57. data/smoke/array7.rb +13 -0
  58. data/smoke/array8.rb +13 -0
  59. data/smoke/array9.rb +12 -0
  60. data/smoke/attr.rb +28 -0
  61. data/smoke/backtrace.rb +32 -0
  62. data/smoke/block1.rb +22 -0
  63. data/smoke/block10.rb +14 -0
  64. data/smoke/block11.rb +39 -0
  65. data/smoke/block12.rb +22 -0
  66. data/smoke/block2.rb +14 -0
  67. data/smoke/block3.rb +38 -0
  68. data/smoke/block4.rb +18 -0
  69. data/smoke/block5.rb +18 -0
  70. data/smoke/block6.rb +20 -0
  71. data/smoke/block7.rb +20 -0
  72. data/smoke/block8.rb +27 -0
  73. data/smoke/block9.rb +12 -0
  74. data/smoke/blown.rb +12 -0
  75. data/smoke/break1.rb +18 -0
  76. data/smoke/break2.rb +15 -0
  77. data/smoke/case.rb +16 -0
  78. data/smoke/case2.rb +17 -0
  79. data/smoke/class.rb +5 -0
  80. data/smoke/class_instance_var.rb +9 -0
  81. data/smoke/class_method.rb +25 -0
  82. data/smoke/class_method2.rb +21 -0
  83. data/smoke/class_method3.rb +27 -0
  84. data/smoke/constant1.rb +38 -0
  85. data/smoke/constant2.rb +33 -0
  86. data/smoke/constant3.rb +9 -0
  87. data/smoke/constant4.rb +11 -0
  88. data/smoke/context-sensitive1.rb +12 -0
  89. data/smoke/cvar.rb +28 -0
  90. data/smoke/cvar2.rb +17 -0
  91. data/smoke/demo.rb +80 -0
  92. data/smoke/demo1.rb +16 -0
  93. data/smoke/demo10.rb +20 -0
  94. data/smoke/demo11.rb +11 -0
  95. data/smoke/demo2.rb +14 -0
  96. data/smoke/demo3.rb +16 -0
  97. data/smoke/demo4.rb +27 -0
  98. data/smoke/demo5.rb +13 -0
  99. data/smoke/demo6.rb +21 -0
  100. data/smoke/demo7.rb +14 -0
  101. data/smoke/demo8.rb +18 -0
  102. data/smoke/demo9.rb +18 -0
  103. data/smoke/dummy-execution1.rb +14 -0
  104. data/smoke/dummy-execution2.rb +16 -0
  105. data/smoke/ensure1.rb +20 -0
  106. data/smoke/enumerator.rb +15 -0
  107. data/smoke/expandarray1.rb +22 -0
  108. data/smoke/expandarray2.rb +23 -0
  109. data/smoke/fib.rb +28 -0
  110. data/smoke/flow1.rb +16 -0
  111. data/smoke/flow2.rb +14 -0
  112. data/smoke/flow3.rb +14 -0
  113. data/smoke/flow4.rb +5 -0
  114. data/smoke/flow5.rb +19 -0
  115. data/smoke/flow6.rb +19 -0
  116. data/smoke/flow7.rb +26 -0
  117. data/smoke/for.rb +9 -0
  118. data/smoke/freeze.rb +11 -0
  119. data/smoke/function.rb +16 -0
  120. data/smoke/gvar.rb +13 -0
  121. data/smoke/hash-fetch.rb +27 -0
  122. data/smoke/hash1.rb +18 -0
  123. data/smoke/hash2.rb +12 -0
  124. data/smoke/hash3.rb +13 -0
  125. data/smoke/hash4.rb +10 -0
  126. data/smoke/hash5.rb +14 -0
  127. data/smoke/inheritance.rb +34 -0
  128. data/smoke/inheritance2.rb +29 -0
  129. data/smoke/initialize.rb +26 -0
  130. data/smoke/instance_eval.rb +18 -0
  131. data/smoke/int_times.rb +14 -0
  132. data/smoke/integer.rb +10 -0
  133. data/smoke/ivar.rb +29 -0
  134. data/smoke/ivar2.rb +30 -0
  135. data/smoke/kernel-class.rb +12 -0
  136. data/smoke/keyword1.rb +11 -0
  137. data/smoke/keyword2.rb +11 -0
  138. data/smoke/keyword3.rb +12 -0
  139. data/smoke/keyword4.rb +11 -0
  140. data/smoke/keyword5.rb +15 -0
  141. data/smoke/kwsplat1.rb +42 -0
  142. data/smoke/kwsplat2.rb +12 -0
  143. data/smoke/manual-rbs.rb +27 -0
  144. data/smoke/manual-rbs.rbs +3 -0
  145. data/smoke/manual-rbs2.rb +20 -0
  146. data/smoke/manual-rbs2.rbs +8 -0
  147. data/smoke/masgn1.rb +13 -0
  148. data/smoke/masgn2.rb +17 -0
  149. data/smoke/masgn3.rb +12 -0
  150. data/smoke/method_in_branch.rb +22 -0
  151. data/smoke/module1.rb +29 -0
  152. data/smoke/module2.rb +28 -0
  153. data/smoke/module3.rb +33 -0
  154. data/smoke/module4.rb +29 -0
  155. data/smoke/module_function1.rb +28 -0
  156. data/smoke/module_function2.rb +28 -0
  157. data/smoke/multiple-include.rb +14 -0
  158. data/smoke/multiple-superclass.rb +16 -0
  159. data/smoke/next1.rb +20 -0
  160. data/smoke/next2.rb +16 -0
  161. data/smoke/object-send1.rb +22 -0
  162. data/smoke/once.rb +12 -0
  163. data/smoke/optional1.rb +13 -0
  164. data/smoke/optional2.rb +15 -0
  165. data/smoke/parameterizedd-self.rb +18 -0
  166. data/smoke/pathname1.rb +13 -0
  167. data/smoke/pathname2.rb +13 -0
  168. data/smoke/printf.rb +20 -0
  169. data/smoke/proc.rb +19 -0
  170. data/smoke/proc2.rb +16 -0
  171. data/smoke/proc3.rb +14 -0
  172. data/smoke/proc4.rb +11 -0
  173. data/smoke/range.rb +13 -0
  174. data/smoke/redo1.rb +21 -0
  175. data/smoke/redo2.rb +22 -0
  176. data/smoke/req-keyword.rb +12 -0
  177. data/smoke/rescue1.rb +20 -0
  178. data/smoke/rescue2.rb +22 -0
  179. data/smoke/respond_to.rb +22 -0
  180. data/smoke/rest-farg.rb +10 -0
  181. data/smoke/rest1.rb +25 -0
  182. data/smoke/rest2.rb +30 -0
  183. data/smoke/rest3.rb +36 -0
  184. data/smoke/rest4.rb +18 -0
  185. data/smoke/rest5.rb +10 -0
  186. data/smoke/rest6.rb +11 -0
  187. data/smoke/retry1.rb +20 -0
  188. data/smoke/return.rb +13 -0
  189. data/smoke/reveal.rb +13 -0
  190. data/smoke/singleton_class.rb +8 -0
  191. data/smoke/singleton_method.rb +9 -0
  192. data/smoke/step.rb +17 -0
  193. data/smoke/string-split.rb +11 -0
  194. data/smoke/struct.rb +9 -0
  195. data/smoke/struct2.rb +24 -0
  196. data/smoke/super1.rb +50 -0
  197. data/smoke/super2.rb +16 -0
  198. data/smoke/super3.rb +19 -0
  199. data/smoke/svar1.rb +12 -0
  200. data/smoke/tap1.rb +17 -0
  201. data/smoke/toplevel.rb +12 -0
  202. data/smoke/two-map.rb +17 -0
  203. data/smoke/type_var.rb +10 -0
  204. data/smoke/typed_method.rb +15 -0
  205. data/smoke/union-recv.rb +29 -0
  206. data/smoke/variadic1.rb.notyet +5 -0
  207. data/smoke/wrong-extend.rb +25 -0
  208. data/smoke/wrong-include.rb +26 -0
  209. data/smoke/wrong-rbs.rb +15 -0
  210. data/smoke/wrong-rbs.rbs +7 -0
  211. data/testbed/ao.rb +297 -0
  212. data/testbed/diff-lcs-entrypoint.rb +4 -0
  213. data/testbed/goodcheck-Gemfile.lock +51 -0
  214. data/tools/coverage.rb +14 -0
  215. data/tools/setup-insns-def.rb +30 -0
  216. data/tools/stackprof-wrapper.rb +10 -0
  217. data/typeprof.gemspec +24 -0
  218. 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