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
@@ -173,7 +173,8 @@ module RBS
173
173
  types: types,
174
174
  kind: :singleton,
175
175
  comment: comment,
176
- attributes: []
176
+ attributes: [],
177
+ overload: false
177
178
  )
178
179
  end
179
180
 
@@ -193,7 +194,8 @@ module RBS
193
194
  types: types,
194
195
  kind: :instance,
195
196
  comment: comment,
196
- attributes: []
197
+ attributes: [],
198
+ overload: false
197
199
  )
198
200
  end
199
201
 
@@ -128,7 +128,7 @@ module RBS
128
128
 
129
129
  def merge_rbs(module_name, members, instance: nil, singleton: nil)
130
130
  if merge
131
- if env.class?(module_name.absolute!)
131
+ if env.class_decls[module_name.absolute!]
132
132
  case
133
133
  when instance
134
134
  method = builder.build_instance(module_name.absolute!).methods[instance]
@@ -152,9 +152,10 @@ module RBS
152
152
  },
153
153
  kind: kind,
154
154
  location: nil,
155
- comment: method.comment,
155
+ comment: method.comments[0],
156
156
  annotations: method.annotations,
157
- attributes: method.attributes
157
+ attributes: method.attributes,
158
+ overload: false
158
159
  )
159
160
  return
160
161
  end
@@ -192,7 +193,8 @@ module RBS
192
193
  location: nil,
193
194
  comment: nil,
194
195
  annotations: [],
195
- attributes: []
196
+ attributes: [],
197
+ overload: false
196
198
  )
197
199
  end
198
200
  else
@@ -225,7 +227,8 @@ module RBS
225
227
  location: nil,
226
228
  comment: nil,
227
229
  annotations: [],
228
- attributes: []
230
+ attributes: [],
231
+ overload: false
229
232
  )
230
233
  end
231
234
  else
@@ -259,7 +262,8 @@ module RBS
259
262
  location: nil,
260
263
  comment: nil,
261
264
  annotations: [],
262
- attributes: []
265
+ attributes: [],
266
+ overload: false
263
267
  )
264
268
  end
265
269
  else
@@ -1,6 +1,7 @@
1
1
  module RBS
2
2
  class Substitution
3
3
  attr_reader :mapping
4
+ attr_accessor :instance_type
4
5
 
5
6
  def initialize()
6
7
  @mapping = {}
@@ -10,7 +11,7 @@ module RBS
10
11
  mapping[from] = to
11
12
  end
12
13
 
13
- def self.build(variables, types, &block)
14
+ def self.build(variables, types, instance_type: Types::Bases::Instance.new(location: nil), &block)
14
15
  unless variables.size == types.size
15
16
  raise "Broken substitution: variables=#{variables}, types=#{types}"
16
17
  end
@@ -22,6 +23,8 @@ module RBS
22
23
  type = block_given? ? yield(t) : t
23
24
  subst.add(from: v, to: type)
24
25
  end
26
+
27
+ subst.instance_type = instance_type
25
28
  end
26
29
  end
27
30
 
@@ -29,6 +32,8 @@ module RBS
29
32
  case ty
30
33
  when Types::Variable
31
34
  mapping[ty.name] || ty
35
+ when Types::Bases::Instance
36
+ instance_type
32
37
  else
33
38
  ty
34
39
  end
@@ -40,6 +45,8 @@ module RBS
40
45
  vars.each do |var|
41
46
  subst.mapping.delete(var)
42
47
  end
48
+
49
+ subst.instance_type = self.instance_type
43
50
  end
44
51
  end
45
52
  end
@@ -94,7 +94,7 @@ module RBS
94
94
 
95
95
  builder.build_instance(type_name).tap do |definition|
96
96
  definition.methods.each do |name, method|
97
- if method.defined_in.name.absolute! == type_name
97
+ if method.defined_in == type_name
98
98
  unless method.annotations.any? {|a| a.string == "rbs:test:skip" }
99
99
  logger.info "Installing a hook on #{type_name}##{name}: #{method.method_types.join(" | ")}"
100
100
  verify instance_method: name, types: method.method_types
