rbs 0.8.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/Gemfile +1 -0
  4. data/README.md +1 -1
  5. data/Rakefile +9 -4
  6. data/Steepfile +28 -0
  7. data/bin/steep +4 -0
  8. data/bin/test_runner.rb +10 -5
  9. data/docs/syntax.md +14 -1
  10. data/lib/rbs/ast/comment.rb +12 -0
  11. data/lib/rbs/ast/declarations.rb +15 -9
  12. data/lib/rbs/ast/members.rb +3 -8
  13. data/lib/rbs/buffer.rb +1 -1
  14. data/lib/rbs/cli.rb +66 -2
  15. data/lib/rbs/definition.rb +35 -16
  16. data/lib/rbs/definition_builder.rb +111 -68
  17. data/lib/rbs/environment.rb +24 -11
  18. data/lib/rbs/environment_loader.rb +55 -35
  19. data/lib/rbs/location.rb +14 -3
  20. data/lib/rbs/method_type.rb +5 -5
  21. data/lib/rbs/namespace.rb +14 -3
  22. data/lib/rbs/parser.y +8 -20
  23. data/lib/rbs/prototype/rb.rb +3 -5
  24. data/lib/rbs/prototype/rbi.rb +1 -4
  25. data/lib/rbs/prototype/runtime.rb +0 -4
  26. data/lib/rbs/substitution.rb +4 -3
  27. data/lib/rbs/test/hook.rb +1 -0
  28. data/lib/rbs/test/setup.rb +17 -12
  29. data/lib/rbs/test/setup_helper.rb +15 -0
  30. data/lib/rbs/test/tester.rb +59 -13
  31. data/lib/rbs/test/type_check.rb +43 -14
  32. data/lib/rbs/type_name.rb +18 -1
  33. data/lib/rbs/type_name_resolver.rb +10 -3
  34. data/lib/rbs/types.rb +27 -21
  35. data/lib/rbs/validator.rb +4 -0
  36. data/lib/rbs/variance_calculator.rb +8 -5
  37. data/lib/rbs/version.rb +1 -1
  38. data/lib/rbs/writer.rb +7 -3
  39. data/sig/annotation.rbs +26 -0
  40. data/sig/buffer.rbs +28 -0
  41. data/sig/builtin_names.rbs +41 -0
  42. data/sig/comment.rbs +26 -0
  43. data/sig/declarations.rbs +202 -0
  44. data/sig/definition.rbs +129 -0
  45. data/sig/definition_builder.rbs +95 -0
  46. data/sig/environment.rbs +94 -0
  47. data/sig/environment_loader.rbs +4 -0
  48. data/sig/location.rbs +52 -0
  49. data/sig/members.rbs +160 -0
  50. data/sig/method_types.rbs +40 -0
  51. data/sig/namespace.rbs +124 -0
  52. data/sig/polyfill.rbs +3 -0
  53. data/sig/rbs.rbs +3 -0
  54. data/sig/substitution.rbs +39 -0
  55. data/sig/type_name_resolver.rbs +24 -0
  56. data/sig/typename.rbs +70 -0
  57. data/sig/types.rbs +361 -0
  58. data/sig/util.rbs +13 -0
  59. data/sig/variance_calculator.rbs +35 -0
  60. data/stdlib/bigdecimal/big_decimal.rbs +887 -0
  61. data/stdlib/bigdecimal/math/big_math.rbs +142 -0
  62. data/stdlib/builtin/array.rbs +2 -1
  63. data/stdlib/builtin/builtin.rbs +0 -3
  64. data/stdlib/builtin/hash.rbs +1 -1
  65. data/stdlib/builtin/math.rbs +26 -26
  66. data/stdlib/builtin/struct.rbs +9 -10
  67. data/stdlib/date/date.rbs +1056 -0
  68. data/stdlib/date/date_time.rbs +582 -0
  69. data/stdlib/forwardable/forwardable.rbs +204 -0
  70. data/stdlib/json/json.rbs +6 -0
  71. data/stdlib/set/set.rbs +1 -1
  72. data/stdlib/uri/file.rbs +167 -0
  73. data/stdlib/uri/generic.rbs +875 -0
  74. data/stdlib/zlib/zlib.rbs +392 -0
  75. data/steep/Gemfile +3 -0
  76. data/steep/Gemfile.lock +55 -0
  77. metadata +39 -6
@@ -75,29 +75,16 @@ module RBS
75
75
  self.class.gem_sig_path(name, version)
76
76
  end
77
77
 
78
- def each_signature(path = nil, immediate: true, &block)
78
+ def each_signature(path, immediate: true, &block)
79
79
  if block_given?
