rbs 0.18.1 → 1.0.0.pre2

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/Rakefile +12 -0
  4. data/Steepfile +2 -1
  5. data/bin/annotate-with-rdoc +0 -4
  6. data/core/builtin.rbs +4 -0
  7. data/core/file.rbs +3 -4
  8. data/core/hash.rbs +1 -3
  9. data/core/io.rbs +165 -7
  10. data/core/kernel.rbs +1 -1
  11. data/core/module.rbs +41 -0
  12. data/core/time.rbs +0 -12
  13. data/docs/syntax.md +0 -17
  14. data/goodcheck.yml +22 -2
  15. data/lib/rbs.rb +2 -0
  16. data/lib/rbs/ast/declarations.rb +7 -49
  17. data/lib/rbs/ast/members.rb +10 -4
  18. data/lib/rbs/cli.rb +10 -10
  19. data/lib/rbs/definition.rb +70 -3
  20. data/lib/rbs/definition_builder.rb +573 -984
  21. data/lib/rbs/definition_builder/ancestor_builder.rb +525 -0
  22. data/lib/rbs/definition_builder/method_builder.rb +217 -0
  23. data/lib/rbs/environment.rb +6 -8
  24. data/lib/rbs/environment_loader.rb +8 -4
  25. data/lib/rbs/errors.rb +88 -121
  26. data/lib/rbs/method_type.rb +1 -31
  27. data/lib/rbs/parser.rb +1082 -1014
  28. data/lib/rbs/parser.y +108 -76
  29. data/lib/rbs/prototype/rb.rb +18 -3
  30. data/lib/rbs/prototype/rbi.rb +6 -6
  31. data/lib/rbs/prototype/runtime.rb +71 -35
  32. data/lib/rbs/substitution.rb +4 -0
  33. data/lib/rbs/test.rb +3 -1
  34. data/lib/rbs/test/hook.rb +26 -8
  35. data/lib/rbs/types.rb +68 -7
  36. data/lib/rbs/validator.rb +4 -2
  37. data/lib/rbs/variance_calculator.rb +5 -1
  38. data/lib/rbs/version.rb +1 -1
  39. data/lib/rbs/writer.rb +13 -4
  40. data/schema/members.json +5 -1
  41. data/sig/ancestor_builder.rbs +98 -0
  42. data/sig/declarations.rbs +4 -16
  43. data/sig/definition.rbs +6 -1
  44. data/sig/definition_builder.rbs +15 -67
  45. data/sig/errors.rbs +159 -0
  46. data/sig/members.rbs +4 -1
  47. data/sig/method_builder.rbs +71 -0
  48. data/sig/method_types.rbs +3 -16
  49. data/sig/substitution.rbs +3 -0
  50. data/sig/type_name_resolver.rbs +4 -2
  51. data/sig/types.rbs +17 -15
  52. data/sig/validator.rbs +12 -0
  53. data/stdlib/csv/0/csv.rbs +3 -0
  54. data/stdlib/dbm/0/dbm.rbs +0 -2
  55. data/stdlib/logger/0/log_device.rbs +1 -2
  56. data/stdlib/monitor/0/monitor.rbs +119 -0
  57. data/stdlib/pathname/0/pathname.rbs +1 -1
  58. data/stdlib/prime/0/prime.rbs +6 -0
  59. data/stdlib/securerandom/0/securerandom.rbs +2 -0
  60. data/stdlib/time/0/time.rbs +327 -0
  61. data/stdlib/tsort/0/tsort.rbs +8 -0
  62. data/stdlib/uri/0/common.rbs +401 -0
  63. data/stdlib/uri/0/rfc2396_parser.rbs +9 -0
  64. data/stdlib/uri/0/rfc3986_parser.rbs +2 -0
  65. data/steep/Gemfile.lock +13 -14
  66. metadata +16 -5
