typeprof 0.1.2 → 0.4.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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/Gemfile +2 -2
  4. data/Gemfile.lock +10 -21
  5. data/LICENSE +21 -0
  6. data/README.md +1 -1
  7. data/doc/demo.md +398 -0
  8. data/doc/doc.ja.md +11 -1
  9. data/doc/doc.md +16 -7
  10. data/exe/typeprof +2 -1
  11. data/lib/typeprof.rb +9 -0
  12. data/lib/typeprof/analyzer.rb +455 -364
  13. data/lib/typeprof/arguments.rb +397 -0
  14. data/lib/typeprof/block.rb +133 -0
  15. data/lib/typeprof/builtin.rb +125 -116
  16. data/lib/typeprof/cli.rb +62 -71
  17. data/lib/typeprof/config.rb +114 -0
  18. data/lib/typeprof/container-type.rb +208 -27
  19. data/lib/typeprof/export.rb +201 -96
  20. data/lib/typeprof/import.rb +451 -365
  21. data/lib/typeprof/iseq.rb +43 -2
  22. data/lib/typeprof/method.rb +139 -100
  23. data/lib/typeprof/type.rb +138 -297
  24. data/lib/typeprof/utils.rb +4 -18
  25. data/lib/typeprof/version.rb +3 -0
  26. data/smoke/arguments2.rb +55 -0
  27. data/smoke/array-each3.rb +1 -4
  28. data/smoke/array12.rb +1 -1
  29. data/smoke/array6.rb +1 -0
  30. data/smoke/block-ambiguous.rb +36 -0
  31. data/smoke/block-args1-rest.rb +62 -0
  32. data/smoke/block-args1.rb +59 -0
  33. data/smoke/block-args2-rest.rb +62 -0
  34. data/smoke/block-args2.rb +59 -0
  35. data/smoke/block-args3-rest.rb +73 -0
  36. data/smoke/block-args3.rb +70 -0
  37. data/smoke/block-blockarg.rb +27 -0
  38. data/smoke/block-kwarg.rb +52 -0
  39. data/smoke/block11.rb +1 -1
  40. data/smoke/block13.rb +9 -0
  41. data/smoke/block13.rbs +3 -0
  42. data/smoke/block14.rb +17 -0
  43. data/smoke/block4.rb +2 -2
  44. data/smoke/block5.rb +1 -0
  45. data/smoke/block6.rb +1 -1
  46. data/smoke/block7.rb +0 -2
  47. data/smoke/block8.rb +2 -2
  48. data/smoke/block9.rb +1 -1
  49. data/smoke/blown.rb +1 -1
  50. data/smoke/class-hierarchy.rb +54 -0
  51. data/smoke/class-hierarchy2.rb +27 -0
  52. data/smoke/class.rb +2 -0
  53. data/smoke/constant1.rb +13 -5
  54. data/smoke/constant2.rb +2 -0
  55. data/smoke/cvar.rb +1 -0
  56. data/smoke/demo10.rb +1 -1
  57. data/smoke/demo5.rb +3 -0
  58. data/smoke/demo8.rb +2 -2
  59. data/smoke/demo9.rb +1 -3
  60. data/smoke/flow7.rb +1 -7
  61. data/smoke/flow8.rb +13 -0
  62. data/smoke/gvar.rb +1 -1
  63. data/smoke/gvar2.rb +17 -0
  64. data/smoke/gvar2.rbs +1 -0
  65. data/smoke/hash4.rb +1 -1
  66. data/smoke/inheritance2.rb +6 -0
  67. data/smoke/instance_eval.rb +1 -1
  68. data/smoke/int_times.rb +1 -1
  69. data/smoke/ivar3.rb +16 -0
  70. data/smoke/ivar3.rbs +3 -0
  71. data/smoke/keyword3.rb +1 -2
  72. data/smoke/keyword4.rb +1 -1
  73. data/smoke/manual-rbs2.rb +1 -1
  74. data/smoke/manual-rbs3.rb +12 -0
  75. data/smoke/manual-rbs3.rbs +3 -0
  76. data/smoke/module4.rb +5 -0
  77. data/smoke/multiple-superclass.rb +12 -0
  78. data/smoke/next2.rb +1 -1
  79. data/smoke/optional1.rb +1 -1
  80. data/smoke/optional2.rb +1 -1
  81. data/smoke/optional3.rb +10 -0
  82. data/smoke/proc4.rb +1 -1
  83. data/smoke/rbs-alias.rb +9 -0
  84. data/smoke/rbs-alias.rbs +4 -0
  85. data/smoke/rbs-attr.rb +26 -0
  86. data/smoke/rbs-attr.rbs +5 -0
  87. data/smoke/rbs-extend.rb +9 -0
  88. data/smoke/rbs-extend.rbs +7 -0
  89. data/smoke/rbs-interface.rb +24 -0
  90. data/smoke/rbs-interface.rbs +12 -0
  91. data/smoke/rbs-proc1.rb +9 -0
  92. data/smoke/rbs-proc1.rbs +3 -0
  93. data/smoke/rbs-proc2.rb +20 -0
  94. data/smoke/rbs-proc2.rbs +3 -0
  95. data/smoke/rbs-proc3.rb +13 -0
  96. data/smoke/rbs-proc3.rbs +4 -0
  97. data/smoke/rbs-record.rb +17 -0
  98. data/smoke/rbs-record.rbs +4 -0
  99. data/smoke/rbs-tyvar.rb +18 -0
  100. data/smoke/rbs-tyvar.rbs +5 -0
  101. data/smoke/rbs-tyvar2.rb +20 -0
  102. data/smoke/rbs-tyvar2.rbs +9 -0
  103. data/smoke/rbs-tyvar3.rb +25 -0
  104. data/smoke/rbs-tyvar3.rbs +4 -0
  105. data/smoke/rbs-vars.rb +39 -0
  106. data/smoke/rbs-vars.rbs +7 -0
  107. data/smoke/rest1.rb +1 -1
  108. data/smoke/rest2.rb +1 -1
  109. data/smoke/rest3.rb +1 -1
  110. data/smoke/rest5.rb +1 -1
  111. data/smoke/rest6.rb +1 -1
  112. data/smoke/retry1.rb +1 -1
  113. data/smoke/return.rb +1 -1
  114. data/smoke/singleton_method.rb +3 -0
  115. data/smoke/step.rb +1 -1
  116. data/smoke/struct.rb +6 -2
  117. data/smoke/struct3.rb +14 -0
  118. data/smoke/super1.rb +18 -0
  119. data/smoke/symbol-proc.rb +24 -0
  120. data/smoke/union-recv.rb +6 -0
  121. data/smoke/user-demo.rb +15 -0
  122. data/smoke/wrong-extend.rb +1 -0
  123. data/tools/setup-insns-def.rb +1 -1
  124. data/tools/stackprof-wrapper.rb +1 -1
  125. data/typeprof.gemspec +12 -4
  126. metadata +68 -10
  127. data/.gitmodules +0 -6
  128. data/run.sh +0 -3
  129. data/smoke/variadic1.rb.notyet +0 -5