80
- if path
81
- case
82
- when path.file?
83
- if path.extname == ".rbs" || immediate
84
- yield path
85
- end
86
- when path.directory?
87
- path.children.each do |child|
88
- each_signature child, immediate: false, &block
89
- end
80
+ case
81
+ when path.file?
82
+ if path.extname == ".rbs" || immediate
83
+ yield path
90
84
  end
91
- else
92
- paths.each do |path|
93
- case path
94
- when Pathname
95
- each_signature path, immediate: immediate, &block
96
- when LibraryPath
97
- each_signature path.path, immediate: immediate, &block
98
- when GemPath
99
- each_signature path.path, immediate: immediate, &block
100
- end
85
+ when path.directory?
86
+ path.children.each do |child|
87
+ each_signature child, immediate: false, &block
101
88
  end
102
89
  end
103
90
  else
@@ -105,32 +92,65 @@ module RBS
105
92
  end
106
93
  end
107
94
 
108
- def no_builtin!
109
- @no_builtin = true
95
+ def each_library_path
96
+ paths.each do |path|
97
+ case path
98
+ when Pathname
99
+ yield path, path
100
+ when LibraryPath
101
+ yield path, path.path
102
+ when GemPath
103
+ yield path, path.path
104
+ end
105
+ end
106
+ end
107
+
108
+ def no_builtin!(skip = true)
109
+ @no_builtin = skip
110
+ self
110
111
  end
111
112
 
112
113
  def no_builtin?
113
114
  @no_builtin
114
115
  end
115
116
 
116
- def load(env:)
117
- signature_files = []
117
+ def each_decl
118
+ if block_given?
119
+ signature_files = []
118
120
 
119
- unless no_builtin?
120
- signature_files.push(*each_signature(stdlib_root + "builtin"))
121
- end
121
+ unless no_builtin?
122
+ each_signature(stdlib_root + "builtin") do |path|
123
+ signature_files << [:stdlib, path]
124
+ end
125
+ end
122
126
 
123
- each_signature do |path|
124
- signature_files.push path
127
+ each_library_path do |library_path, pathname|
128
+ each_signature(pathname) do |path|
129
+ signature_files << [library_path, path]
130
+ end
131
+ end
132
+
133
+ signature_files.each do |lib_path, file_path|
134
+ buffer = Buffer.new(name: file_path.to_s, content: file_path.read)
135
+ Parser.parse_signature(buffer).each do |decl|
136
+ yield decl, buffer, file_path, lib_path
137
+ end
138
+ end
139
+ else
140
+ enum_for :each_decl
125
141
  end
142
+ end
143
+
144
+ def load(env:)
145
+ loadeds = []
126
146
 
127
- signature_files.each do |file|
128
- buffer = Buffer.new(name: file.to_s, content: file.read)
147
+ each_decl do |decl, buffer, file_path, lib_path|
129
148
  env.buffers.push(buffer)
130
- Parser.parse_signature(buffer).each do |decl|
131
- env << decl
132
- end
149
+ env << decl
150
+ loadeds << [decl, file_path, lib_path]
133
151
  end
152
+
153
+ loadeds
134
154
  end
135
155
  end
136
156
  end
@@ -43,7 +43,7 @@ module RBS
43
43
  end
44
44
 
45
45
  def source
46
- @source ||= buffer.content[start_pos...end_pos]
46
+ @source ||= buffer.content[start_pos...end_pos] or raise
47
47
  end
48
48
 
49
49
  def to_s
@@ -73,8 +73,19 @@ module RBS
73
73
  end
74
74
  end
75
75
 
76
- def self.concat(*locations)
77
- locations.inject {|l1, l2| l1 + l2 }
76
+ def concat(*others)
77
+ others.each { |other| self << other }
78
+ self
79
+ end
80
+
81
+ def <<(other)
82
+ if other
83
+ raise "Invalid concat: buffer=#{buffer.name}, other.buffer=#{other.buffer.name}" unless other.buffer == buffer
84
+ @end_pos = other.end_pos
85
+ @source = nil
86
+ @end_loc = nil
87
+ end
88
+ self
78
89
  end
79
90
 
80
91
  def pred?(loc)
@@ -93,7 +93,7 @@ module RBS
93
93
  end
94
94
 
95
95
  def each_type(&block)
96
- if block_given?
96
+ if block
97
97
  type.each_type(&block)
98
98
  self.block&.yield_self do |b|
99
99
  b.type.each_type(&block)
@@ -105,10 +105,10 @@ module RBS
105
105
 
106
106
  def to_s
107
107
  s = case