@@ -0,0 +1,217 @@
1
+ module RBS
2
+ class DefinitionBuilder
3
+ class MethodBuilder
4
+ class Methods
5
+ Definition = Struct.new(:name, :type, :originals, :overloads, :accessibilities, keyword_init: true) do
6
+ def original
7
+ originals[0]
8
+ end
9
+
10
+ def accessibility
11
+ accessibilities[0]
12
+ end
13
+
14
+ def self.empty(name:, type:)
15
+ new(type: type, name: name, originals: [], overloads: [], accessibilities: [])
16
+ end
17
+ end
18
+
19
+ attr_reader :type
20
+ attr_reader :methods
21
+
22
+ def initialize(type:)
23
+ @type = type
24
+ @methods = {}
25
+ end
26
+
27
+ def validate!
28
+ methods.each_value do |defn|
29
+ if defn.originals.size > 1
30
+ raise DuplicatedMethodDefinitionError.new(
31
+ type: type,
32
+ method_name: defn.name,
33
+ members: defn.originals
34
+ )
35
+ end
36
+ end
37
+
38
+ self
39
+ end
40
+
41
+ def each
42
+ if block_given?
43
+ Sorter.new(methods).each_strongly_connected_component do |scc|
44
+ if scc.size > 1
45
+ raise RecursiveAliasDefinitionError.new(type: type, defs: scc)
46
+ end
47
+
48
+ yield scc[0]
49
+ end
50
+ else
51
+ enum_for :each
52
+ end
53
+ end
54
+
55
+ class Sorter
56
+ include TSort
57
+
58
+ attr_reader :methods
59
+
60
+ def initialize(methods)
61
+ @methods = methods
62
+ end
63
+
64
+ def tsort_each_node(&block)
65
+ methods.each_value(&block)
66
+ end
67
+
68
+ def tsort_each_child(defn)
69
+ if (member = defn.original).is_a?(AST::Members::Alias)
70
+ if old = methods[member.old_name]
71
+ yield old
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ attr_reader :env
79
+ attr_reader :instance_methods
80
+ attr_reader :singleton_methods
81
+ attr_reader :interface_methods
82
+
83
+ def initialize(env:)
84
+ @env = env
85
+
86
+ @instance_methods = {}
87
+ @singleton_methods = {}
88
+ @interface_methods = {}
89
+ end
90
+
91
+ def build_instance(type_name)
92
+ instance_methods[type_name] ||=
93
+ begin
94
+ entry = env.class_decls[type_name]
95
+ args = Types::Variable.build(entry.type_params.each.map(&:name))
96
+ type = Types::ClassInstance.new(name: type_name, args: args, location: nil)
97
+ Methods.new(type: type).tap do |methods|
98
+ entry.decls.each do |d|
99
+ each_member_with_accessibility(d.decl.members) do |member, accessibility|
100
+ case member
101
+ when AST::Members::MethodDefinition
102
+ if member.instance?
103
+ build_method(methods, type, member: member, accessibility: accessibility)
104
+ end
105
+ when AST::Members::AttrReader, AST::Members::AttrWriter, AST::Members::AttrAccessor
106
+ if member.kind == :instance
107
+ build_attribute(methods, type, member: member, accessibility: accessibility)
108
+ end
109
+ when AST::Members::Alias
110
+ if member.kind == :instance
111
+ build_alias(methods, type, member: member, accessibility: accessibility)
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end.validate!
117
+ end
118
+ end
119
+
120
+ def build_singleton(type_name)
121
+ singleton_methods[type_name] ||=
122
+ begin
123
+ entry = env.class_decls[type_name]
124
+ type = Types::ClassSingleton.new(name: type_name, location: nil)
125
+
126
+ Methods.new(type: type).tap do |methods|
127
+ entry.decls.each do |d|
128
+ each_member_with_accessibility(d.decl.members) do |member, accessibility|
129
+ case member
130
+ when AST::Members::MethodDefinition
131
+ if member.singleton?
132
+ build_method(methods, type, member: member, accessibility: accessibility)
133
+ end
134
+ when AST::Members::AttrReader, AST::Members::AttrWriter, AST::Members::AttrAccessor
135
+ if member.kind == :singleton
136
+ build_attribute(methods, type, member: member, accessibility: accessibility)
137
+ end
138
+ when AST::Members::Alias
139
+ if member.kind == :singleton
140
+ build_alias(methods, type, member: member, accessibility: accessibility)
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end.validate!
146
+ end
147
+ end
148
+
149
+ def build_interface(type_name)
150
+ interface_methods[type_name] ||=
151
+ begin
152
+ entry = env.interface_decls[type_name]
153
+ args = Types::Variable.build(entry.decl.type_params.each.map(&:name))
154
+ type = Types::Interface.new(name: type_name, args: args, location: nil)
155
+
156
+ Methods.new(type: type).tap do |methods|
157
+ entry.decl.members.each do |member|
158
+ case member
159
+ when AST::Members::MethodDefinition
160
+ build_method(methods, type, member: member, accessibility: :public)
161
+ when AST::Members::Alias
162
+ build_alias(methods, type, member: member, accessibility: :public)
163
+ end
164
+ end
165
+ end.validate!
166
+ end
167
+ end
168
+
169
+ def build_alias(methods, type, member:, accessibility:)
170
+ defn = methods.methods[member.new_name] ||= Methods::Definition.empty(type: type, name: member.new_name)
171
+
172
+ defn.originals << member
173
+ defn.accessibilities << accessibility
174
+ end
175
+
176
+ def build_attribute(methods, type, member:, accessibility:)
177
+ if member.is_a?(AST::Members::AttrReader) || member.is_a?(AST::Members::AttrAccessor)
178
+ defn = methods.methods[member.name] ||= Methods::Definition.empty(type: type, name: member.name)
179
+
180
+ defn.accessibilities << accessibility
181
+ defn.originals << member
182
+ end
183
+
184
+ if member.is_a?(AST::Members::AttrWriter) || member.is_a?(AST::Members::AttrAccessor)
185
+ defn = methods.methods[:"#{member.name}="] ||= Methods::Definition.empty(type: type, name: :"#{member.name}=")
186
+
187
+ defn.accessibilities << accessibility
188
+ defn.originals << member
189
+ end
190
+ end
191
+
192
+ def build_method(methods, type, member:, accessibility:)
193
+ defn = methods.methods[member.name] ||= Methods::Definition.empty(type: type, name: member.name)
194
+
195
+ if member.overload?
196
+ defn.overloads << member
197
+ else
198
+ defn.accessibilities << accessibility
199
+ defn.originals << member
200
+ end
201
+ end
202
+
203
+ def each_member_with_accessibility(members, accessibility: :public)
204
+ members.each do |member|
205
+ case member
206
+ when AST::Members::Public
207
+ accessibility = :public
208
+ when AST::Members::Private
209
+ accessibility = :private
210
+ else
211
+ yield member, accessibility
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -133,7 +133,7 @@ module RBS
133
133
 