@@ -107,7 +107,7 @@ module RBS
107
107
 
108
108
  builder.build_singleton(type_name).tap do |definition|
109
109
  definition.methods.each do |name, method|
110
- if method.defined_in&.name&.absolute! == type_name || name == :new
110
+ if method.defined_in == type_name || name == :new
111
111
  unless method.annotations.any? {|a| a.string == "rbs:test:skip" }
112
112
  logger.info "Installing a hook on #{type_name}.#{name}: #{method.method_types.join(" | ")}"
113
113
  verify singleton_method: name, types: method.method_types
@@ -33,6 +33,8 @@ OptionParser.new do |opts|
33
33
  end.parse!(opts)
34
34
  loader.load(env: env)
35
35
 
36
+ env = env.resolve_type_names
37
+
36
38
  def match(filter, name)
37
39
  if filter.end_with?("*")
38
40
  name.start_with?(filter[0, filter.size - 1]) || name == filter[0, filter.size-3]
@@ -48,7 +50,7 @@ TracePoint.trace :end do |tp|
48
50
  if filter.any? {|f| match(f, class_name) } && skips.none? {|f| match(f, class_name) }
49
51
  type_name = RBS::Namespace.parse(class_name).absolute!.to_type_name
50
52
  if hooks.none? {|hook| hook.klass == tp.self }
51
- if env.find_class(type_name)
53
+ if env.class_decls.key?(type_name)
52
54
  logger.info "Setting up hooks for #{class_name}"
53
55
  hooks << RBS::Test::Hook.install(env, tp.self, logger: logger).verify_all.raise_on_error!(raise_on_error)
54
56
  end
@@ -17,9 +17,7 @@ module RBS
17
17
  loader.add library: lib
18
18
  end
19
19
 
20
- RBS::Environment.new.tap do |env|
21
- loader.load(env: env)
22
- end
20
+ RBS::Environment.from_loader(loader).resolve_type_names
23
21
  end
24
22
  end
25
23
 
@@ -126,8 +124,7 @@ module RBS
126
124
  type, definition = target
127
125
  method_types = case
128
126
  when definition.instance_type?
129
- subst = Substitution.build(definition.declaration.type_params.each.map(&:name),
130
- type.args)
127
+ subst = Substitution.build(definition.type_params, type.args)
131
128
  definition.methods[method].method_types.map do |method_type|
132
129
  method_type.sub(subst)
133
130
  end
@@ -220,8 +220,7 @@ module RBS
220
220
  val == klass
221
221
  when Types::Interface
222
222
  methods = Set.new(Test.call(val, METHODS))
223
- decl = builder.env.find_class(type.name)
224
- if (definition = builder.build_interface(type.name, decl))
223
+ if (definition = builder.build_interface(type.name))
225
224
  definition.methods.each_key.all? do |method_name|
226
225
  methods.member?(method_name)
227
226
  end
@@ -0,0 +1,58 @@
1
+ module RBS
2
+ class TypeNameResolver
3
+ Query = Struct.new(:type_name, :context, keyword_init: true)
4
+
5
+ attr_reader :all_names
6
+ attr_reader :cache
7
+
8
+ def initialize()
9
+ @all_names = Set[]
10
+ @cache = {}
11
+ end
12
+
13
+ def self.from_env(env)
14
+ new.add_names(env.class_decls.keys)
15
+ .add_names(env.interface_decls.keys)
16
+ .add_names(env.alias_decls.keys)
17
+ end
18
+
19
+ def add_names(names)
20
+ all_names.merge(names)
21
+ self
22
+ end
23
+
24
+ def try_cache(query)
25
+ cache.fetch(query) do
26
+ result = yield
27
+ cache[query] = result
28
+ end
29
+ end
30
+
31
+ def resolve(type_name, context:)
32
+ if type_name.absolute?
33
+ return type_name
34
+ end
35
+
36
+ query = Query.new(type_name: type_name, context: context)
37
+ try_cache(query) do
38
+ path_head, *path_tail = type_name.to_namespace.path
39
+ name_head = TypeName.new(name: path_head, namespace: Namespace.empty)
40
+
41
+ absolute_head = context.each.find do |namespace|
42
+ full_name = name_head.with_prefix(namespace)
43
+ has_name?(full_name) and break full_name
44
+ end
45
+
46
+ if absolute_head
47
+ has_name?(Namespace.new(path: absolute_head.to_namespace.path.push(*path_tail), absolute: true).to_type_name)
48
+ end
49
+ end
50
+ end
51
+
52
+ def has_name?(full_name)
53
+ if all_names.include?(full_name)
54
+ full_name
55
+ end
56
+ end
57
+ end
58
+ end
@@ -12,6 +12,12 @@ module RBS
12
12
  end