108
- when block && block.required
109
- "(#{type.param_to_s}) { (#{block.type.param_to_s}) -> #{block.type.return_to_s} } -> #{type.return_to_s}"
110
- when block
111
- "(#{type.param_to_s}) ?{ (#{block.type.param_to_s}) -> #{block.type.return_to_s} } -> #{type.return_to_s}"
108
+ when (b = block) && b.required
109
+ "(#{type.param_to_s}) { (#{b.type.param_to_s}) -> #{b.type.return_to_s} } -> #{type.return_to_s}"
110
+ when b = block
111
+ "(#{type.param_to_s}) ?{ (#{b.type.param_to_s}) -> #{b.type.return_to_s} } -> #{type.return_to_s}"
112
112
  else
113
113
  "(#{type.param_to_s}) -> #{type.return_to_s}"
114
114
  end
@@ -63,7 +63,9 @@ module RBS
63
63
  end
64
64
 
65
65
  def split
66
- [parent, path.last]
66
+ last = path.last or return
67
+ parent = self.parent
68
+ [parent, last]
67
69
  end
68
70
 
69
71
  def to_s
@@ -77,6 +79,10 @@ module RBS
77
79
 
78
80
  def to_type_name
79
81
  parent, name = split
82
+
83
+ raise unless name
84
+ raise unless parent
85
+
80
86
  TypeName.new(name: name, namespace: parent)
81
87
  end
82
88
 
@@ -88,14 +94,13 @@ module RBS
88
94
  end
89
95
  end
90
96
 
91
-
92
97
  def ascend
93
98
  if block_given?
94
99
  current = self
95
100
 
96
101
  until current.empty?
97
102
  yield current
98
- current = current.parent
103
+ current = _ = current.parent
99
104
  end
100
105
 
101
106
  yield current
@@ -107,3 +112,9 @@ module RBS
107
112
  end
108
113
  end
109
114
  end
115
+
116
+ module Kernel
117
+ def Namespace(name)
118
+ RBS::Namespace.parse(name)
119
+ end
120
+ end
@@ -435,14 +435,6 @@ rule
435
435
  method_member:
436
436
  annotations attributes overload kDEF method_kind def_name method_types {
437
437
  location = val[3].location + val[6].last.location
438
- types = val[6].map do |type|
439
- case type
440
- when LocatedValue
441
- type.value
442
- else
443
- type
444
- end
445
- end
446
438
 
447
439
  last_type = val[6].last
448
440
  if last_type.is_a?(LocatedValue) && last_type.value == :dot3
@@ -458,16 +450,14 @@ rule
458
450
  types: val[6],
459
451
  annotations: val[0],
460
452
  location: location,
461
- comment: leading_comment(val[0].first&.location || val[1].first&.location || val[2]&.location || val[3].location),
462
- attributes: val[1].map(&:value),
453
+ comment: leading_comment(val[0].first&.location || val[2]&.location || val[3].location),
463
454
  overload: overload || !!val[2]
464
455
  )
465
456
  }
466
457
 
467
458
  attributes:
468
- { result = [] }
469
459
  | attributes kINCOMPATIBLE {
470
- result = val[0].push(val[1])
460
+ RBS.logger.warn "`incompatible` method attribute is deprecated and ignored."
471
461
  }
472
462
 
473
463
  method_kind:
@@ -1164,15 +1154,13 @@ def leading_comment(location)
1164
1154
  end
1165
1155
 
1166
1156
  def push_comment(string, location)
1167
- new_comment = AST::Comment.new(string: string+"\n", location: location)
1168
-
1169
- if (prev_comment = leading_comment(location)) && prev_comment.location.start_column == location.start_column
1170
- @comments.delete prev_comment.location.end_line
1171
- new_comment = AST::Comment.new(string: prev_comment.string + new_comment.string,
1172
- location: prev_comment.location + new_comment.location)
1157
+ if (comment = leading_comment(location)) && comment.location.start_column == location.start_column
1158
+ comment.concat(string: "#{string}\n", location: location)
1159
+ @comments[comment.location.end_line] = comment
1160
+ else
1161
+ new_comment = AST::Comment.new(string: "#{string}\n", location: location)
1162
+ @comments[new_comment.location.end_line] = new_comment
1173
1163
  end
1174
-
1175
- @comments[new_comment.location.end_line] = new_comment
1176
1164
  end
1177
1165
 
1178
1166
  def new_token(type, value = input.matched)
@@ -36,7 +36,7 @@ module RBS
36
36
  tokens.each.with_object({}) do |token, hash|
37
37
  if token[1] == :on_comment
38
38
  line = token[0][0]
39
- body = token[2][2..]
39
+ body = token[2][2..-1]
40
40
 
41
41
  body = "\n" if body.empty?