@@ -3,208 +3,124 @@ require "rbs"
3
3
  module TypeProf
4
4
  class RBSReader
5
5
  def initialize
6
- @env, @builtin_env_dump = RBSReader.builtin_env
6
+ @env, @builtin_env_json = RBSReader.get_builtin_env
7
7
  end
8
8
 
9
- @builtin_env = nil
10
- def self.builtin_env
11
- return @builtin_env.dup, @builtin_env_dump if @builtin_env
9
+ @builtin_env = @builtin_env_json = nil
10
+ def self.get_builtin_env
11
+ unless @builtin_env
12
+ @builtin_env = RBS::Environment.new
13
+ @builtin_env_json = load_rbs(@builtin_env, builtin: true)
14
+ end
12
15
 
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
16
+ return @builtin_env.dup, @builtin_env_json
19
17
  end
20
18
 
21
19
  def load_builtin
22
- @builtin_env_dump
20
+ @builtin_env_json
23
21
  end
24
22
 
25
23
  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
24
+ RBSReader.load_rbs(@env, library: lib)
31
25
  end
32
26
 
33
27
  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
28
+ RBSReader.load_rbs(@env, path: path)
39
29
  end
40
- end
41
30
 
42
- class RBS2JSON
43
- def initialize(env, new_decls)
44
- @all_env = env.resolve_type_names
31
+ def self.load_rbs(env, builtin: false, **opt)
32
+ loader = RBS::EnvironmentLoader.new
33
+ unless builtin
34
+ loader.no_builtin!
35
+ loader.add(**opt)
36
+ end
37
+ new_decls = loader.load(env: env)
45
38
 
46
- resolver = RBS::TypeNameResolver.from_env(env)
47
- @current_env = RBS::Environment.new()
39
+ all_env = env.resolve_type_names
48
40
 
41
+ resolver = RBS::TypeNameResolver.from_env(all_env)
42
+ cur_env = RBS::Environment.new
49
43
  new_decls.each do |decl,|
