rbs 0.10.0 → 0.13.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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +9 -9
  3. data/CHANGELOG.md +29 -0
  4. data/Gemfile +1 -0
  5. data/README.md +1 -1
  6. data/Rakefile +16 -6
  7. data/Steepfile +28 -0
  8. data/bin/steep +4 -0
  9. data/bin/test_runner.rb +7 -5
  10. data/docs/syntax.md +14 -1
  11. data/lib/rbs/ast/comment.rb +7 -1
  12. data/lib/rbs/ast/declarations.rb +15 -9
  13. data/lib/rbs/ast/members.rb +3 -8
  14. data/lib/rbs/buffer.rb +1 -1
  15. data/lib/rbs/cli.rb +72 -3
  16. data/lib/rbs/constant.rb +1 -1
  17. data/lib/rbs/constant_table.rb +9 -8
  18. data/lib/rbs/definition.rb +31 -14
  19. data/lib/rbs/definition_builder.rb +97 -67
  20. data/lib/rbs/environment.rb +28 -11
  21. data/lib/rbs/environment_loader.rb +67 -47
  22. data/lib/rbs/location.rb +1 -5
  23. data/lib/rbs/method_type.rb +5 -5
  24. data/lib/rbs/namespace.rb +14 -3
  25. data/lib/rbs/parser.y +2 -12
  26. data/lib/rbs/prototype/rb.rb +3 -5
  27. data/lib/rbs/prototype/rbi.rb +1 -4
  28. data/lib/rbs/prototype/runtime.rb +0 -4
  29. data/lib/rbs/substitution.rb +4 -3
  30. data/lib/rbs/test/setup.rb +5 -1
  31. data/lib/rbs/test/setup_helper.rb +15 -0
  32. data/lib/rbs/test/tester.rb +7 -5
  33. data/lib/rbs/test/type_check.rb +14 -2
  34. data/lib/rbs/type_name.rb +18 -1
  35. data/lib/rbs/type_name_resolver.rb +10 -3
  36. data/lib/rbs/types.rb +27 -21
  37. data/lib/rbs/variance_calculator.rb +9 -6
  38. data/lib/rbs/version.rb +1 -1
  39. data/lib/rbs/writer.rb +26 -17
  40. data/sig/annotation.rbs +26 -0
  41. data/sig/buffer.rbs +28 -0
  42. data/sig/builtin_names.rbs +41 -0
  43. data/sig/comment.rbs +26 -0
  44. data/sig/constant.rbs +21 -0
  45. data/sig/constant_table.rbs +30 -0
  46. data/sig/declarations.rbs +202 -0
  47. data/sig/definition.rbs +129 -0
  48. data/sig/definition_builder.rbs +94 -0
  49. data/sig/environment.rbs +94 -0
  50. data/sig/environment_loader.rbs +58 -0
  51. data/sig/location.rbs +52 -0
  52. data/sig/members.rbs +160 -0
  53. data/sig/method_types.rbs +40 -0
  54. data/sig/namespace.rbs +124 -0
  55. data/sig/polyfill.rbs +3 -0
  56. data/sig/rbs.rbs +3 -0
  57. data/sig/substitution.rbs +39 -0
  58. data/sig/type_name_resolver.rbs +24 -0
  59. data/sig/typename.rbs +70 -0
  60. data/sig/types.rbs +361 -0
  61. data/sig/util.rbs +13 -0
  62. data/sig/variance_calculator.rbs +35 -0
  63. data/sig/version.rbs +3 -0
  64. data/sig/writer.rbs +40 -0
  65. data/stdlib/bigdecimal/big_decimal.rbs +887 -0
  66. data/stdlib/bigdecimal/math/big_math.rbs +142 -0
  67. data/stdlib/builtin/array.rbs +2 -1
  68. data/stdlib/builtin/builtin.rbs +0 -3
  69. data/stdlib/builtin/hash.rbs +1 -1
  70. data/stdlib/builtin/kernel.rbs +2 -0
  71. data/stdlib/builtin/math.rbs +26 -26
  72. data/stdlib/builtin/struct.rbs +9 -10
  73. data/stdlib/date/date.rbs +1056 -0
  74. data/stdlib/date/date_time.rbs +582 -0
  75. data/stdlib/forwardable/forwardable.rbs +204 -0
  76. data/stdlib/pathname/pathname.rbs +2 -0
  77. data/stdlib/pty/pty.rbs +5 -29
  78. data/stdlib/set/set.rbs +1 -1
  79. data/stdlib/uri/file.rbs +167 -0
  80. data/stdlib/uri/generic.rbs +875 -0
  81. data/stdlib/uri/http.rbs +158 -0
  82. data/stdlib/uri/https.rbs +108 -0
  83. data/stdlib/uri/ldap.rbs +224 -0
  84. data/stdlib/uri/ldaps.rbs +108 -0
  85. data/stdlib/zlib/zlib.rbs +1 -1
  86. data/steep/Gemfile +3 -0
  87. data/steep/Gemfile.lock +51 -0
  88. metadata +45 -5