13
13
  end
14
14
 
15
+ module NoTypeName
16
+ def map_type_name
17
+ self
18
+ end
19
+ end
20
+
15
21
  module EmptyEachType
16
22
  def each_type
17
23
  if block_given?
@@ -43,6 +49,7 @@ module RBS
43
49
  include NoFreeVariables
44
50
  include NoSubst
45
51
  include EmptyEachType
52
+ include NoTypeName
46
53
 
47
54
  def to_json(*a)
48
55
  klass = to_s.to_sym
@@ -82,7 +89,11 @@ module RBS
82
89
  class Top < Base; end
83
90
  class Bottom < Base; end
84
91
  class Self < Base; end
85
- class Instance < Base; end
92
+ class Instance < Base
93
+ def sub(s)
94
+ s.apply(self)
95
+ end
96
+ end
86
97
  class Class < Base; end
87
98
  end
88
99
 
@@ -90,6 +101,8 @@ module RBS
90
101
  attr_reader :name
91
102
  attr_reader :location
92
103
 
104
+ include NoTypeName
105
+
93
106
  def initialize(name:, location:)
94
107
  @name = name
95
108
  @location = location
@@ -174,6 +187,13 @@ module RBS
174
187
  end
175
188
 
176
189
  include EmptyEachType
190
+
191
+ def map_type_name
192
+ ClassSingleton.new(
193
+ name: yield(name, location, self),
194
+ location: location
195
+ )
196
+ end
177
197
  end
178
198
 
179
199
  module Application
@@ -235,6 +255,14 @@ module RBS
235
255
  args: args.map {|ty| ty.sub(s) },
236
256
  location: location)
237
257
  end
258
+
259
+ def map_type_name(&block)
260
+ Interface.new(
261
+ name: yield(name, location, self),
262
+ args: args.map {|type| type.map_type_name(&block) },
263
+ location: location
264
+ )
265
+ end
238
266
  end
239
267
 
240
268
  class ClassInstance
@@ -257,6 +285,14 @@ module RBS
257
285
  args: args.map {|ty| ty.sub(s) },
258
286
  location: location)
259
287
  end
288
+
289
+ def map_type_name(&block)
290
+ ClassInstance.new(
291
+ name: yield(name, location, self),
292
+ args: args.map {|type| type.map_type_name(&block) },
293
+ location: location
294
+ )
295
+ end
260
296
  end
261
297
 
262
298
  class Alias
@@ -290,6 +326,13 @@ module RBS
290
326
  end
291
327
 
292
328
  include EmptyEachType
329
+
330
+ def map_type_name
331
+ Alias.new(
332
+ name: yield(name, location, self),
333
+ location: location
334
+ )
335
+ end
293
336
  end
294
337
 
295
338
  class Tuple
@@ -343,6 +386,13 @@ module RBS
343
386
  enum_for :each_type
344
387
  end
345
388
  end
389
+
390
+ def map_type_name(&block)
391
+ Tuple.new(
392
+ types: types.map {|type| type.map_type_name(&block) },
393
+ location: location
394
+ )
395
+ end
346
396
  end
347
397
 
348
398
  class Record
@@ -401,6 +451,13 @@ module RBS
401
451
  enum_for :each_type
402
452
  end
403
453
  end
454
+
455
+ def map_type_name(&block)
456
+ Record.new(
457
+ fields: fields.transform_values {|ty| ty.map_type_name(&block) },
458
+ location: location
459
+ )
460
+ end
404
461
  end
405
462
 
406
463
  class Optional
