rbs 0.2.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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,