@@ -16,7 +16,7 @@ module RBS
16
16
  tokens.each.with_object({}) do |token, hash|
17
17
  if token[1] == :on_comment
18
18
  line = token[0][0]
19
- body = token[2][2..]
19
+ body = token[2][2..-1]
20
20
 
21
21
  body = "\n" if body.empty?
22
22
 
@@ -173,7 +173,6 @@ module RBS
173
173
  types: types,
174
174
  kind: :singleton,
175
175
  comment: comment,
176
- attributes: [],
177
176
  overload: false
178
177
  )
179
178
  end
@@ -194,7 +193,6 @@ module RBS
194
193
  types: types,
195
194
  kind: :instance,
196
195
  comment: comment,
197
- attributes: [],
198
196
  overload: false
199
197
  )
200
198
  end
@@ -502,7 +500,6 @@ module RBS
502
500
  else
503
501
  type_node.type == :CALL && proc_type?(type_node.children[0])
504
502
  end
505
-
506
503
  end
507
504
 
508
505
  def call_node?(node, name:, receiver: -> (node) { node.type == :CONST && node.children[0] == :T }, args: -> (node) { true })
@@ -154,7 +154,6 @@ module RBS
154
154
  location: nil,
155
155
  comment: method.comments[0],
156
156
  annotations: method.annotations,
157
- attributes: method.attributes,
158
157
  overload: false
159
158
  )
160
159
  return
@@ -193,7 +192,6 @@ module RBS
193
192
  location: nil,
194
193
  comment: nil,
195
194
  annotations: [],
196
- attributes: [],
197
195
  overload: false
198
196
  )
199
197
  end
@@ -227,7 +225,6 @@ module RBS
227
225
  location: nil,
228
226
  comment: nil,
229
227
  annotations: [],
230
- attributes: [],
231
228
  overload: false
232
229
  )
233
230
  end
@@ -262,7 +259,6 @@ module RBS
262
259
  location: nil,
263
260
  comment: nil,
264
261
  annotations: [],
265
- attributes: [],
266
262
  overload: false
267
263
  )
268
264
  end
@@ -31,10 +31,11 @@ module RBS
31
31
  def apply(ty)
32
32
  case ty
33
33
  when Types::Variable
34
+ # @type var ty: Types::Variable
34
35
  mapping[ty.name] || ty
35
36
  when Types::Bases::Instance
36
- if instance_type
37
- instance_type
37
+ if t = instance_type
38
+ t
38
39
  else
39
40
  ty
40
41
  end
@@ -44,7 +45,7 @@ module RBS
44
45
  end
45
46
 
46
47
  def without(*vars)
47
- self.class.new.tap do |subst|
48
+ Substitution.new.tap do |subst|
48
49
  subst.mapping.merge!(mapping)