50
- @current_env << env.resolve_declaration(resolver, decl, outer: [], prefix: RBS::Namespace.root)
44
+ cur_env << env.resolve_declaration(resolver, decl, outer: [], prefix: RBS::Namespace.root)
51
45
  end
46
+
47
+ RBS2JSON.new(all_env, cur_env).dump_json
52
48
  end
49
+ end
53
50
 
54
- def dump
55
- [import_rbs_classes, import_rbs_constants]
51
+ class RBS2JSON
52
+ def initialize(all_env, cur_env)
53
+ @all_env, @cur_env = all_env, cur_env
54
+ end
55
+
56
+ def dump_json
57
+ {
58
+ classes: conv_classes,
59
+ constants: conv_constants,
60
+ globals: conv_globals,
61
+ }
56
62
  end
57
63
 
58
64
  # constant_name = [Symbol]
59
65
  #
60
66
  # { constant_name => type }
61
- def import_rbs_constants
67
+ def conv_constants
62
68
  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)
69
+ @cur_env.constant_decls.each do |name, decl|
70
+ klass = conv_type_name(name)
71
+ constants[klass] = conv_type(decl.decl.type)
67
72
  end
68
73
  constants
69
74
  end
70
75
 
71
- # class_name = [Symbol]
72
- # method_name = [singleton: true|false, Symbol}
73
- # method_def = [...]
76
+ # gvar_name = Symbol (:$gvar)
74
77
  #
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
78
+ # { gvar_name => type }
79
+ def conv_globals
80
+ gvars = {}
81
+ @cur_env.global_decls.each do |name, decl|
82
+ decl = decl.decl
83
+ gvars[name] = conv_type(decl.type)
94
84
  end
85
+ gvars
86
+ end
95
87
 
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
88
+ def conv_classes
89
+ json = {}
137
90
 
138
- result = {}
139
- classes.each do |type_name, klass, superclass|
140
- next unless @current_env.class_decls[type_name]
91
+ each_class_decl do |name, decls|
92
+ super_class_name = get_super_class_name(name, decls)
93
+ klass = conv_type_name(name)
94
+ superclass = super_class_name ? conv_type_name(super_class_name) : nil
141
95
 
96
+ type_params = nil
142
97
  included_modules = []
98
+ extended_modules = []
143
99
  methods = {}
100
+ ivars = {}
101
+ cvars = {}
144
102
  rbs_sources = {}
145
- type_params = nil
146
103
 
147
- @current_env.class_decls[type_name].decls.each do |decl|
104
+ decls.each do |decl|
148
105
  decl = decl.decl
149
- raise NotImplementedError if decl.is_a?(RBS::AST::Declarations::Interface)
106
+
150
107
  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
108
+ raise "inconsistent type parameter declaration" if type_params && type_params != type_params2
109
+ type_params = type_params2
156
110
 
157
111
  decl.members.each do |member|
158
112
  case member
159
113
  when RBS::AST::Members::MethodDefinition
160
114
  name = member.name
161
115
 
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
116
  method_types = member.types.map do |method_type|
199
117
  case method_type
200
- when RBS::MethodType
201
- method_type
202
- when :super
203
- raise NotImplementedError
118
+ when RBS::MethodType then method_type
119
+ when :super then raise NotImplementedError
204
120
  end
205
121
  end
206
122
 
207
- method_def = translate_typed_method_def(method_types)
123
+ method_def = conv_method_def(method_types)
208
124
  rbs_source = [(member.kind == :singleton ? "self." : "") + member.name.to_s, member.types.map {|type| type.location.source }]
209
125
  if member.instance?
210
126
  methods[[false, name]] = method_def
@@ -214,8 +130,16 @@ module TypeProf
214
130
  methods[[true, name]] = method_def
215
131
  rbs_sources[[true, name]] = rbs_source
216
132
  end
217
- #when RBS::AST::Members::AttrReader, RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrWriter
218
- #raise NotImplementedError
133
+ when RBS::AST::Members::AttrReader
134
+ ty = conv_type(member.type)
135
+ methods[[false, member.name]] = attr_reader_def(ty)
136
+ when RBS::AST::Members::AttrWriter
137
+ ty = conv_type(member.type)
138
+ methods[[false, :"#{ member.name }="]] = attr_writer_def(ty)
139
+ when RBS::AST::Members::AttrAccessor
140
+ ty = conv_type(member.type)
141
+ methods[[false, member.name]] = attr_reader_def(ty)
142
+ methods[[false, :"#{ member.name }="]] = attr_writer_def(ty)
219
143
  when RBS::AST::Members::Alias
220
144
  if member.instance?
221
145
  method_def = methods[[false, member.old_name]]