134
134
  def cache_name(cache, name:, decl:, outer:)
135
135
  if cache.key?(name)
136
- raise DuplicatedDeclarationError.new(name, decl, cache[name].decl)
136
+ raise DuplicatedDeclarationError.new(_ = name, _ = decl, _ = cache[name].decl)
137
137
  end
138
138
 
139
139
  cache[name] = SingleEntry.new(name: name, decl: decl, outer: outer)
@@ -195,9 +195,6 @@ module RBS
195
195
 
196
196
  when AST::Declarations::Global
197
197
  cache_name global_decls, name: decl.name, decl: decl, outer: outer
198
-
199
- when AST::Declarations::Extension
200
- RBS.logger.warn "#{Location.to_string decl.location} Extension construct is deprecated: use class/module syntax instead"
201
198
  end
202
199
  end
203
200
 
@@ -244,7 +241,8 @@ module RBS
244
241
  super_class: decl.super_class&.yield_self do |super_class|
245
242
  AST::Declarations::Class::Super.new(
246
243
  name: absolute_type_name(resolver, super_class.name, context: context),
247
- args: super_class.args.map {|type| absolute_type(resolver, type, context: context) }
244
+ args: super_class.args.map {|type| absolute_type(resolver, type, context: context) },
245
+ location: super_class.location
248
246
  )
249
247
  end,
250
248
  members: decl.members.map do |member|
@@ -325,9 +323,6 @@ module RBS
325
323
  location: decl.location,
326
324
  comment: decl.comment
327
325
  )
328
-
329
- else
330
- raise
331
326
  end
332
327
  end
333
328
 