49
50
  vars.each do |var|
50
51
  subst.mapping.delete(var)
@@ -13,6 +13,8 @@ begin
13
13
  skips = (ENV['RBS_TEST_SKIP'] || '').split(',').map! { |e| e.strip }
14
14
  RBS.logger_level = (ENV["RBS_TEST_LOGLEVEL"] || "info")
15
15
  sample_size = get_sample_size(ENV['RBS_TEST_SAMPLE_SIZE'] || '')
16
+ double_class = to_double_class(ENV['RBS_TEST_DOUBLE_SUITE'])
17
+ unchecked_classes = (ENV['RBS_TEST_UNCHECKED_CLASSES'] || '').split(',').map! { |unchecked_class| unchecked_class.strip }.push(*double_class)
16
18
  rescue InvalidSampleSizeError => exception
17
19
  RBS.logger.error exception.message
18
20
  exit 1
@@ -25,6 +27,8 @@ if filter.empty?
25
27
  STDERR.puts " [OPTIONAL] RBS_TEST_OPT: options for signatures (`-r` for libraries or `-I` for signatures)"
26
28
  STDERR.puts " [OPTIONAL] RBS_TEST_LOGLEVEL: one of debug|info|warn|error|fatal (defaults to info)"
27
29
  STDERR.puts " [OPTIONAL] RBS_TEST_SAMPLE_SIZE: sets the amount of values in a collection to be type-checked (Set to `ALL` to type check all the values)"
30
+ STDERR.puts " [OPTIONAL] RBS_TEST_DOUBLE_SUITE: sets the double suite in use (currently supported: minitest | rspec)"
31
+ STDERR.puts " [OPTIONAL] RBS_TEST_UNCHECKED_CLASSES: sets the classes that would not be checked"
28
32
  exit 1
29
33
  end
30
34
 
@@ -60,7 +64,7 @@ TracePoint.trace :end do |tp|
60
64
  if filter.any? {|f| match(to_absolute_typename(f).to_s, class_name.to_s) } && skips.none? {|f| match(f, class_name.to_s) }
61
65
  if env.class_decls.key?(class_name)
62
66
  logger.info "Setting up hooks for #{class_name}"
63
- tester.install!(tp.self, sample_size: sample_size)
67
+ tester.install!(tp.self, sample_size: sample_size, unchecked_classes: unchecked_classes)
64
68
  end
65
69
  end
66
70
  end
@@ -24,6 +24,21 @@ module RBS
24
24
  int_size
25
25
  end
26
26
  end
27
+
28
+ def to_double_class(double_suite)
29
+ return nil unless double_suite
30
+
31
+ case double_suite.downcase.strip
32
+ when 'rspec'
33
+ ['::RSpec::Mocks::Double']
34
+ when 'minitest'
35
+ ['::Minitest::Mock']
36
+ else
37
+ RBS.logger.warn "Unknown test suite - defaults to nil"
38
+ nil
39
+ end
40
+ end
41
+
27
42
  end
28
43
  end
29
44
  end
@@ -37,7 +37,7 @@ module RBS
37
37
  end
38
38
  end
39
39
 
40
- def install!(klass, sample_size:)
40
+ def install!(klass, sample_size:, unchecked_classes:)
41
41
  RBS.logger.info { "Installing runtime type checker in #{klass}..." }
42
42
 
43
43
  type_name = factory.type_name(klass.name).absolute!
@@ -45,7 +45,7 @@ module RBS
45
45
  builder.build_instance(type_name).tap do |definition|
46
46
  instance_key = new_key(type_name, "InstanceChecker")
47
47
  tester, set = instance_testers[klass] ||= [
48
- MethodCallTester.new(klass, builder, definition, kind: :instance, sample_size: sample_size),
48
+ MethodCallTester.new(klass, builder, definition, kind: :instance, sample_size: sample_size, unchecked_classes: unchecked_classes),
49
49
  Set[]
50
50
  ]