@@ -225,322 +149,484 @@ module TypeProf
225
149
  method_def = methods[[true, member.old_name]]
226
150
  methods[[true, member.new_name]] = method_def if method_def
227
151
  end
152
+
228
153
  when RBS::AST::Members::Include
229
154
  name = member.name
230
- mod = name.namespace.path + [name.name]
231
- included_modules << mod
155
+ if name.kind == :class
156
+ mod = conv_type_name(name)
157
+ included_modules << mod
158
+ else
159
+ # including an interface is not supported yet
160
+ end
161
+
162
+ when RBS::AST::Members::Extend
163
+ name = member.name
164
+ if name.kind == :class
165
+ mod = conv_type_name(name)
166
+ extended_modules << mod
167
+ else
168
+ # extending a module with an interface is not supported yet
169
+ end
170
+
232
171
  when RBS::AST::Members::InstanceVariable
172
+ ivars[member.name] = conv_type(member.type)
233
173
  when RBS::AST::Members::ClassVariable
234
- when RBS::AST::Members::Public, RBS::AST::Members::Private
174
+ cvars[member.name] = conv_type(member.type)
175
+
176
+ when RBS::AST::Members::Public, RBS::AST::Members::Private # XXX
177
+
178
+ # The following declarations are ignoreable because they are handled in other level
235
179
  when RBS::AST::Declarations::Constant
236
- when RBS::AST::Declarations::Alias
180
+ when RBS::AST::Declarations::Alias # type alias
181
+ when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module
182
+ when RBS::AST::Declarations::Interface
183
+
237
184
  else
238
185
  warn "Importing #{ member.class.name } is not supported yet"
239
- #p member
240
186
  end
241
187
  end
242
188
  end
243
189
 
244
- result[klass] = [type_params, superclass, included_modules, methods, rbs_sources]
245
- end.compact
190
+ json[klass] = {
191
+ type_params: type_params,
192
+ superclass: superclass,
193
+ members: {
194
+ included_modules: included_modules,
195
+ extended_modules: extended_modules,
196
+ methods: methods,
197
+ ivars: ivars,
198
+ cvars: cvars,
199
+ rbs_sources: rbs_sources,
200
+ },
201
+ }
202
+ end
246
203
 
247
- result
204
+ json
248
205
  end
249
206
 
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
207
+ def each_class_decl
208
+ # topological sort
209
+ # * superclasses and modules appear earlier than their subclasses (Object is earlier than String)
210
+ # * namespace module appers earlier than its children (Process is earlier than Process::Status)
211
+ visited = {}
212
+ queue = @cur_env.class_decls.keys.map {|name| [:visit, name] }
213
+ until queue.empty?
214
+ event, name = queue.pop
215
+ case event
216
+ when :visit
217
+ if !visited[name]
218
+ visited[name] = true
219
+ queue << [:new, name]
220
+ @all_env.class_decls[name].decls.each do |decl|
221
+ decl = decl.decl
222
+ next if decl.is_a?(RBS::AST::Declarations::Module)
223
+ each_ancestor(decl) {|name| queue << [:visit, name] }
224
+ end
225
+ queue << [:visit, name.namespace.to_type_name] if !name.namespace.empty?
226
+ end
227
+ when :new
228
+ decls = @cur_env.class_decls[name]
229
+ yield name, decls.decls if decls
256
230
  end
257
- type_params = type.type_params
231
+ end
258
232
 
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
233
+ @cur_env.interface_decls.each do |name, decl|
234
+ yield name, [decl]
235
+ end
236
+ end
237
+
238
+ def each_ancestor(decl, &blk)
239
+ yield decl.name
240
+ super_class = decl.super_class || RBS::BuiltinNames::Object
241
+ return if decl.name == RBS::BuiltinNames::BasicObject.name
242
+ return if decl.name == super_class.name
243
+ @all_env.class_decls[super_class.name].decls.each do |decl|
244
+ each_ancestor(decl.decl, &blk)
245
+ end
246
+ end
247
+
248
+ def get_super_class_name(name, decls)
249
+ return nil if name == RBS::BuiltinNames::BasicObject.name
276
250
 
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
251
+ decls.each do |decl|
252
+ decl = decl.decl
253
+ case decl
254
+ when RBS::AST::Declarations::Class
255
+ return decl.super_class.name if decl.super_class
256
+ when RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface
257
+ return nil
258
+ else
259
+ raise "unknown declaration: %p" % decl.class
281
260
  end
