rbs 0.2.0 → 0.6.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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +7 -1
  3. data/.gitignore +1 -1
  4. data/CHANGELOG.md +35 -0
  5. data/COPYING +1 -1
  6. data/Gemfile +16 -2
  7. data/README.md +87 -48
  8. data/Rakefile +54 -22
  9. data/bin/rbs-prof +9 -0
  10. data/bin/run_in_md.rb +49 -0
  11. data/bin/test_runner.rb +0 -2
  12. data/docs/sigs.md +6 -6
  13. data/docs/stdlib.md +3 -5
  14. data/docs/syntax.md +6 -3
  15. data/goodcheck.yml +65 -0
  16. data/lib/rbs.rb +3 -0
  17. data/lib/rbs/ast/declarations.rb +115 -14
  18. data/lib/rbs/ast/members.rb +41 -17
  19. data/lib/rbs/cli.rb +301 -123
  20. data/lib/rbs/constant.rb +4 -4
  21. data/lib/rbs/constant_table.rb +64 -53
  22. data/lib/rbs/definition.rb +175 -59
  23. data/lib/rbs/definition_builder.rb +646 -603
  24. data/lib/rbs/environment.rb +352 -210
  25. data/lib/rbs/environment_walker.rb +14 -23
  26. data/lib/rbs/errors.rb +159 -3
  27. data/lib/rbs/factory.rb +14 -0
  28. data/lib/rbs/namespace.rb +18 -0
  29. data/lib/rbs/parser.y +75 -21
  30. data/lib/rbs/prototype/rb.rb +119 -117
  31. data/lib/rbs/prototype/rbi.rb +5 -3
  32. data/lib/rbs/prototype/runtime.rb +34 -7
  33. data/lib/rbs/substitution.rb +8 -1
  34. data/lib/rbs/test.rb +81 -3
  35. data/lib/rbs/test/errors.rb +1 -1
  36. data/lib/rbs/test/hook.rb +133 -259
  37. data/lib/rbs/test/observer.rb +17 -0
  38. data/lib/rbs/test/setup.rb +13 -14
  39. data/lib/rbs/test/spy.rb +0 -321
  40. data/lib/rbs/test/tester.rb +116 -0
  41. data/lib/rbs/test/type_check.rb +44 -7
  42. data/lib/rbs/type_name_resolver.rb +58 -0
  43. data/lib/rbs/types.rb +94 -2
  44. data/lib/rbs/validator.rb +51 -0
  45. data/lib/rbs/variance_calculator.rb +12 -2
  46. data/lib/rbs/version.rb +1 -1
  47. data/lib/rbs/writer.rb +127 -91
  48. data/rbs.gemspec +0 -9
  49. data/schema/annotation.json +14 -0
  50. data/schema/comment.json +26 -0
  51. data/schema/decls.json +353 -0
  52. data/schema/function.json +87 -0
  53. data/schema/location.json +56 -0
  54. data/schema/members.json +248 -0
  55. data/schema/methodType.json +44 -0
  56. data/schema/types.json +299 -0
  57. data/stdlib/benchmark/benchmark.rbs +151 -151
  58. data/stdlib/builtin/encoding.rbs +2 -0
  59. data/stdlib/builtin/enumerable.rbs +2 -2
  60. data/stdlib/builtin/enumerator.rbs +3 -1
  61. data/stdlib/builtin/fiber.rbs +5 -1
  62. data/stdlib/builtin/file.rbs +0 -3
  63. data/stdlib/builtin/io.rbs +4 -4
  64. data/stdlib/builtin/proc.rbs +1 -2
  65. data/stdlib/builtin/symbol.rbs +1 -1
  66. data/stdlib/builtin/thread.rbs +2 -2
  67. data/stdlib/csv/csv.rbs +4 -6
  68. data/stdlib/fiber/fiber.rbs +117 -0
  69. data/stdlib/json/json.rbs +1 -1
  70. data/stdlib/logger/formatter.rbs +23 -0
  71. data/stdlib/logger/log_device.rbs +39 -0
  72. data/stdlib/logger/logger.rbs +507 -0
  73. data/stdlib/logger/period.rbs +7 -0
  74. data/stdlib/logger/severity.rbs +8 -0
  75. data/stdlib/mutex_m/mutex_m.rbs +77 -0
  76. data/stdlib/pathname/pathname.rbs +6 -6
  77. data/stdlib/prime/integer-extension.rbs +1 -1
  78. data/stdlib/prime/prime.rbs +44 -44
  79. data/stdlib/tmpdir/tmpdir.rbs +1 -1
  80. metadata +26 -116
  81. data/lib/rbs/test/test_helper.rb +0 -183