@@ -349,6 +344,7 @@ module RBS
349
344
  AST::Members::AttrAccessor.new(
350
345
  name: member.name,
351
346
  type: absolute_type(resolver, member.type, context: context),
347
+ kind: member.kind,
352
348
  annotations: member.annotations,
353
349
  comment: member.comment,
354
350
  location: member.location,
@@ -358,6 +354,7 @@ module RBS
358
354
  AST::Members::AttrReader.new(
359
355
  name: member.name,
360
356
  type: absolute_type(resolver, member.type, context: context),
357
+ kind: member.kind,
361
358
  annotations: member.annotations,
362
359
  comment: member.comment,
363
360
  location: member.location,
@@ -367,6 +364,7 @@ module RBS
367
364
  AST::Members::AttrWriter.new(
368
365
  name: member.name,
369
366
  type: absolute_type(resolver, member.type, context: context),
367
+ kind: member.kind,
370
368
  annotations: member.annotations,
371
369
  comment: member.comment,
372
370
  location: member.location,
@@ -48,7 +48,11 @@ module RBS
48
48
  end
49
49
 
50
50
  def has_library?(library:, version:)
51
- self.class.gem_sig_path(library, version) || repository.lookup(library, version)
51
+ if self.class.gem_sig_path(library, version) || repository.lookup(library, version)
52
+ true
53
+ else
54
+ false
55
+ end
52
56
  end
53
57
 
54
58
  def load(env:)
@@ -70,7 +74,7 @@ module RBS
70
74
 
71
75
  libs.each do |lib|
72
76
  unless has_library?(version: lib.version, library: lib.name)
73
- raise UnknownLibraryError.new(lib: lib)
77
+ raise UnknownLibraryError.new(lib: lib)
74
78
  end
75
79
 
76
80
  case
@@ -97,12 +101,12 @@ module RBS
97
101
  if path.basename.to_s.start_with?("_")
98
102
  if skip_hidden
99
103
  unless immediate
100
- return
104
+ return
101
105
  end
102
106
  end
103
107
  end
104
108
 
105
- path.each_child do |child|
109
+ path.children.sort.each do |child|
106
110
  each_file(child, immediate: false, skip_hidden: skip_hidden, &block)
107
111
  end
108
112
  end
@@ -35,51 +35,25 @@ module RBS
35
35
  end
36
36
  end
37
37
 
38
- class InvalidExtensionParameterError < StandardError
39
- attr_reader :type_name
40
- attr_reader :extension_name
41
- attr_reader :location
42
- attr_reader :extension_params
43
- attr_reader :class_params
44
-
45
- def initialize(type_name:, extension_name:, extension_params:, class_params:, location:)
46
- @type_name = type_name
47
- @extension_name = extension_name
48
- @extension_params = extension_params
49
- @class_params = class_params
50
- @location = location
51
-
52
- super "#{Location.to_string location}: Expected #{class_params.size} parameters to #{type_name} (#{extension_name}) but has #{extension_params.size} parameters"
53
- end
54
-
55
- def self.check!(type_name:, extension_name:, extension_params:, class_params:, location:)
56
- unless extension_params.size == class_params.size
57
- raise new(type_name: type_name,
58
- extension_name: extension_name,
59
- extension_params: extension_params,
60
- class_params: class_params,
61
- location: location)
62
- end
63
- end
64
- end
65
-
66
38
  class RecursiveAncestorError < StandardError
67
39
  attr_reader :ancestors
68
40
  attr_reader :location
69
41
 
70
42
  def initialize(ancestors:, location:)
71
- last = case last = ancestors.last
72
- when Definition::Ancestor::Singleton
73
- "singleton(#{last.name})"
74
- when Definition::Ancestor::Instance
75
- if last.args.empty?
76
- last.name.to_s
77
- else
78
- "#{last.name}[#{last.args.join(", ")}]"
79
- end
80
- end
81
-
82
- super "#{Location.to_string location}: Detected recursive ancestors: #{last}"
43
+ names = ancestors.map do |ancestor|
44
+ case ancestor
45
+ when Definition::Ancestor::Singleton
46
+ "singleton(#{ancestor.name})"
47
+ when Definition::Ancestor::Instance
48
+ if ancestor.args.empty?
49
+ ancestor.name.to_s
50
+ else
51
+ "#{ancestor.name}[#{ancestor.args.join(", ")}]"
52
+ end
53
+ end
54
+ end
55
+
56
+ super "#{Location.to_string location}: Detected recursive ancestors: #{names.join(" < ")}"
83
57
  end
84
58
 
85
59
  def self.check!(self_ancestor, ancestors:, location:)
@@ -160,6 +134,8 @@ module RBS
160
134
  env.class_decls
161
135
  when type_name.interface?
162
136
  env.interface_decls
137
+ else
138
+ raise
163
139
  end
164
140
 
165
141
  dic.key?(type_name) or raise new(type_name: type_name, location: self_type.location)
@@ -187,6 +163,8 @@ module RBS
187
163
  env.class_decls
188
164
  when type_name.interface?
189
165
  env.interface_decls
166
+ else
167
+ raise
190
168
  end
191
169
 
192
170
  dic.key?(type_name) or raise new(type_name: type_name, member: member)
@@ -194,44 +172,60 @@ module RBS
194
172
  end
195
173
 
196
174
  class DuplicatedMethodDefinitionError < StandardError
197
- attr_reader :decl
198
- attr_reader :location
175
+ attr_reader :type
176
+ attr_reader :method_name
177
+ attr_reader :members
199
178
 
200
- def initialize(decl:, name:, location:)
201
- decl_str = case decl
202
- when AST::Declarations::Interface, AST::Declarations::Class, AST::Declarations::Module
203
- decl.name.to_s
204
- when AST::Declarations::Extension
205
- "#{decl.name} (#{decl.extension_name})"
206
- end
179
+ def initialize(type:, method_name:, members:)
180
+ @type = type
181
+ @method_name = method_name
182
+ @members = members
207
183
 
208
- super "#{Location.to_string location}: #{decl_str} has duplicated method definition: #{name}"
184
+ message = "#{Location.to_string location}: #{qualified_method_name} has duplicated definitions"
185
+ if members.size > 1
186
+ message << " in #{other_locations.map { |loc| Location.to_string loc }.join(', ')}"
187
+ end
188
+ super message
209
189
  end
210
190
 
211
- def self.check!(decl:, methods:, name:, location:)
212
- if methods.key?(name)
213
- raise new(decl: decl, name: name, location: location)
191
+ def qualified_method_name
192
+ case type
193
+ when Types::ClassSingleton
194
+ "#{type.name}.#{method_name}"
195
+ else
196
+ "#{type.name}##{method_name}"
214
197
  end
215
198
  end
216
- end
217
199
 
218
- class MethodDefinitionConflictWithInterfaceMixinError < StandardError
219
- include MethodNameHelper
200
+ def location
201
+ members[0].location
202
+ end
220
203
 
221
- attr_reader :type_name
204
+ def other_locations
205
+ members.drop(1).map(&:location)
206
+ end
207
+ end
208
+
209
+ class DuplicatedInterfaceMethodDefinitionError < StandardError
210
+ attr_reader :type
222
211
  attr_reader :method_name
223
- attr_reader :kind
224
- attr_reader :mixin_member
225
- attr_reader :entries
212
+ attr_reader :member
226
213
 
227
- def initialize(type_name:, method_name:, kind:, mixin_member:, entries:)
228
- @type_name = type_name
214
+ def initialize(type:, method_name:, member:)
215
+ @type = type
229
216
  @method_name = method_name
230
- @kind = kind
231
- @mixin_member = mixin_member
232
- @entries = entries
217
+ @member = member
233
218
 
234
- super "#{entries[0].decl.location}: Duplicated method with interface mixin: #{method_name_string}"
219
+ super "#{member.location}: Duplicated method definition: #{qualified_method_name}"
220
+ end
221
+
222
+ def qualified_method_name
223
+ case type
224
+ when Types::ClassSingleton
225
+ "#{type.name}.#{method_name}"
226
+ else
227
+ "#{type.name}##{method_name}"
228
+ end
235
229
  end
236
230
  end
237
231
 
@@ -247,48 +241,19 @@ module RBS
247
241
 
248
242
  super "#{Location.to_string location}: Unknown method alias name: #{original_name} => #{aliased_name}"
249
243
  end
250
-
251
- def self.check!(methods:, original_name:, aliased_name:, location:)
252
- unless methods.key?(original_name)
253
- raise new(original_name: original_name, aliased_name: aliased_name, location: location)
254
- end
255
- end
256
244
  end
257
245
 
258
246
  class SuperclassMismatchError < StandardError
259
247
  attr_reader :name
260
248
  attr_reader :entry
261
249
 
262
- def initialize(name:, super_classes:, entry:)
250
+ def initialize(name:, entry:)
263
251
  @name = name
264
252
  @entry = entry
265
253
  super "#{Location.to_string entry.primary.decl.location}: Superclass mismatch: #{name}"
266
254
  end
267
255
  end
268
256
 
269
- class InconsistentMethodVisibilityError < StandardError
270
- attr_reader :type_name
271
- attr_reader :method_name
272
- attr_reader :kind
273
- attr_reader :member_pairs
274
-
275
- def initialize(type_name:, method_name:, kind:, member_pairs:)
276
- @type_name = type_name
277
- @method_name = method_name
278
- @kind = kind
279
- @member_pairs = member_pairs
280
-
281
- delimiter = case kind
282
- when :instance
283
- "#"
284
- when :singleton
285
- "."
286
- end
287
-
288
- super "#{Location.to_string member_pairs[0][0].location}: Inconsistent method visibility: #{type_name}#{delimiter}#{method_name}"
289
- end
290
- end
291
-
292
257
  class InvalidOverloadMethodError < StandardError
293
258
  attr_reader :type_name
294
259
  attr_reader :method_name
@@ -331,38 +296,40 @@ module RBS
331
296
  @name = name
332
297
  @decls = decls
333
298
 
334
- super "#{Location.to_string decls.last.location}: Duplicated declaration: #{name}"
299
+ last_decl = decls.last or raise
300
+ super "#{Location.to_string last_decl.location}: Duplicated declaration: #{name}"
335
301
  end
336
302
  end
337
303
 
338
304
  class InvalidVarianceAnnotationError < StandardError
339
- MethodTypeError = Struct.new(:method_name, :method_type, :param, keyword_init: true)
340
- InheritanceError = Struct.new(:super_class, :param, keyword_init: true)
341
- MixinError = Struct.new(:include_member, :param, keyword_init: true)
305
+ attr_reader :type_name
306
+ attr_reader :param
307
+ attr_reader :location
342
308
 
343
- attr_reader :decl
344
- attr_reader :errors
309
+ def initialize(type_name:, param:, location:)
310
+ @type_name = type_name
311
+ @param = param
312
+ @location = location
345
313
 
346
- def initialize(decl:, errors:)
347
- @decl = decl
348
- @errors = errors
349
-
350
- message = [
351
- "#{Location.to_string decl.location}: Invalid variance annotation: #{decl.name}"
352
- ]
353
-
354
- errors.each do |error|
355
- case error
356
- when MethodTypeError
357
- message << " MethodTypeError (#{error.param.name}): on `#{error.method_name}` #{error.method_type.to_s} (#{error.method_type.location&.start_line})"
358
- when InheritanceError
359
- message << " InheritanceError: #{error.super_class}"
360
- when MixinError
361
- message << " MixinError: #{error.include_member.name} (#{error.include_member.location&.start_line})"
362
- end
363
- end
314
+ super "#{Location.to_string location}: Type parameter variance error: #{param.name} is #{param.variance} but used as incompatible variance"
315
+ end
316
+ end
317
+
318
+ class RecursiveAliasDefinitionError < StandardError
319
+ attr_reader :type
320
+ attr_reader :defs
364
321
 
365
- super message.join("\n")
322
+ def initialize(type:, defs:)
323
+ @type = type
324
+ @defs = defs
325
+
326
+ super "#{Location.to_string location}: Recursive aliases in #{type}: #{defs.map(&:name).join(", ")}"
327
+ end
328
+
329
+ def location
330
+ first_def = defs.first or raise
331
+ original = first_def.original or raise
332
+ original.location
366
333
  end
367
334
  end
368
335
  end