282
- end.compact
261
+ end
262
+
263
+ return RBS::BuiltinNames::Object.name
264
+ end
265
+
266
+ def conv_method_def(rbs_method_types)
267
+ rbs_method_types.map do |method_type|
268
+ conv_func(method_type.type_params, method_type.type, method_type.block)
269
+ end
270
+ end
271
+
272
+ def conv_func(type_params, func, block)
273
+ blk = block ? conv_block(block) : nil
274
+
275
+ lead_tys = func.required_positionals.map {|type| conv_type(type.type) }
276
+ opt_tys = func.optional_positionals.map {|type| conv_type(type.type) }
277
+ rest_ty = func.rest_positionals
278
+ rest_ty = conv_type(rest_ty.type) if rest_ty
279
+ opt_kw_tys = func.optional_keywords.to_h {|key, type| [key, conv_type(type.type)] }
280
+ req_kw_tys = func.required_keywords.to_h {|key, type| [key, conv_type(type.type)] }
281
+ rest_kw_ty = func.rest_keywords
282
+ raise NotImplementedError if rest_kw_ty # XXX
283
+
284
+ ret_ty = conv_type(func.return_type)
285
+
286
+ {
287
+ type_params: type_params,
288
+ lead_tys: lead_tys,
289
+ opt_tys: opt_tys,
290
+ rest_ty: rest_ty,
291
+ req_kw_tys: req_kw_tys,
292
+ opt_kw_tys: opt_kw_tys,
293
+ rest_kw_ty: rest_kw_ty,
294
+ blk: blk,
295
+ ret_ty: ret_ty,
296
+ }
297
+ end
298
+
299
+ def attr_reader_def(ty)
300
+ [{
301
+ type_params: [],
302
+ lead_tys: [],
303
+ opt_tys: [],
304
+ rest_ty: nil,
305
+ req_kw_tys: {},
306
+ opt_kw_tys: {},
307
+ rest_kw_ty: nil,
308
+ blk: nil,
309
+ ret_ty: ty,
310
+ }]
311
+ end
312
+
313
+ def attr_writer_def(ty)
314
+ [{
315
+ type_params: [],
316
+ lead_tys: [ty],
317
+ opt_tys: [],
318
+ rest_ty: nil,
319
+ req_kw_tys: {},
320
+ opt_kw_tys: {},
321
+ rest_kw_ty: nil,
322
+ blk: nil,
323
+ ret_ty: ty,
324
+ }]
283
325
  end
284
326
 
285
- def translate_typed_block(rs_block)
286
- type = rs_block.type
327
+ def conv_block(rbs_block)
328
+ type = rbs_block.type
329
+
330
+ # XXX
287
331
  raise NotImplementedError unless type.optional_keywords.empty?
288
332
  raise NotImplementedError unless type.required_keywords.empty?
289
- raise NotImplementedError unless type.optional_positionals.empty?
290
333
  raise NotImplementedError if type.rest_keywords
334
+
335
+ req = rbs_block.required
336
+
291
337
  lead_tys = type.required_positionals.map do |type|
292
- convert_type(type.type)
338
+ conv_type(type.type)
293
339
  end
294
- ret_ty = convert_type(type.return_type)
295
- [lead_tys, ret_ty]
296
- end
340
+ opt_tys = type.optional_positionals.map do |type|
341
+ conv_type(type.type)
342
+ end
343
+
344
+ ret_ty = conv_type(type.return_type)
297
345
 
298
- class UnsupportedType < StandardError
346
+ [req, lead_tys, opt_tys, ret_ty]
299
347
  end
300
348
 
301
- def convert_type(ty)
349
+ def conv_type(ty)
302
350
  case ty
303
351
  when RBS::Types::ClassSingleton
304
- klass = ty.name.namespace.path + [ty.name.name]
305
- [:class, klass]
352
+ [:class, conv_type_name(ty.name)]
306
353
  when RBS::Types::ClassInstance
307
- klass = ty.name.namespace.path + [ty.name.name]
354
+ klass = conv_type_name(ty.name)
308
355
  case klass
309
356
  when [:Array]
310
357
  raise if ty.args.size != 1
311
- [:array, :Array, [], convert_type(ty.args.first)]
358
+ [:array, [:Array], [], conv_type(ty.args.first)]
312
359
  when [:Hash]
313
360
  raise if ty.args.size != 2
314
361
  key, val = ty.args
315
- [:hash, :Hash, [convert_type(key), convert_type(val)]]
362
+ [:hash, [:Hash], [conv_type(key), conv_type(val)]]
316
363
  when [:Enumerator]
317
364
  raise if ty.args.size != 2
318
- [:array, :Enumerator, [], convert_type(ty.args.first)]
365
+ [:array, [:Enumerator], [], conv_type(ty.args.first)]
319
366
  else
