rbs 0.4.0 → 0.5.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +7 -1
  3. data/.gitignore +1 -1
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +12 -0
  6. data/README.md +86 -47
  7. data/Rakefile +54 -21
  8. data/bin/rbs-prof +9 -0
  9. data/bin/run_in_md.rb +49 -0
  10. data/lib/rbs.rb +2 -0
  11. data/lib/rbs/ast/declarations.rb +62 -7
  12. data/lib/rbs/ast/members.rb +41 -17
  13. data/lib/rbs/cli.rb +299 -121
  14. data/lib/rbs/constant.rb +4 -4
  15. data/lib/rbs/constant_table.rb +50 -44
  16. data/lib/rbs/definition.rb +175 -59
  17. data/lib/rbs/definition_builder.rb +647 -603
  18. data/lib/rbs/environment.rb +338 -209
  19. data/lib/rbs/environment_walker.rb +14 -23
  20. data/lib/rbs/errors.rb +141 -3
  21. data/lib/rbs/parser.y +14 -9
  22. data/lib/rbs/prototype/rb.rb +100 -112
  23. data/lib/rbs/prototype/rbi.rb +4 -2
  24. data/lib/rbs/prototype/runtime.rb +10 -6
  25. data/lib/rbs/substitution.rb +8 -1
  26. data/lib/rbs/test/hook.rb +2 -2
  27. data/lib/rbs/test/setup.rb +3 -1
  28. data/lib/rbs/test/test_helper.rb +2 -5
  29. data/lib/rbs/test/type_check.rb +1 -2
  30. data/lib/rbs/type_name_resolver.rb +58 -0
  31. data/lib/rbs/types.rb +94 -2
  32. data/lib/rbs/validator.rb +51 -0
  33. data/lib/rbs/variance_calculator.rb +12 -2
  34. data/lib/rbs/version.rb +1 -1
  35. data/lib/rbs/writer.rb +125 -89
  36. data/rbs.gemspec +0 -10
  37. data/schema/decls.json +15 -0
  38. data/schema/members.json +3 -0
  39. data/stdlib/benchmark/benchmark.rbs +151 -151
  40. data/stdlib/builtin/enumerable.rbs +1 -1
  41. data/stdlib/builtin/file.rbs +0 -3
  42. data/stdlib/builtin/io.rbs +4 -4
  43. data/stdlib/builtin/thread.rbs +2 -2
  44. data/stdlib/csv/csv.rbs +4 -6
  45. data/stdlib/fiber/fiber.rbs +1 -1
  46. data/stdlib/json/json.rbs +1 -1
  47. data/stdlib/mutex_m/mutex_m.rbs +77 -0
  48. data/stdlib/pathname/pathname.rbs +6 -6
  49. data/stdlib/prime/integer-extension.rbs +1 -1
  50. data/stdlib/prime/prime.rbs +44 -44
  51. data/stdlib/tmpdir/tmpdir.rbs +1 -1
  52. metadata +8 -129
@@ -23,13 +23,9 @@ module RBS
23
23
  include TSort
24
24
 
25
25
  def tsort_each_node(&block)
26
- env.each_decl do |name|
27
- yield name.absolute!
28
- end
29
-
30
- env.each_alias do |name, _|
31
- yield name.absolute!
32
- end
26
+ env.class_decls.each_key(&block)
27
+ env.interface_decls.each_key(&block)
28
+ env.alias_decls.each_key(&block)
33
29
  end
34
30
 
35
31
  def tsort_each_child(name, &block)
@@ -46,31 +42,26 @@ module RBS
46
42
  definitions << builder.build_instance(name)
47
43
  definitions << builder.build_singleton(name)
48
44
  when name.interface?
49
- definitions << builder.build_interface(name, env.find_class(name))
45
+ definitions << builder.build_interface(name)
50
46
  end
51
47
 
52
48
  definitions.each do |definition|
53
- definition.ancestors.each do |ancestor|
54
- yield ancestor.name
49
+ if ancestors = definition.ancestors
50
+ ancestors.ancestors.each do |ancestor|
51
+ yield ancestor.name
55
52
 