51
51
  Observer.register(instance_key, tester)
@@ -68,7 +68,7 @@ module RBS
68
68
  builder.build_singleton(type_name).tap do |definition|
69
69
  singleton_key = new_key(type_name, "SingletonChecker")
70
70
  tester, set = singleton_testers[klass] ||= [
71
- MethodCallTester.new(klass.singleton_class, builder, definition, kind: :singleton, sample_size: sample_size),
71
+ MethodCallTester.new(klass.singleton_class, builder, definition, kind: :singleton, sample_size: sample_size, unchecked_classes: unchecked_classes),
72
72
  Set[]
73
73
  ]
74
74
  Observer.register(singleton_key, tester)
@@ -111,13 +111,15 @@ module RBS
111
111
  attr_reader :builder
112
112
  attr_reader :kind
113
113
  attr_reader :sample_size
114
+ attr_reader :unchecked_classes
114
115
 
115
- def initialize(self_class, builder, definition, kind:, sample_size:)
116
+ def initialize(self_class, builder, definition, kind:, sample_size:, unchecked_classes:)
116
117
  @self_class = self_class
117
118
  @definition = definition
118
119
  @builder = builder
119
120
  @kind = kind
120
121
  @sample_size = sample_size
122
+ @unchecked_classes = unchecked_classes
121
123
  end
122
124
 
123
125
  def env
@@ -125,7 +127,7 @@ module RBS
125
127
  end
126
128
 
127
129
  def check
128
- @check ||= TypeCheck.new(self_class: self_class, builder: builder, sample_size: sample_size)
130
+ @check ||= TypeCheck.new(self_class: self_class, builder: builder, sample_size: sample_size, unchecked_classes: unchecked_classes)
129
131
  end
130
132
 
131
133
  def format_method_name(name)
@@ -4,15 +4,17 @@ module RBS
4
4
  attr_reader :self_class
5
5
  attr_reader :builder
6
6
  attr_reader :sample_size
7
+ attr_reader :unchecked_classes
7
8
 
8
9
  attr_reader :const_cache
9
10
 
10
11
  DEFAULT_SAMPLE_SIZE = 100
11
12
 
12
- def initialize(self_class:, builder:, sample_size:)
13
+ def initialize(self_class:, builder:, sample_size:, unchecked_classes:)
13
14
  @self_class = self_class
14
15
  @builder = builder
15
16
  @sample_size = sample_size
17
+ @unchecked_classes = unchecked_classes.uniq
16
18
  @const_cache = {}
17
19
  end
18
20
 
@@ -203,7 +205,16 @@ module RBS
203
205
  const_cache[type_name] ||= Object.const_get(type_name.to_s)
204
206
  end
205
207
 
208
+ def is_double?(value)
209
+ unchecked_classes.any? { |unchecked_class| Test.call(value, IS_AP, Object.const_get(unchecked_class))}
210
+ end
211
+
206
212
  def value(val, type)
213
+ if is_double?(val)
214
+ RBS.logger.info("A double (#{val.inspect}) is detected!")
215
+ return true
216
+ end
217
+
207
218
  case type
208
219
  when Types::Bases::Any
209
220
  true
@@ -295,7 +306,8 @@ module RBS
295
306
  Test.call(val, IS_AP, ::Array) &&
296
307
  type.types.map.with_index {|ty, index| value(val[index], ty) }.all?
297
308
  when Types::Record
298
- Test::call(val, IS_AP, ::Hash)
309
+ Test::call(val, IS_AP, ::Hash) &&
310
+ type.fields.map {|key, type| value(val[key], type) }.all?
299
311
  when Types::Proc
300
312
  Test::call(val, IS_AP, ::Proc)
301
313
  else
@@ -1,3 +1,4 @@
1
+
1
2
  module RBS
2
3
  class TypeName
3
4
  attr_reader :namespace