@@ -449,6 +506,13 @@ module RBS
449
506
  enum_for :each_type
450
507
  end
451
508
  end
509
+
510
+ def map_type_name(&block)
511
+ Optional.new(
512
+ type: type.map_type_name(&block),
513
+ location: location
514
+ )
515
+ end
452
516
  end
453
517
 
454
518
  class Union
@@ -510,6 +574,13 @@ module RBS
510
574
  enum_for :map_type
511
575
  end
512
576
  end
577
+
578
+ def map_type_name(&block)
579
+ Union.new(
580
+ types: types.map {|type| type.map_type_name(&block) },
581
+ location: location
582
+ )
583
+ end
513
584
  end
514
585
 
515
586
  class Intersection
@@ -572,6 +643,13 @@ module RBS
572
643
  enum_for :map_type
573
644
  end
574
645
  end
646
+
647
+ def map_type_name(&block)
648
+ Intersection.new(
649
+ types: types.map {|type| type.map_type_name(&block) },
650
+ location: location
651
+ )
652
+ end
575
653
  end
576
654
 
577
655
  class Function
@@ -648,7 +726,7 @@ module RBS
648
726
  other.required_keywords == required_keywords &&
649
727
  other.optional_keywords == optional_keywords &&
650
728
  other.rest_keywords == rest_keywords &&
651
- return_type == return_type
729
+ other.return_type == return_type
652
730
  end
653
731
 
654
732
  alias eql? ==
@@ -710,6 +788,12 @@ module RBS
710
788
  end
711
789
  end
712
790
 
791
+ def map_type_name(&block)
792
+ map_type do |type|
793
+ type.map_type_name(&block)
794
+ end
795
+ end
796
+
713
797
  def each_type
714
798
  if block_given?
715
799
  required_positionals.each {|param| yield param.type }
@@ -899,6 +983,13 @@ module RBS
899
983
  enum_for :each_type
900
984
  end
901
985
  end
986
+
987
+ def map_type_name(&block)
988
+ Proc.new(
989
+ type: type.map_type_name(&block),
990
+ location: location
991
+ )
992
+ end
902
993
  end
903
994
 
904
995
  class Literal
@@ -923,6 +1014,7 @@ module RBS
923
1014
  include NoFreeVariables
924
1015
  include NoSubst
925
1016
  include EmptyEachType
1017
+ include NoTypeName
926
1018
 
927
1019
  def to_json(*a)
928
1020
  { class: :literal, literal: literal.inspect, location: location }.to_json(*a)
@@ -0,0 +1,51 @@
1
+ module RBS
2
+ class Validator
3
+ attr_reader :env
4
+ attr_reader :resolver
5
+
6
+ def initialize(env:, resolver:)
7
+ @env = env
8
+ @resolver = resolver
9
+ end
10
+
11
+ def absolute_type(type, context:)
12
+ type.map_type_name do |type_name, _, type|
13
+ resolver.resolve(type_name, context: context) || yield(type)
14
+ end
15
+ end
16
+
17
+ # Validates presence of the relative type, and application arity match.
18
+ def validate_type(type, context:)
19
+ case type
20
+ when Types::ClassInstance, Types::Interface
21
+ if type.name.namespace.relative?
22
+ type = absolute_type(type, context: context) do |type|
23
+ NoTypeFoundError.check!(type.name.absolute!, env: env, location: type.location)
24
+ end
25
+ end
26
+
27
+ type_params = case type
28
+ when Types::ClassInstance
29
+ env.class_decls[type.name]&.type_params
30
+ when Types::Interface
31
+ env.interface_decls[type.name]&.decl&.type_params
32
+ end
33
+
34
+ unless type_params
35
+ raise NoTypeFoundError.new(type_name: type.name, location: type.location)
36
+ end
37
+
38
+ InvalidTypeApplicationError.check!(
39
+ type_name: type.name,
40
+ args: type.args,
41
+ params: type_params.each.map(&:name),
42
+ location: type.location
43
+ )
44
+ end
45
+
46
+ type.each_type do |type|
47
+ validate_type(type, context: context)
48
+ end
49
+ end
50
+ end
51
+ end