42
42
 
@@ -130,7 +130,6 @@ module RBS
130
130
  types: types,
131
131
  kind: kind,
132
132
  comment: comments[node.first_lineno - 1],
133
- attributes: [],
134
133
  overload: false
135
134
  )
136
135
 
@@ -354,7 +353,6 @@ module RBS
354
353
  Types::Bases::Nil.new(location: nil)
355
354
  when :LIT
356
355
  lit = node.children[0]
357
- name = lit.class.name
358
356
  case lit
359
357
  when Symbol
360
358
  if lit.match?(/\A[ -~]+\z/)
@@ -365,7 +363,7 @@ module RBS
365
363
  when Integer
366
364
  Types::Literal.new(literal: lit, location: nil)
367
365
  else
368
- type_name = TypeName.new(name: name, namespace: Namespace.root)
366
+ type_name = TypeName.new(name: lit.class.name.to_sym, namespace: Namespace.root)
369
367
  Types::ClassInstance.new(name: type_name, args: [], location: nil)
370
368
  end
371
369
  when :ZLIST, :ZARRAY
@@ -421,7 +419,7 @@ module RBS
421
419
 
422
420
  types = types.map do |t|
423
421
  if t.is_a?(Types::Literal)
424
- type_name = TypeName.new(name: t.literal.class.name, namespace: Namespace.root)
422
+ type_name = TypeName.new(name: t.literal.class.name.to_sym, namespace: Namespace.root)
425
423
  Types::ClassInstance.new(name: type_name, args: [], location: nil)
426
424
  else
427
425
  t
@@ -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)
@@ -7,6 +7,7 @@ module RBS
7
7
  OPERATORS = {
8
8
  :== => "eqeq",
9
9
  :=== => "eqeqeq",
10
+ :!= => "noteq",
10
11
  :+ => "plus",
11
12
  :- => "minus",
12
13
  :* => "star",
@@ -9,21 +9,26 @@ logger = Logger.new(STDERR)
9
9
 
10
10
  begin
11
11
  opts = Shellwords.shellsplit(ENV["RBS_TEST_OPT"] || "-I sig")
12
- filter = ENV.fetch('RBS_TEST_TARGET').split(',').map! { |e| e.strip }
12
+ filter = ENV.fetch('RBS_TEST_TARGET', "").split(',').map! { |e| e.strip }
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
19
- rescue Exception => e
20
- raise e.message
21
+ end
22
+
23
+ if filter.empty?
21
24
  STDERR.puts "rbs/test/setup handles the following environment variables:"
22
25
  STDERR.puts " [REQUIRED] RBS_TEST_TARGET: test target class name, `Foo::Bar,Foo::Baz` for each class or `Foo::*` for all classes under `Foo`"
23
26
  STDERR.puts " [OPTIONAL] RBS_TEST_SKIP: skip testing classes"
24
27
  STDERR.puts " [OPTIONAL] RBS_TEST_OPT: options for signatures (`-r` for libraries or `-I` for signatures)"
25
28
  STDERR.puts " [OPTIONAL] RBS_TEST_LOGLEVEL: one of debug|info|warn|error|fatal (defaults to info)"
26
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"
27
32
  exit 1
28
33
  end
29
34
 
@@ -50,16 +55,16 @@ end
50
55
 
51
56
  tester = RBS::Test::Tester.new(env: env)
52
57
 
58
+ module_name = Module.instance_method(:name)
59
+
53
60
  TracePoint.trace :end do |tp|
54
- class_name = tp.self.name&.yield_self {|name| to_absolute_typename name }
61
+ class_name = module_name.bind(tp.self).call&.yield_self {|name| to_absolute_typename name }
55
62
 
56
63
  if class_name
57
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) }
58
- if tester.checkers.none? {|hook| hook.klass == tp.self }
59
- if env.class_decls.key?(class_name)
60
- logger.info "Setting up hooks for #{class_name}"
61
- tester.install!(tp.self, sample_size: sample_size)
62
- end
65
+ if env.class_decls.key?(class_name)
66
+ logger.info "Setting up hooks for #{class_name}"
67
+ tester.install!(tp.self, sample_size: sample_size, unchecked_classes: unchecked_classes)
63
68
  end
64
69
  end
65
70
  end
@@ -67,8 +72,8 @@ end
67
72
 
68
73
  at_exit do
69
74
  if $!.nil? || $!.is_a?(SystemExit) && $!.success?
70
- logger.warn "No type checker was installed! " if tester.checkers.empty?
75
+ if tester.targets.empty?
76
+ logger.debug { "No type checker was installed!" }
77
+ end
71
78
  end
72
79
  end
73
-
74
-