@@ -14,13 +15,15 @@ module RBS
14
15
  :alias
15
16
  when "_"
16
17
  :interface
18
+ else
19
+ raise
17
20
  end
18
21
  end
19
22
 
20
23
  def ==(other)
21
24
  other.is_a?(self.class) && other.namespace == namespace && other.name == name
22
25
  end
23
-
26
+
24
27
  alias eql? ==
25
28
 
26
29
  def hash
@@ -68,3 +71,17 @@ module RBS
68
71
  end
69
72
  end
70
73
  end
74
+
75
+ module Kernel
76
+ def TypeName(string)
77
+ absolute = string.start_with?("::")
78
+
79
+ *path, name = string.delete_prefix("::").split("::").map(&:to_sym)
80
+ raise unless name
81
+
82
+ RBS::TypeName.new(
83
+ name: name,
84
+ namespace: RBS::Namespace.new(path: path, absolute: absolute)
85
+ )
86
+ end
87
+ end
@@ -1,6 +1,6 @@
1
1
  module RBS
2
2
  class TypeNameResolver
3
- Query = Struct.new(:type_name, :context, keyword_init: true)
3
+ Query = _ = Struct.new(:type_name, :context, keyword_init: true)
4
4
 
5
5
  attr_reader :all_names
6
6
  attr_reader :cache
@@ -36,15 +36,22 @@ module RBS
36
36
  query = Query.new(type_name: type_name, context: context)
37
37
  try_cache(query) do
38
38
  path_head, *path_tail = type_name.to_namespace.path
39
+ raise unless path_head
40
+
39
41
  name_head = TypeName.new(name: path_head, namespace: Namespace.empty)
40
42
 
41
- absolute_head = context.each.find do |namespace|
43
+ absolute_head = context.find do |namespace|
44
+ # @type break: TypeName
42
45
  full_name = name_head.with_prefix(namespace)
43
46
  has_name?(full_name) and break full_name
44
47
  end
45
48
 
46
- if absolute_head
49
+ case absolute_head
50
+ when TypeName
47
51
  has_name?(Namespace.new(path: absolute_head.to_namespace.path.push(*path_tail), absolute: true).to_type_name)
52
+ when Namespace
53
+ # This cannot happen because the `context.find` doesn't return a Namespace.
54
+ raise
48
55
  end
49
56
  end
50
57
  end
@@ -1,3 +1,4 @@
1
+
1
2
  module RBS
2
3
  module Types
3
4
  module NoFreeVariables
@@ -77,7 +78,7 @@ module RBS
77
78
  when Types::Bases::Class
78
79
  'class'
79
80
  else
80
- raise "Unexpected base type: #{type.inspect}"
81
+ raise "Unexpected base type: #{inspect}"
81
82
  end
82
83
  end
83
84
  end
@@ -138,8 +139,6 @@ module RBS
138
139
  new(name: v, location: nil)
139
140
  when Array
140
141
  v.map {|x| new(name: x, location: nil) }
141
- else
142
- raise
143
142
  end
144
143
  end
145
144
 
@@ -227,7 +226,7 @@ module RBS
227
226
  end
228
227
 
229
228
  def each_type(&block)
230
- if block_given?
229
+ if block
231
230
  args.each(&block)
232
231
  else
233
232
  enum_for :each_type
@@ -380,7 +379,7 @@ module RBS
380
379
  end
381
380
 
382
381
  def each_type(&block)
383
- if block_given?
382
+ if block
384
383
  types.each(&block)
385
384
  else
386
385
  enum_for :each_type
@@ -445,7 +444,7 @@ module RBS
445
444
  end
446
445
 
447
446
  def each_type(&block)
448
- if block_given?
447
+ if block
449
448
  fields.each_value(&block)
450
449
  else
451
450
  enum_for :each_type
@@ -492,11 +491,15 @@ module RBS
492
491
  end
493
492
 
494
493
  def to_s(level = 0)