@@ -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,13 +108,66 @@ 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
101
126
  end
102
127
 
128
+ class NoSuperclassFoundError < StandardError
129
+ attr_reader :type_name
130
+ attr_reader :location
131
+
132
+ def initialize(type_name:, location:)
133
+ @type_name = type_name
134
+ @location = location
135
+
136
+ super "#{Location.to_string location}: Could not find super class: #{type_name}"
137
+ end
138
+
139
+ def self.check!(type_name, env:, location:)
140
+ env.class_decls.key?(type_name) or raise new(type_name: type_name, location: location)
141
+ end
142
+ end
143
+
144
+ class NoMixinFoundError < StandardError
145
+ attr_reader :type_name
146
+ attr_reader :member
147
+
148
+ def initialize(type_name:, member:)
149
+ @type_name = type_name
150
+ @member = member
151
+
152
+ super "#{Location.to_string location}: Could not find mixin: #{type_name}"
153
+ end
154
+
155
+ def location
156
+ member.location
157
+ end
158
+
159
+ def self.check!(type_name, env:, member:)
160
+ dic = case
161
+ when type_name.class?
162
+ env.class_decls
163
+ when type_name.interface?
164
+ env.interface_decls
165
+ end
166
+
167
+ dic.key?(type_name) or raise new(type_name: type_name, member: member)
168
+ end
169
+ end
170
+
103
171
  class DuplicatedMethodDefinitionError < StandardError
104
172
  attr_reader :decl
105
173
  attr_reader :location
@@ -122,6 +190,26 @@ module RBS
122
190
  end
123
191
  end
124
192
 
193
+ class MethodDefinitionConflictWithInterfaceMixinError < StandardError
194
+ include MethodNameHelper
195
+
196
+ attr_reader :type_name
197
+ attr_reader :method_name
198
+ attr_reader :kind
199
+ attr_reader :mixin_member
200
+ attr_reader :entries
201
+
202
+ def initialize(type_name:, method_name:, kind:, mixin_member:, entries:)
203
+ @type_name = type_name
204
+ @method_name = method_name
205
+ @kind = kind
206
+ @mixin_member = mixin_member
207
+ @entries = entries
208
+
209
+ super "#{entries[0].decl.location}: Duplicated method with interface mixin: #{method_name_string}"
210
+ end
211
+ end
212
+
125
213
  class UnknownMethodAliasError < StandardError
126
214
  attr_reader :original_name
127
215
  attr_reader :aliased_name
@@ -142,6 +230,74 @@ module RBS
142
230
  end
143
231
  end
144
232
 
233
+ class SuperclassMismatchError < StandardError
234
+ attr_reader :name
235
+ attr_reader :entry
236
+
237
+ def initialize(name:, super_classes:, entry:)
238
+ @name = name
239
+ @entry = entry
240
+ super "#{Location.to_string entry.primary.decl.location}: Superclass mismatch: #{name}"
241
+ end
242
+ end
243
+
244
+ class InconsistentMethodVisibilityError < StandardError
245
+ attr_reader :type_name
246
+ attr_reader :method_name
247
+ attr_reader :kind
248
+ attr_reader :member_pairs
249
+
250
+ def initialize(type_name:, method_name:, kind:, member_pairs:)
251
+ @type_name = type_name
252
+ @method_name = method_name
253
+ @kind = kind
254
+ @member_pairs = member_pairs
255
+
256
+ delimiter = case kind
257
+ when :instance
258
+ "#"
259
+ when :singleton
260
+ "."
261
+ end
262
+
263
+ super "#{Location.to_string member_pairs[0][0].location}: Inconsistent method visibility: #{type_name}#{delimiter}#{method_name}"
264
+ end
265
+ end
266
+
267
+ class InvalidOverloadMethodError < StandardError
268
+ attr_reader :type_name
269
+ attr_reader :method_name
270
+ attr_reader :kind
271
+ attr_reader :members
272
+
273
+ def initialize(type_name:, method_name:, kind:, members:)
274
+ @type_name = type_name
275
+ @method_name = method_name
276
+ @kind = kind
277
+ @members = members
278
+
279
+ delimiter = case kind
280
+ when :instance
281
+ "#"
282
+ when :singleton
283
+ "."
284
+ end
285
+
286
+ super "#{Location.to_string members[0].location}: Invalid method overloading: #{type_name}#{delimiter}#{method_name}"
287
+ end
288
+ end
289
+
290
+ class GenericParameterMismatchError < StandardError
291
+ attr_reader :name
292
+ attr_reader :decl
293
+
294
+ def initialize(name:, decl:)
295
+ @name = name
296
+ @decl = decl
297
+ super "#{Location.to_string decl.location}: Generic parameters mismatch: #{name}"
298
+ end
299
+ end
300
+
145
301
  class DuplicatedDeclarationError < StandardError