320
367
  [:instance, klass]
321
368
  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]
369
+ when RBS::Types::Bases::Bool then [:bool]
370
+ when RBS::Types::Bases::Any then [:any]
371
+ when RBS::Types::Bases::Void then [:void]
372
+ when RBS::Types::Bases::Self then [:self]
373
+ when RBS::Types::Bases::Nil then [:nil]
374
+ when RBS::Types::Bases::Bottom then [:union, []]
375
+ when RBS::Types::Variable then [:var, ty.name]
336
376
  when RBS::Types::Tuple
337
- tys = ty.types.map {|ty2| convert_type(ty2) }
338
- [:array, :Array, tys, [:union, []]]
377
+ tys = ty.types.map {|ty2| conv_type(ty2) }
378
+ [:array, [:Array], tys, [:union, []]]
339
379
  when RBS::Types::Literal
340
380
  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]
381
+ when Integer then [:int]
382
+ when String then [:str]
383
+ when true then [:true]
384
+ when false then [:false]
385
+ when Symbol then [:sym, ty.literal]
351
386
  else
352
387
  p ty.literal
353
388
  raise NotImplementedError
354
389
  end
355
390
  when RBS::Types::Alias
356
391
  alias_decl = @all_env.alias_decls[ty.name]
357
- alias_decl ? convert_type(alias_decl.decl.type) : [:any]
392
+ alias_decl ? conv_type(alias_decl.decl.type) : [:any]
358
393
  when RBS::Types::Union
359
- [:union, ty.types.map {|ty2| begin convert_type(ty2); rescue UnsupportedType; end }.compact]
394
+ [:union, ty.types.map {|ty2| conv_type(ty2) }.compact]
360
395
  when RBS::Types::Optional
361
- [:optional, convert_type(ty.type)]
362
- when RBS::Types::Record
363
- [:any]
396
+ [:optional, conv_type(ty.type)]
364
397
  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]]
398
+ # XXX: Currently, only a few builtin interfaces are supported
399
+ case ty.to_s
400
+ when "::_ToStr" then [:str]
401
+ when "::_ToInt" then [:int]
402
+ when "::_ToAry[U]" then [:array, [:Array], [], [:var, :U]]
403
+ else
404
+ [:instance, conv_type_name(ty.name)]
369
405
  end
370
- [:any]
406
+ when RBS::Types::Bases::Instance then [:any] # XXX: not implemented yet
407
+ when RBS::Types::Record
408
+ [:hash_record, [:Hash], ty.fields.map {|key, ty| [key, conv_type(ty)] }]
409
+ when RBS::Types::Proc
410
+ [:proc, conv_func(nil, ty.type, nil)]
371
411
  else
372
- pp ty
373
- raise NotImplementedError
412
+ warn "unknown RBS type: %p" % ty.class
413
+ [:any]
374
414
  end
375
415
  end
376
- end
377
-
378
- module RubySignatureImporter
379
- module_function
380
416
 
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
417
+ def conv_type_name(name)
418
+ name.namespace.path + [name.name]
388
419
  end
420
+ end
389
421
 
390
- CACHE = {}
391
-
392
- def import_builtin(scratch)
393
- import_ruby_signature(scratch, scratch.rbs_reader.load_builtin)
422
+ class Import
423
+ def self.import_builtin(scratch)
424
+ Import.new(scratch, scratch.rbs_reader.load_builtin).import
394
425
  end
395
426
 
396
- def import_library(scratch, feature)
427
+ def self.import_library(scratch, feature)
428
+ begin
429
+ json = scratch.rbs_reader.load_library(feature)
430
+ rescue RBS::EnvironmentLoader::UnknownLibraryNameError
431
+ return nil
432
+ end
397
433
  # need cache?
398
- import_ruby_signature(scratch, scratch.rbs_reader.load_library(feature))
399
- rescue RBS::EnvironmentLoader::UnknownLibraryNameError
400
- false
434
+ Import.new(scratch, json).import
401
435
  end
402
436
 
403
- def import_rbs_file(scratch, rbs_path)
404
- import_ruby_signature(scratch, scratch.rbs_reader.load_path(Pathname(rbs_path)), true)
437
+ def self.import_rbs_file(scratch, rbs_path)
438
+ rbs_path = Pathname(rbs_path) unless rbs_path.is_a?(Pathname)
439
+ Import.new(scratch, scratch.rbs_reader.load_path(rbs_path)).import(true)
405
440
  end
