typeprof 0.1.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.
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