495
- if type.is_a?(RBS::Types::Literal) && type.literal.is_a?(Symbol)
496
- "#{type.to_s(1)} ?"
497
- else
498
- "#{type.to_s(1)}?"
494
+ case t = type
495
+ when RBS::Types::Literal
496
+ case t.literal
497
+ when Symbol
498
+ return "#{type.to_s(1)} ?"
499
+ end
499
500
  end
501
+
502
+ "#{type.to_s(1)}?"
500
503
  end
501
504
 
502
505
  def each_type
@@ -560,7 +563,7 @@ module RBS
560
563
  end
561
564
 
562
565
  def each_type(&block)
563
- if block_given?
566
+ if block
564
567
  types.each(&block)
565
568
  else
566
569
  enum_for :each_type
@@ -568,7 +571,7 @@ module RBS
568
571
  end
569
572
 
570
573
  def map_type(&block)
571
- if block_given?
574
+ if block
572
575
  Union.new(types: types.map(&block), location: location)
573
576
  else
574
577
  enum_for :map_type
@@ -629,7 +632,7 @@ module RBS
629
632
  end
630
633
 
631
634
  def each_type(&block)
632
- if block_given?
635
+ if block
633
636
  types.each(&block)
634
637
  else
635
638
  enum_for :each_type
@@ -637,7 +640,7 @@ module RBS
637
640
  end
638
641
 
639
642
  def map_type(&block)
640
- if block_given?
643
+ if block
641
644
  Intersection.new(types: types.map(&block), location: location)
642
645
  else
643
646
  enum_for :map_type
@@ -672,8 +675,8 @@ module RBS
672
675
  self.class.hash ^ type.hash ^ name.hash
673
676
  end
674
677
 
675
- def map_type
676
- if block_given?
678
+ def map_type(&block)
679
+ if block
677
680
  Param.new(name: name, type: yield(type))
678
681
  else
679
682
  enum_for :map_type
@@ -772,7 +775,7 @@ module RBS
772
775
  end
773
776
 
774
777
  def map_type(&block)
775
- if block_given?
778
+ if block
776
779
  Function.new(
777
780
  required_positionals: required_positionals.map {|param| param.map_type(&block) },
778
781
  optional_positionals: optional_positionals.map {|param| param.map_type(&block) },
@@ -810,7 +813,7 @@ module RBS
810
813
  end
811
814
 
812
815
  def each_param(&block)
813
- if block_given?
816
+ if block
814
817
  required_positionals.each(&block)
815
818
  optional_positionals.each(&block)
816
819
  rest_positionals&.yield_self(&block)
@@ -891,7 +894,9 @@ module RBS
891
894
  end
892
895
 
893
896
  def param_to_s
897
+ # @type var params: Array[String]
894
898
  params = []
899
+
895
900
  params.push(*required_positionals.map(&:to_s))
896
901
  params.push(*optional_positionals.map {|p| "?#{p}"})
897
902
  params.push("*#{rest_positionals}") if rest_positionals
@@ -927,8 +932,9 @@ module RBS
927
932
  def drop_tail
928
933
  case
929
934
  when !trailing_positionals.empty?
935
+ last = trailing_positionals.last or raise
930
936
  [
931
- trailing_positionals.last,
937
+ last,
932
938
  update(trailing_positionals: trailing_positionals.take(trailing_positionals.size - 1))
933
939
  ]
934
940
  else
@@ -960,7 +966,7 @@ module RBS
960
966
  self.class.hash ^ type.hash
961
967
  end
962
968
 
963
- def free_variables(set)
969
+ def free_variables(set = Set[])
964
970
  type.free_variables(set)
965
971
  end
966
972
 
@@ -977,7 +983,7 @@ module RBS
977
983
  end
978
984
 
979
985
  def each_type(&block)
980
- if block_given?
986
+ if block
981
987
  type.each_type(&block)
982
988
  else
983
989
  enum_for :each_type