406
441
 
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
442
+ def initialize(scratch, json)
443
+ @scratch = scratch
444
+ @json = json
445
+ end
446
+
447
+ def import(explicit = false)
448
+ classes = @json[:classes].map do |classpath, cdef|
449
+ type_params = cdef[:type_params]
450
+ superclass = cdef[:superclass]
451
+ members = cdef[:members]
452
+
453
+ name = classpath.last
454
+ superclass = path_to_klass(superclass) if superclass
455
+ base_klass = path_to_klass(classpath[0..-2])
456
+
457
+ klass = @scratch.get_constant(base_klass, name)
458
+ if klass.is_a?(Type::Any)
459
+ klass = @scratch.new_class(base_klass, name, type_params, superclass, nil)
460
+
461
+ # There builtin classes are needed to interpret RBS declarations
462
+ case classpath
463
+ when [:NilClass] then Type::Builtin[:nil] = klass
464
+ when [:TrueClass] then Type::Builtin[:true] = klass
465
+ when [:FalseClass] then Type::Builtin[:false] = klass
466
+ when [:Integer] then Type::Builtin[:int] = klass
467
+ when [:String] then Type::Builtin[:str] = klass
468
+ when [:Symbol] then Type::Builtin[:sym] = klass
469
+ when [:Array] then Type::Builtin[:ary] = klass
470
+ when [:Hash] then Type::Builtin[:hash] = klass
471
+ when [:Proc] then Type::Builtin[:proc] = klass
428
472
  end
429
473
  end
430
- classes << [klass, included_modules, methods, rbs_sources]
474
+
475
+ [klass, members]
431
476
  end
432
477
 
433
- classes.each do |klass, included_modules, methods, rbs_sources|
478
+ classes.each do |klass, members|
479
+ included_modules = members[:included_modules]
480
+ extended_modules = members[:extended_modules]
481
+ methods = members[:methods]
482
+ ivars = members[:ivars]
483
+ cvars = members[:cvars]
484
+ rbs_sources = members[:rbs_sources]
485
+
434
486
  included_modules.each do |mod|
435
- mod = path_to_klass(scratch, mod)
436
- scratch.include_module(klass, mod, false)
487
+ @scratch.include_module(klass, path_to_klass(mod), nil)
488
+ end
489
+
490
+ extended_modules.each do |mod|
491
+ @scratch.extend_module(klass, path_to_klass(mod), nil)
437
492
  end
493
+
438
494
  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)
495
+ rbs_source = explicit ? rbs_sources[[singleton, method_name]] : nil
496
+ mdef = conv_method_def(method_name, mdef, rbs_source)
497
+ @scratch.add_method(klass, method_name, singleton, mdef)
498
+ end
499
+
500
+ ivars.each do |ivar_name, ty|
501
+ ty = conv_type(ty)
502
+ @scratch.add_ivar_write!(Type::Instance.new(klass), ivar_name, ty, nil)
443
503
  end
504
+
505
+ cvars.each do |ivar_name, ty|
506
+ ty = conv_type(ty)
507
+ @scratch.add_cvar_write!(klass, ivar_name, ty, nil)
508
+ end
509
+ end
510
+
511
+ @json[:constants].each do |classpath, value|
512
+ base_klass = path_to_klass(classpath[0..-2])
513
+ value = conv_type(value)
514
+ @scratch.add_constant(base_klass, classpath[-1], value, nil)
444
515
  end
445
516
 
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)
517
+ @json[:globals].each do |name, value|
518
+ @scratch.add_gvar_write!(name, conv_type(value), nil)
450
519
  end
451
520
 
452
521
  true
453
522
  end
454
523
 
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
524
+ def conv_method_def(method_name, mdef, rbs_source)
525
+ sig_rets = mdef.flat_map do |sig_ret|
526
+ conv_func(sig_ret)
527
+ end
478
528
 
479
529
  TypedMethodDef.new(sig_rets, rbs_source)
480
530
  end
481
531
 
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])
532
+ def conv_func(sig_ret)
533
+ #type_params = sig_ret[:type_params] # XXX
534
+ lead_tys = sig_ret[:lead_tys]
535
+ opt_tys = sig_ret[:opt_tys]
536
+ rest_ty = sig_ret[:rest_ty]
537
+ req_kw_tys = sig_ret[:req_kw_tys]
538
+ opt_kw_tys = sig_ret[:opt_kw_tys]
539
+ rest_kw_ty = sig_ret[:rest_kw_ty]
540
+ blk = sig_ret[:blk]
541
+ ret_ty = sig_ret[:ret_ty]
542
+
543
+ lead_tys = lead_tys.map {|ty| conv_type(ty) }
544
+ opt_tys = opt_tys.map {|ty| conv_type(ty) }
545
+ rest_ty = conv_type(rest_ty) if rest_ty
546
+ kw_tys = []
547
+ req_kw_tys.each {|key, ty| kw_tys << [true, key, conv_type(ty)] }
548
+ opt_kw_tys.each {|key, ty| kw_tys << [false, key, conv_type(ty)] }
549
+ kw_rest_ty = conv_type(rest_kw_ty) if rest_kw_ty
550
+
551
+ blks = conv_block(blk)
552
+
553
+ ret_ty = conv_type(ret_ty)
554
+
555
+ blks.map do |blk|
556
+ [MethodSignature.new(lead_tys, opt_tys, rest_ty, [], kw_tys, kw_rest_ty, blk), ret_ty]
557
+ end
487
558
  end