146
302
  attr_reader :name
147
303
  attr_reader :decls
@@ -0,0 +1,14 @@
1
+ module RBS
2
+ class Factory
3
+ def type_name(string)
4
+ absolute = string.start_with?("::")
5
+
6
+ *path, name = string.delete_prefix("::").split("::").map(&:to_sym)
7
+
8
+ TypeName.new(
9
+ name: name,
10
+ namespace: Namespace.new(path: path, absolute: absolute)
11
+ )
12
+ end
13
+ end
14
+ end
@@ -87,5 +87,23 @@ module RBS
87
87
  new(path: string.split("::").map(&:to_sym), absolute: false)
88
88
  end
89
89
  end
90
+
91
+
92
+ def ascend
93
+ if block_given?
94
+ current = self
95
+
96
+ until current.empty?
97
+ yield current
98
+ current = current.parent
99
+ end
100
+
101
+ yield current
102
+
103
+ self
104
+ else
105
+ enum_for(:ascend)
106
+ end
107
+ end
90
108
  end
91
109
  end
@@ -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
@@ -106,28 +106,28 @@ rule
106
106
  }
107
107
 
108
108
  module_decl:
109
- annotations kMODULE start_new_scope class_name module_type_params module_self_type class_members kEND {
109
+ annotations kMODULE start_new_scope class_name module_type_params colon_module_self_types class_members kEND {
110
110
  reset_variable_scope
111
111
 
112
112
  location = val[1].location + val[7].location
113
113
  result = Declarations::Module.new(
114
114
  name: val[3].value,
115
115
  type_params: val[4]&.value || Declarations::ModuleTypeParams.empty,
116
- self_type: val[5],
116
+ self_types: val[5],
117
117
  members: val[6],
118
118
  annotations: val[0],
119
119
  location: location,
120
120
  comment: leading_comment(val[0].first&.location || location)
121
121
  )
122
122
  }
123
- | annotations kMODULE start_new_scope tUKEYWORD type class_members kEND {
123
+ | annotations kMODULE start_new_scope tUKEYWORD module_self_types class_members kEND {
124
124
  reset_variable_scope
125
125
 
126
126
  location = val[1].location + val[6].location
127
127
  result = Declarations::Module.new(
128
128
  name: val[3].value,
129
129
  type_params: Declarations::ModuleTypeParams.empty,
130
- self_type: val[4],
130
+ self_types: val[4],
131
131
  members: val[5],
132
132
  annotations: val[0],
133
133
  location: location,
@@ -135,12 +135,50 @@ rule
135
135
  )
136
136
  }
137
137
 
138
- module_self_type:
139
- { result = nil }
140
- | kCOLON type {
138
+ colon_module_self_types:
139
+ { result = [] }
140
+ | kCOLON module_self_types {
141
141
  result = val[1]
142
142
  }
143
143
 
144
+ module_self_types:
145
+ module_self_type {
146
+ result = [val[0]]
147
+ }
148
+ | module_self_types kCOMMA module_self_type {
149
+ result = val[0].push(val[2])
150
+ }
151
+
152
+ module_self_type:
153
+ qualified_name kLBRACKET type_list kRBRACKET {
154
+ name = val[0].value
155
+ args = val[2]
156
+ location = val[0].location + val[3].location
157
+
158
+ case
159
+ when name.class?
160
+ result = Declarations::Module::Self.new(name: name, args: args, location: location)
161
+ when name.interface?
162
+ result = Declarations::Module::Self.new(name: name, args: args, location: location)
163
+ else
164
+ raise SemanticsError.new("Module self type should be instance or interface", subject: val[0], location: val[0].location)
165
+ end
166
+ }
167
+ | qualified_name {
168
+ name = val[0].value
169
+ args = []
170
+ location = val[0].location
171
+
172
+ case
173
+ when name.class?
174
+ result = Declarations::Module::Self.new(name: name, args: args, location: location)
175
+ when name.interface?
176
+ result = Declarations::Module::Self.new(name: name, args: args, location: location)
177
+ else
178
+ raise SemanticsError.new("Module self type should be instance or interface", subject: val[0], location: val[0].location)
179
+ end
180
+ }
181
+
144
182
  class_members:
145
183
  { result = [] }
146
184
  | class_members class_member {
@@ -161,6 +199,7 @@ rule
161
199
  result = Members::Private.new(location: val[0].location)
162
200
  }
163
201
  | alias_member
202
+ | signature
164
203
 
165
204
  attribute_member:
166
205
  annotations kATTRREADER keyword type {
@@ -386,10 +425,12 @@ rule
386
425
  comment: leading_comment(val[0].first&.location || location))
387
426
  }
388
427
 
428
+ overload: { result = nil } | kOVERLOAD
429
+
389
430
  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|
431
+ annotations attributes overload kDEF method_kind def_name method_types {
432
+ location = val[3].location + val[6].last.location
433
+ types = val[6].map do |type|
393
434
  case type
394
435
  when LocatedValue
395
436
  type.value
@@ -398,13 +439,14 @@ rule
398
439
  end
399
440
  end
400
441
  result = Members::MethodDefinition.new(
401
- name: val[4].value,
402
- kind: val[3],
442
+ name: val[5].value,
443
+ kind: val[4],
403
444
  types: types,
404
445
  annotations: val[0],
405
446
  location: location,
406
- comment: leading_comment(val[0].first&.location || val[1].first&.location || val[2].location),
407
- attributes: val[1].map(&:value)
447
+ comment: leading_comment(val[0].first&.location || val[1].first&.location || val[2]&.location || val[3].location),
448
+ attributes: val[1].map(&:value),
449
+ overload: !!val[2]
408
450
  )
409
451
  }
410
452
 
@@ -500,13 +542,13 @@ rule
500
542
  | tQUOTEDIDENT
501
543
  | tWRITE_ATTR
502
544
 
503
- method_name0: tUIDENT | tLIDENT | identifier_keywords
545
+ method_name0: tUIDENT | tLIDENT | tINTERFACEIDENT | identifier_keywords
504
546
 
505
547
  identifier_keywords:
506
548
  kCLASS | kVOID | kNIL | kTRUE | kFALSE | kANY | kUNTYPED | kTOP | kBOT | kINSTANCE | kBOOL | kSINGLETON
507
549
  | kTYPE | kMODULE | kPRIVATE | kPUBLIC | kEND | kINCLUDE | kEXTEND | kPREPEND
508
550
  | kATTRREADER | kATTRACCESSOR | kATTRWRITER | kDEF | kEXTENSION | kSELF | kINCOMPATIBLE
509
- | kUNCHECKED
551
+ | kUNCHECKED | kINTERFACE | kSUPER | kALIAS | kOUT | kIN | kOVERLOAD
510
552
 
511
553
  module_type_params:
512
554
  { result = nil }
@@ -1026,6 +1068,7 @@ def initialize(type, buffer:, eof_re:)
1026
1068
  @eof = false
1027
1069
  @bound_variables_stack = []
1028
1070
  @comments = {}
1071
+ @ascii_only = buffer.content.ascii_only?
1029
1072
  end
1030
1073
 
1031
1074
  def start_merged_variables_scope
@@ -1119,8 +1162,9 @@ def push_comment(string, location)
1119
1162
  end
1120
1163
 
1121
1164
  def new_token(type, value = input.matched)
1122
- start_index = input.charpos - input.matched.size
1123
- end_index = input.charpos
1165
+ charpos = charpos(input)
1166
+ start_index = charpos - input.matched.size
1167
+ end_index = charpos
1124
1168
 
1125
1169
  location = RBS::Location.new(buffer: buffer,
1126
1170
  start_pos: start_index,
@@ -1129,6 +1173,14 @@ def new_token(type, value = input.matched)
1129
1173
  [type, LocatedValue.new(location: location, value: value)]
1130
1174
  end
1131
1175
 
1176
+ def charpos(scanner)
1177
+ if @ascii_only
1178
+ scanner.pos
1179
+ else
1180
+ scanner.charpos
1181
+ end
1182
+ end
1183
+
1132
1184
  def empty_params_result
1133
1185
  [
1134
1186
  [],
@@ -1173,6 +1225,7 @@ KEYWORDS = {
1173
1225
  "extension" => :kEXTENSION,
1174
1226
  "incompatible" => :kINCOMPATIBLE,
1175
1227
  "unchecked" => :kUNCHECKED,
1228
+ "overload" => :kOVERLOAD,
1176
1229
  "out" => :kOUT,
1177
1230
  "in" => :kIN,
1178
1231
  }
@@ -1245,8 +1298,9 @@ def next_token
1245
1298
  when input.scan(/\s+/)
1246
1299
  # skip
1247
1300
  when input.scan(/#(( *)|( ?(?<string>.*)))\n/)
1248
- start_index = input.charpos - input.matched.size
1249
- end_index = input.charpos-1
1301
+ charpos = charpos(input)
1302
+ start_index = charpos - input.matched.size
1303
+ end_index = charpos-1
1250
1304
 
1251
1305
  location = RBS::Location.new(buffer: buffer,
1252
1306
  start_pos: start_index,