56
- case ancestor
57
- when Definition::Ancestor::Instance, Definition::Ancestor::ExtensionInstance
58
- ancestor.args.each do |type|
59
- each_type_name type, &block
53
+ case ancestor
54
+ when Definition::Ancestor::Instance
55
+ ancestor.args.each do |type|
56
+ each_type_name type, &block
57
+ end
60
58
  end
61
59
  end
62
60
  end
63
61
 
64
62
  unless only_ancestors?
65
- definition.methods.each do |_, method|
66
- method.method_types.each do |method_type|
67
- method_type.type.each_type do |type|
68
- each_type_name type, &block
69
- end
70
- method_type.block&.type&.each_type do |type|
71
- each_type_name type, &block
72
- end
73
- end
63
+ definition.each_type do |type|
64
+ each_type_name type, &block
74
65
  end
75
66
  end
76
67
  end
@@ -1,4 +1,19 @@
1
1
  module RBS
2
+ module MethodNameHelper
3
+ def method_name_string()
4
+ separator = case kind
5
+ when :instance
6
+ "#"
7
+ when :singleton
8
+ "."
9
+ else
10
+ raise
11
+ end
12
+
13
+ "#{type_name}#{separator}#{method_name}"
14
+ end
15
+ end
16
+
2
17
  class InvalidTypeApplicationError < StandardError
3
18
  attr_reader :type_name
4
19
  attr_reader :args
@@ -10,7 +25,7 @@ module RBS
10
25
  @args = args
11
26
  @params = params
12
27
  @location = location
13
- super "#{Location.to_string location}: #{type_name} expects parameters [#{params.each.map(&:name).join(", ")}], but given args [#{args.join(", ")}]"
28
+ super "#{Location.to_string location}: #{type_name} expects parameters [#{params.join(", ")}], but given args [#{args.join(", ")}]"
14
29
  end
15
30
 
16
31
  def self.check!(type_name:, args:, params:, location:)
@@ -93,8 +108,18 @@ module RBS
93
108
  end
94
109
 
95
110
  def self.check!(type_name, env:, location:)
96
- env.find_type_decl(type_name) or
97
- raise new(type_name: type_name, location: location)
111
+ dic = case
112
+ when type_name.class?
113
+ env.class_decls
114
+ when type_name.alias?
115
+ env.alias_decls
116
+ when type_name.interface?
117
+ env.interface_decls
118
+ else
119
+ raise
120
+ end
121
+
122
+ dic.key?(type_name) or raise new(type_name: type_name, location: location)
98
123
 
99
124
  type_name
100
125
  end
@@ -122,6 +147,26 @@ module RBS
122
147
  end
123
148
  end
124
149
 
150
+ class MethodDefinitionConflictWithInterfaceMixinError < StandardError
151
+ include MethodNameHelper
152
+
153
+ attr_reader :type_name
154
+ attr_reader :method_name
155
+ attr_reader :kind
156
+ attr_reader :mixin_member
157
+ attr_reader :entries
158
+
159
+ def initialize(type_name:, method_name:, kind:, mixin_member:, entries:)
160
+ @type_name = type_name
161
+ @method_name = method_name
162
+ @kind = kind
163
+ @mixin_member = mixin_member
164
+ @entries = entries
165
+
166
+ super "#{entries[0].decl.location}: Duplicated method with interface mixin: #{method_name_string}"
167
+ end
168
+ end
169
+
125
170
  class UnknownMethodAliasError < StandardError
126
171
  attr_reader :original_name
127
172
  attr_reader :aliased_name
@@ -142,6 +187,99 @@ module RBS
142
187
  end
143
188
  end
144
189
 