488
559
 
489
- class UnsupportedType < StandardError
560
+ def conv_block(blk)
561
+ return [Type.nil] unless blk
562
+ req, lead_tys, opt_tys, ret_ty = blk
563
+ lead_tys = lead_tys.map {|ty| conv_type(ty) }
564
+ opt_tys = opt_tys.map {|ty| conv_type(ty) }
565
+ msig = MethodSignature.new(lead_tys, opt_tys, nil, nil, nil, nil, nil)
566
+ ret_ty = conv_type(ret_ty)
567
+ ret = [Type::Proc.new(TypedBlock.new(msig, ret_ty), Type::Builtin[:proc])]
568
+ ret << Type.nil unless req
569
+ ret
490
570
  end
491
571
 
492
- def convert_type(scratch, ty)
572
+ def conv_type(ty)
493
573
  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])
574
+ when :class then path_to_klass(ty[1])
575
+ when :instance then Type::Instance.new(path_to_klass(ty[1]))
576
+ when :any then Type.any
577
+ when :void then Type::Void.new
578
+ when :nil then Type.nil
579
+ when :optional then Type.optional(conv_type(ty[1]))
580
+ when :bool then Type.bool
581
+ when :self then Type::Var.new(:self)
582
+ when :int then Type::Instance.new(Type::Builtin[:int])
583
+ when :str then Type::Instance.new(Type::Builtin[:str])
584
+ when :sym then Type::Symbol.new(ty.last, Type::Instance.new(Type::Builtin[:sym]))
585
+ when :true then Type::Instance.new(Type::Builtin[:true])
586
+ when :false then Type::Instance.new(Type::Builtin[:false])
520
587
  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))
588
+ _, path, lead_tys, rest_ty = ty
589
+ lead_tys = lead_tys.map {|ty| conv_type(ty) }
590
+ rest_ty = conv_type(rest_ty)
591
+ base_type = Type::Instance.new(path_to_klass(path))
525
592
  Type::Array.new(Type::Array::Elements.new(lead_tys, rest_ty), base_type)
526
593
  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)
594
+ _, path, (k, v) = ty
595
+ Type.gen_hash(Type::Instance.new(path_to_klass(path))) do |h|
596
+ k_ty = conv_type(k)
597
+ v_ty = conv_type(v)
531
598
  h[k_ty] = v_ty
532
599
  end
600
+ when :hash_record
601
+ _, path, key_tys = ty
602
+ Type.gen_hash(Type::Instance.new(path_to_klass(path))) do |h|
603
+ key_tys.each do |key, ty|
604
+ k_ty = Type::Symbol.new(key, Type::Instance.new(Type::Builtin[:sym]))
605
+ v_ty = conv_type(ty)
606
+ h[k_ty] = v_ty
607
+ end
608
+ end
533
609
  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]))
610
+ tys = ty[1]
611
+ Type::Union.new(Utils::Set[*tys.map {|ty2| conv_type(ty2) }], nil) # XXX: Array and Hash support
538
612
  when :var
539
- Type::Var.new(ty[1]) # Currently, only for Array#* : (int | string) -> Array[Elem]
613
+ Type::Var.new(ty[1])
614
+ when :proc
615
+ msig, ret_ty = conv_func(ty[1]).first # Currently, RBS Proc does not accept a block, so the size should be always one
616
+ Type::Proc.new(TypedBlock.new(msig, ret_ty), Type::Instance.new(Type::Builtin[:proc]))
540
617
  else
541
618
  pp ty
542
619
  raise NotImplementedError
543
620
  end
544
621
  end
622
+
623
+ def path_to_klass(path)
624
+ klass = Type::Builtin[:obj]
625
+ path.each do |name|
626
+ klass = @scratch.get_constant(klass, name)
627
+ raise path.inspect if klass == Type.any
628
+ end
629
+ klass
630
+ end
545
631
  end
546
632
  end