rbs 0.18.1 → 1.0.0.pre2

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