190
+ class MixedClassModuleDeclarationError < StandardError
191
+ attr_reader :name
192
+ attr_reader :decl
193
+
194
+ def initialize(name:, decl:)
195
+ @name = name
196
+ @decl = decl
197
+ super "#{Location.to_string decl.location}: Both class and module declarations: #{name}"
198
+ end
199
+ end
200
+
201
+ class SuperclassMismatchError < StandardError
202
+ attr_reader :name
203
+ attr_reader :entry
204
+
205
+ def initialize(name:, super_classes:, entry:)
206
+ @name = name
207
+ @entry = entry
208
+ super "#{Location.to_string entry.primary.decl.location}: Superclass mismatch: #{name}"
209
+ end
210
+ end
211
+
212
+ class ModuleSelfTypeMismatchError < StandardError
213
+ attr_reader :name
214
+ attr_reader :entry
215
+ attr_reader :location
216
+
217
+ def initialize(name:, entry:, location:)
218
+ @name = name
219
+ @entry = entry
220
+ @location = location
221
+
222
+ super "#{Location.to_string location}: Module self type mismatch: #{name}"
223
+ end
224
+ end
225
+
226
+ class InconsistentMethodVisibilityError < StandardError
227
+ attr_reader :type_name
228
+ attr_reader :method_name
229
+ attr_reader :kind
230
+ attr_reader :member_pairs
231
+
232
+ def initialize(type_name:, method_name:, kind:, member_pairs:)
233
+ @type_name = type_name
234
+ @method_name = method_name
235
+ @kind = kind
236
+ @member_pairs = member_pairs
237
+
238
+ delimiter = case kind
239
+ when :instance
240
+ "#"
241
+ when :singleton
242
+ "."
243
+ end
244
+
245
+ super "#{Location.to_string member_pairs[0][0].location}: Inconsistent method visibility: #{type_name}#{delimiter}#{method_name}"
246
+ end
247
+ end
248
+
249
+ class InvalidOverloadMethodError < StandardError
250
+ attr_reader :type_name
251
+ attr_reader :method_name
252
+ attr_reader :kind
253
+ attr_reader :members
254
+
255
+ def initialize(type_name:, method_name:, kind:, members:)
256
+ @type_name = type_name
257
+ @method_name = method_name
258
+ @kind = kind
259
+ @members = members
260
+
261
+ delimiter = case kind
262
+ when :instance
263
+ "#"
264
+ when :singleton
265
+ "."
266
+ end
267
+
268
+ super "#{Location.to_string members[0].location}: Invalid method overloading: #{type_name}#{delimiter}#{method_name}"
269
+ end
270
+ end
271
+
272
+ class GenericParameterMismatchError < StandardError
273
+ attr_reader :name
274
+ attr_reader :decl
275
+
276
+ def initialize(name:, decl:)
277
+ @name = name
278
+ @decl = decl
279
+ super "#{Location.to_string decl.location}: Generic parameters mismatch: #{name}"
280
+ end
281
+ end
282
+
145
283
  class DuplicatedDeclarationError < StandardError
146
284
  attr_reader :name
147
285
  attr_reader :decls
@@ -10,7 +10,7 @@ class RBS::Parser
10
10
  kINTERFACE kEND kINCLUDE kEXTEND kATTRREADER kATTRWRITER kATTRACCESSOR tOPERATOR tQUOTEDMETHOD tQUOTEDIDENT
11
11
  kPREPEND kEXTENSION kINCOMPATIBLE
12
12
  type_TYPE type_SIGNATURE type_METHODTYPE tEOF
13
- kOUT kIN kUNCHECKED
13
+ kOUT kIN kUNCHECKED kOVERLOAD
14
14
 
15
15
  prechigh
16
16
  nonassoc kQUESTION
@@ -161,6 +161,7 @@ rule
161
161
  result = Members::Private.new(location: val[0].location)
162
162
  }
163
163
  | alias_member
164
+ | signature
164
165
 
165
166
  attribute_member:
166
167
  annotations kATTRREADER keyword type {
@@ -386,10 +387,12 @@ rule
386
387
  comment: leading_comment(val[0].first&.location || location))
387
388
  }
388
389
 
390
+ overload: { result = nil } | kOVERLOAD
391
+
389
392
  method_member:
390
- annotations attributes kDEF method_kind def_name method_types {
391
- location = val[2].location + val[5].last.location
392
- types = val[5].map do |type|
393
+ annotations attributes overload kDEF method_kind def_name method_types {
394
+ location = val[3].location + val[6].last.location
395
+ types = val[6].map do |type|
393
396
  case type
394
397
  when LocatedValue
395
398
  type.value
@@ -398,13 +401,14 @@ rule
398
401
  end
399
402
  end
400
403
  result = Members::MethodDefinition.new(
401
- name: val[4].value,
402
- kind: val[3],
404
+ name: val[5].value,
405
+ kind: val[4],
403
406
  types: types,
404
407
  annotations: val[0],
405
408
  location: location,
406
- comment: leading_comment(val[0].first&.location || val[1].first&.location || val[2].location),
407
- attributes: val[1].map(&:value)
409
+ comment: leading_comment(val[0].first&.location || val[1].first&.location || val[2]&.location || val[3].location),
410
+ attributes: val[1].map(&:value),
411
+ overload: !!val[2]
408
412
  )
409
413
  }
410
414
 
@@ -506,7 +510,7 @@ rule
506
510
  kCLASS | kVOID | kNIL | kTRUE | kFALSE | kANY | kUNTYPED | kTOP | kBOT | kINSTANCE | kBOOL | kSINGLETON
507
511
  | kTYPE | kMODULE | kPRIVATE | kPUBLIC | kEND | kINCLUDE | kEXTEND | kPREPEND
508
512
  | kATTRREADER | kATTRACCESSOR | kATTRWRITER | kDEF | kEXTENSION | kSELF | kINCOMPATIBLE
509
- | kUNCHECKED | kINTERFACE | kSUPER | kALIAS | kOUT | kIN
513
+ | kUNCHECKED | kINTERFACE | kSUPER | kALIAS | kOUT | kIN | kOVERLOAD
510
514
 
511
515
  module_type_params:
512
516
  { result = nil }
@@ -1173,6 +1177,7 @@ KEYWORDS = {
1173
1177
  "extension" => :kEXTENSION,
1174
1178
  "incompatible" => :kINCOMPATIBLE,
1175
1179
  "unchecked" => :kUNCHECKED,
1180
+ "overload" => :kOVERLOAD,
1176
1181
  "out" => :kOUT,
1177
1182
  "in" => :kIN,
1178
1183
  }
@@ -6,19 +6,20 @@ module RBS
6
6
 
7
7
  def initialize
8
8
  @source_decls = []
9
- @toplevel_members = []
10
9
  end
11
10
 
12
11
  def decls
13
12
  decls = []
14
13
 
15
- decls.push(*source_decls)
14
+ top_decls, top_members = source_decls.partition {|decl| decl.is_a?(AST::Declarations::Base) }
16
15
 
17
- unless toplevel_members.empty?
18
- top = AST::Declarations::Extension.new(
16
+ decls.push(*top_decls)
17
+
18
+ unless top_members.empty?
19
+ top = AST::Declarations::Class.new(
19
20
  name: TypeName.new(name: :Object, namespace: Namespace.empty),
20
- extension_name: :Toplevel,
21
- members: toplevel_members,
21
+ super_class: nil,
22
+ members: top_members,
22
23
  annotations: [],
23
24
  comment: nil,
24
25
  location: nil,
@@ -27,7 +28,7 @@ module RBS
27
28
  decls << top
28
29
  end
29
30
 
30
- decls.uniq
31
+ decls
31
32
  end
32
33
 
33
34
  def parse(string)
@@ -51,19 +52,15 @@ module RBS
51
52
  end
52
53
  end
53
54
 
54
- process RubyVM::AbstractSyntaxTree.parse(string), namespace: Namespace.empty, current_module: nil, comments: comments, singleton: false
55
- end
56
-
57
- def nested_name(name)
58
- (current_namespace + const_to_name(name).to_namespace).to_type_name.relative!
55
+ process RubyVM::AbstractSyntaxTree.parse(string), decls: source_decls, comments: comments, singleton: false
59
56
  end
60
57
 
61
- def process(node, namespace:, current_module:, comments:, singleton:)
58
+ def process(node, decls:, comments:, singleton:)
62
59
  case node.type
63
60
  when :CLASS
64
61
  class_name, super_class, *class_body = node.children
65
62
  kls = AST::Declarations::Class.new(
66
- name: const_to_name(class_name).with_prefix(namespace).relative!,
63
+ name: const_to_name(class_name),
67
64
  super_class: super_class && AST::Declarations::Class::Super.new(name: const_to_name(super_class), args: []),
68
65
  type_params: AST::Declarations::ModuleTypeParams.empty,
69
66
  members: [],
@@ -72,16 +69,17 @@ module RBS
72
69
  comment: comments[node.first_lineno - 1]
73
70
  )
74
71
 
75
- source_decls.push kls
72
+ decls.push kls
76
73
 
77
74
  each_node class_body do |child|
78
- process child, namespace: kls.name.to_namespace, current_module: kls, comments: comments, singleton: false
75
+ process child, decls: kls.members, comments: comments, singleton: false
79
76
  end
77
+
80
78
  when :MODULE
81
79
  module_name, *module_body = node.children
82
80
 
83
81
  mod = AST::Declarations::Module.new(
84
- name: const_to_name(module_name).with_prefix(namespace).relative!,
82
+ name: const_to_name(module_name),
85
83
  type_params: AST::Declarations::ModuleTypeParams.empty,
86
84
  self_type: nil,
87
85
  members: [],
@@ -90,21 +88,23 @@ module RBS
90
88
  comment: comments[node.first_lineno - 1]
91
89
  )
92
90
 
93
- source_decls.push mod
91
+ decls.push mod
94
92
 
95
93
  each_node module_body do |child|
96
- process child, namespace: mod.name.to_namespace, current_module: mod, comments: comments, singleton: false
94
+ process child, decls: mod.members, comments: comments, singleton: false
97
95
  end
96
+
98
97
  when :SCLASS
99
- this = node.children[0]
98
+ this, body = node.children
99
+
100
100
  if this.type != :SELF
101
101
  RBS.logger.warn "`class <<` syntax with not-self may be compiled to incorrect code: #{this}"
102
102
  end
103
103
 
104
- body = node.children[1]
105
104
  each_child(body) do |child|
106
- process child, namespace: namespace, current_module: current_module, comments: comments, singleton: true
105
+ process child, decls: decls, comments: comments, singleton: true
107
106
  end
107
+
108
108
  when :DEFN, :DEFS
109
109
  if node.type == :DEFN
110
110
  def_name, def_body = node.children
@@ -130,116 +130,104 @@ module RBS
130
130
  types: types,
131
131
  kind: kind,
132
132
  comment: comments[node.first_lineno - 1],
133
- attributes: []
133
+ attributes: [],
134
+ overload: false
134
135
  )
135
136
 
136
- if current_module
137
- current_module.members.push member
138
- else
139
- toplevel_members.push member
140
- end
137
+ decls.push member
138
+
141
139
  when :FCALL
142
- if current_module
143
- # Inside method definition cannot reach here.
144
- args = node.children[1]&.children || []
145
-
146
- case node.children[0]
147
- when :include
148
- args.each do |arg|
149
- if (name = const_to_name(arg))
150
- current_module.members << AST::Members::Include.new(
151
- name: name,
152
- args: [],
153
- annotations: [],
154
- location: nil,
155
- comment: comments[node.first_lineno - 1]
156
- )
157
- end
140
+ # Inside method definition cannot reach here.
141
+ args = node.children[1]&.children || []
142
+
143
+ case node.children[0]
144
+ when :include
145
+ args.each do |arg|
146
+ if (name = const_to_name(arg))
147
+ decls << AST::Members::Include.new(
148
+ name: name,
149
+ args: [],
150
+ annotations: [],
151
+ location: nil,
152
+ comment: comments[node.first_lineno - 1]
153
+ )
158
154
  end
159
- when :extend
160
- args.each do |arg|
161
- if (name = const_to_name(arg))
162
- current_module.members << AST::Members::Extend.new(
163
- name: name,
164
- args: [],
165
- annotations: [],
166
- location: nil,
167
- comment: comments[node.first_lineno - 1]
168
- )
169
- end
155
+ end
156
+ when :extend
157
+ args.each do |arg|
158
+ if (name = const_to_name(arg))
159
+ decls << AST::Members::Extend.new(
160
+ name: name,
161
+ args: [],
162
+ annotations: [],
163
+ location: nil,
164
+ comment: comments[node.first_lineno - 1]
165
+ )
170
166
  end
171
- when :attr_reader
172
- args.each do |arg|
173
- if arg&.type == :LIT && arg.children[0].is_a?(Symbol)
174
- current_module.members << AST::Members::AttrReader.new(
175
- name: arg.children[0],
176
- ivar_name: nil,
177
- type: Types::Bases::Any.new(location: nil),
178
- location: nil,
179
- comment: comments[node.first_lineno - 1],
180
- annotations: []
181
- )
182
- end
167
+ end
168
+ when :attr_reader
169
+ args.each do |arg|
170
+ if arg&.type == :LIT && arg.children[0].is_a?(Symbol)
171
+ decls << AST::Members::AttrReader.new(
172
+ name: arg.children[0],
173
+ ivar_name: nil,
174
+ type: Types::Bases::Any.new(location: nil),
175
+ location: nil,
176
+ comment: comments[node.first_lineno - 1],
177
+ annotations: []
178
+ )
183
179
  end
184
- when :attr_accessor
185
- args.each do |arg|
186
- if arg&.type == :LIT && arg.children[0].is_a?(Symbol)
187
- current_module.members << AST::Members::AttrAccessor.new(
188
- name: arg.children[0],
189
- ivar_name: nil,
190
- type: Types::Bases::Any.new(location: nil),
191
- location: nil,
192
- comment: comments[node.first_lineno - 1],
193
- annotations: []
194
- )
195
- end
180
+ end
181
+ when :attr_accessor
182
+ args.each do |arg|
183
+ if arg&.type == :LIT && arg.children[0].is_a?(Symbol)
184
+ decls << AST::Members::AttrAccessor.new(
185
+ name: arg.children[0],
186
+ ivar_name: nil,
187
+ type: Types::Bases::Any.new(location: nil),
188
+ location: nil,
189
+ comment: comments[node.first_lineno - 1],
190
+ annotations: []
191
+ )
196
192
  end
197
- when :attr_writer
198
- args.each do |arg|
199
- if arg&.type == :LIT && arg.children[0].is_a?(Symbol)
200
- current_module.members << AST::Members::AttrWriter.new(
201
- name: arg.children[0],
202
- ivar_name: nil,
203
- type: Types::Bases::Any.new(location: nil),
204
- location: nil,
205
- comment: comments[node.first_lineno - 1],
206
- annotations: []
207
- )
208
- end
193
+ end
194
+ when :attr_writer
195
+ args.each do |arg|
196
+ if arg&.type == :LIT && arg.children[0].is_a?(Symbol)
197
+ decls << AST::Members::AttrWriter.new(
198
+ name: arg.children[0],
199
+ ivar_name: nil,
200
+ type: Types::Bases::Any.new(location: nil),
201
+ location: nil,
202
+ comment: comments[node.first_lineno - 1],
203
+ annotations: []
204
+ )
209
205
  end
210
206
  end
211
207
  end
208
+
212
209
  each_child node do |child|
213
- process child, namespace: namespace, current_module: current_module, comments: comments, singleton: singleton
210
+ process child, decls: decls, comments: comments, singleton: singleton
214
211
  end
215
212
 
216
213
  when :CDECL
217
- type_name = case
218
- when node.children[0].is_a?(Symbol)
219
- ns = if current_module
220
- current_module.name.to_namespace
221
- else
222
- Namespace.empty
223
- end
224
- TypeName.new(name: node.children[0], namespace: ns)
225
- else
226
- name = const_to_name(node.children[0])
227
- if current_module
228
- name.with_prefix current_module.name.to_namespace
229
- else
230
- name
231
- end.relative!
232
- end
233
-
234
- source_decls << AST::Declarations::Constant.new(
235
- name: type_name,
214
+ const_name = case
215
+ when node.children[0].is_a?(Symbol)
216
+ TypeName.new(name: node.children[0], namespace: Namespace.empty)
217
+ else
218
+ const_to_name(node.children[0])
219
+ end
220
+
221
+ decls << AST::Declarations::Constant.new(
222
+ name: const_name,
236
223
  type: node_type(node.children.last),
237
224
  location: nil,
238
225
  comment: comments[node.first_lineno - 1]
239
226
  )
227
+
240
228
  else
241
229
  each_child node do |child|
242
- process child, namespace: namespace, current_module: current_module, comments: comments, singleton: singleton
230
+ process child, decls: decls, comments: comments, singleton: singleton
243
231
  end
244
232
  end
245
233
  end