rbs 3.3.2 → 3.4.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 (132) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/comments.yml +2 -5
  3. data/.github/workflows/ruby.yml +7 -8
  4. data/.github/workflows/typecheck.yml +37 -0
  5. data/CHANGELOG.md +65 -0
  6. data/Gemfile +1 -1
  7. data/Gemfile.lock +11 -11
  8. data/README.md +1 -0
  9. data/Rakefile +2 -2
  10. data/Steepfile +2 -2
  11. data/core/array.rbs +19 -49
  12. data/core/basic_object.rbs +2 -2
  13. data/core/comparable.rbs +17 -8
  14. data/core/complex.rbs +82 -43
  15. data/core/data.rbs +2 -4
  16. data/core/dir.rbs +635 -295
  17. data/core/enumerable.rbs +11 -18
  18. data/core/enumerator.rbs +37 -31
  19. data/core/errors.rbs +4 -0
  20. data/core/false_class.rbs +34 -15
  21. data/core/fiber.rbs +23 -0
  22. data/core/file.rbs +329 -120
  23. data/core/float.rbs +17 -32
  24. data/core/gc.rbs +17 -11
  25. data/core/hash.rbs +22 -44
  26. data/core/integer.rbs +82 -113
  27. data/core/io/buffer.rbs +90 -47
  28. data/core/io.rbs +54 -121
  29. data/core/kernel.rbs +442 -489
  30. data/core/match_data.rbs +55 -56
  31. data/core/module.rbs +45 -1
  32. data/core/nil_class.rbs +98 -35
  33. data/core/numeric.rbs +22 -32
  34. data/core/object_space/weak_key_map.rbs +102 -0
  35. data/core/process.rbs +1242 -655
  36. data/core/ractor.rbs +139 -120
  37. data/core/range.rbs +100 -4
  38. data/core/rational.rbs +0 -4
  39. data/core/rbs/unnamed/argf.rbs +16 -8
  40. data/core/rbs/unnamed/env_class.rbs +0 -24
  41. data/core/refinement.rbs +8 -0
  42. data/core/regexp.rbs +1149 -598
  43. data/core/ruby_vm.rbs +126 -12
  44. data/core/rubygems/platform.rbs +9 -0
  45. data/core/rubygems/rubygems.rbs +1 -1
  46. data/core/rubygems/version.rbs +5 -1
  47. data/core/set.rbs +20 -22
  48. data/core/signal.rbs +4 -4
  49. data/core/string.rbs +283 -230
  50. data/core/string_io.rbs +2 -14
  51. data/core/struct.rbs +404 -24
  52. data/core/symbol.rbs +1 -19
  53. data/core/thread.rbs +29 -12
  54. data/core/time.rbs +227 -104
  55. data/core/trace_point.rbs +2 -5
  56. data/core/true_class.rbs +54 -21
  57. data/core/warning.rbs +14 -11
  58. data/docs/data_and_struct.md +29 -0
  59. data/docs/gem.md +58 -0
  60. data/docs/syntax.md +3 -5
  61. data/docs/tools.md +1 -0
  62. data/ext/rbs_extension/lexer.c +643 -559
  63. data/ext/rbs_extension/lexer.re +5 -1
  64. data/ext/rbs_extension/parser.c +12 -3
  65. data/ext/rbs_extension/unescape.c +7 -47
  66. data/lib/rbs/cli/diff.rb +4 -1
  67. data/lib/rbs/cli/validate.rb +280 -0
  68. data/lib/rbs/cli.rb +2 -194
  69. data/lib/rbs/collection/config.rb +5 -6
  70. data/lib/rbs/collection/sources/git.rb +1 -1
  71. data/lib/rbs/collection.rb +1 -0
  72. data/lib/rbs/diff.rb +7 -4
  73. data/lib/rbs/errors.rb +11 -0
  74. data/lib/rbs/test/errors.rb +10 -2
  75. data/lib/rbs/test/guaranteed.rb +2 -3
  76. data/lib/rbs/test/type_check.rb +15 -10
  77. data/lib/rbs/test.rb +3 -3
  78. data/lib/rbs/types.rb +29 -0
  79. data/lib/rbs/unit_test/convertibles.rb +176 -0
  80. data/lib/rbs/unit_test/spy.rb +136 -0
  81. data/lib/rbs/unit_test/type_assertions.rb +341 -0
  82. data/lib/rbs/unit_test/with_aliases.rb +143 -0
  83. data/lib/rbs/unit_test.rb +6 -0
  84. data/lib/rbs/version.rb +1 -1
  85. data/sig/cli/validate.rbs +43 -0
  86. data/sig/diff.rbs +3 -1
  87. data/sig/errors.rbs +8 -0
  88. data/sig/rbs.rbs +1 -1
  89. data/sig/test/errors.rbs +52 -0
  90. data/sig/test/guranteed.rbs +9 -0
  91. data/sig/test/type_check.rbs +19 -0
  92. data/sig/test.rbs +82 -0
  93. data/sig/types.rbs +6 -1
  94. data/sig/unit_test/convertibles.rbs +154 -0
  95. data/sig/unit_test/spy.rbs +28 -0
  96. data/sig/unit_test/type_assertions.rbs +194 -0
  97. data/sig/unit_test/with_aliases.rbs +136 -0
  98. data/stdlib/base64/0/base64.rbs +307 -45
  99. data/stdlib/bigdecimal/0/big_decimal.rbs +35 -15
  100. data/stdlib/coverage/0/coverage.rbs +2 -2
  101. data/stdlib/csv/0/csv.rbs +25 -55
  102. data/stdlib/date/0/date.rbs +1 -43
  103. data/stdlib/date/0/date_time.rbs +1 -13
  104. data/stdlib/delegate/0/delegator.rbs +186 -0
  105. data/stdlib/delegate/0/kernel.rbs +47 -0
  106. data/stdlib/delegate/0/simple_delegator.rbs +98 -0
  107. data/stdlib/did_you_mean/0/did_you_mean.rbs +1 -1
  108. data/stdlib/erb/0/erb.rbs +2 -2
  109. data/stdlib/fileutils/0/fileutils.rbs +0 -19
  110. data/stdlib/io-console/0/io-console.rbs +12 -1
  111. data/stdlib/ipaddr/0/ipaddr.rbs +2 -1
  112. data/stdlib/json/0/json.rbs +320 -81
  113. data/stdlib/logger/0/logger.rbs +9 -5
  114. data/stdlib/minitest/0/minitest/test/lifecycle_hooks.rbs +6 -6
  115. data/stdlib/monitor/0/monitor.rbs +78 -0
  116. data/stdlib/net-http/0/net-http.rbs +1880 -543
  117. data/stdlib/objspace/0/objspace.rbs +19 -13
  118. data/stdlib/openssl/0/openssl.rbs +508 -127
  119. data/stdlib/optparse/0/optparse.rbs +25 -11
  120. data/stdlib/pathname/0/pathname.rbs +1 -1
  121. data/stdlib/pp/0/pp.rbs +2 -5
  122. data/stdlib/prettyprint/0/prettyprint.rbs +2 -2
  123. data/stdlib/pstore/0/pstore.rbs +2 -4
  124. data/stdlib/rdoc/0/comment.rbs +1 -2
  125. data/stdlib/resolv/0/resolv.rbs +4 -2
  126. data/stdlib/socket/0/socket.rbs +2 -2
  127. data/stdlib/socket/0/unix_socket.rbs +2 -2
  128. data/stdlib/strscan/0/string_scanner.rbs +3 -2
  129. data/stdlib/tempfile/0/tempfile.rbs +1 -1
  130. data/stdlib/uri/0/common.rbs +245 -123
  131. metadata +24 -4
  132. data/lib/rbs/test/spy.rb +0 -6
@@ -97,7 +97,11 @@ start:
97
97
  "as" { return next_token(state, kAS); }
98
98
  "__todo__" { return next_token(state, k__TODO__); }
99
99
 
100
- dqstring = ["] ("\\"[abefnrstv"\\] | [^"\\\x00])* ["];
100
+ unicode_char = "\\u" [0-9a-fA-F]{4};
101
+ oct_char = "\\x" [0-9a-f]{1,2};
102
+ hex_char = "\\" [0-7]{1,3};
103
+
104
+ dqstring = ["] (unicode_char | oct_char | hex_char | "\\" [^xu] | [^\\"\x00])* ["];
101
105
  sqstring = ['] ("\\"['\\] | [^'\x00])* ['];
102
106
 
103
107
  dqstring { return next_token(state, tDQSTRING); }
@@ -276,6 +276,14 @@ static VALUE parse_function_param(parserstate *state) {
276
276
  param_range.start = type_range.start;
277
277
  param_range.end = name_range.end;
278
278
 
279
+ if (!is_keyword_token(state->current_token.type)) {
280
+ raise_syntax_error(
281
+ state,
282
+ state->current_token,
283
+ "unexpected token for function parameter name"
284
+ );
285
+ }
286
+
279
287
  VALUE name = rb_to_symbol(rbs_unquote_string(state, state->current_token.range, 0));
280
288
  VALUE location = rbs_new_location(state->buffer, param_range);
281
289
  rbs_loc *loc = rbs_check_location(location);
@@ -503,6 +511,7 @@ PARSE_KEYWORDS:
503
511
 
504
512
  case tUIDENT:
505
513
  case tLIDENT:
514
+ case tQIDENT:
506
515
  case tULIDENT:
507
516
  case tULLIDENT:
508
517
  case tBANGIDENT:
@@ -714,7 +723,7 @@ VALUE parse_record_attributes(parserstate *state) {
714
723
  case tINTEGER:
715
724
  case kTRUE:
716
725
  case kFALSE:
717
- key = rb_funcall(parse_type(state), rb_intern("literal"), 0);
726
+ key = rb_funcall(parse_simple(state), rb_intern("literal"), 0);
718
727
  break;
719
728
  default:
720
729
  raise_syntax_error(
@@ -1476,8 +1485,8 @@ InstanceSingletonKind parse_instance_singleton_kind(parserstate *state, bool all
1476
1485
 
1477
1486
  /**
1478
1487
  * def_member ::= {kDEF} method_name `:` <method_types>
1479
- * | {kPRIVATE2} kDEF method_name `:` <method_types>
1480
- * | {kPUBLIC2} kDEF method_name `:` <method_types>
1488
+ * | {kPRIVATE} kDEF method_name `:` <method_types>
1489
+ * | {kPUBLIC} kDEF method_name `:` <method_types>
1481
1490
  *
1482
1491
  * method_types ::= {} <method_type>
1483
1492
  * | {} <`...`>
@@ -1,49 +1,5 @@
1
1
  #include "rbs_extension.h"
2
2
 
3
- static VALUE DQ_REGEXP = 0;
4
- static VALUE SQ_REGEXP = 0;
5
- static VALUE HASH = 0;
6
-
7
- static const char *dq_regexp_str = "\\\\[abefnrstv\"\\\\]";
8
- static const char *sq_regexp_str = "\\\\[\'\\\\]";
9
-
10
- static ID gsub = 0;
11
-
12
- void rbs_unescape_string(VALUE string, bool dq_string) {
13
- if (!DQ_REGEXP) {
14
- DQ_REGEXP = rb_reg_new(dq_regexp_str, strlen(dq_regexp_str), 0);
15
- rb_global_variable(&DQ_REGEXP);
16
- }
17
-
18
- if (!SQ_REGEXP) {
19
- SQ_REGEXP = rb_reg_new(sq_regexp_str, strlen(sq_regexp_str), 0);
20
- rb_global_variable(&SQ_REGEXP);
21
- }
22
-
23
- if (!gsub) {
24
- gsub = rb_intern("gsub!");
25
- }
26
-
27
- if (!HASH) {
28
- HASH = rb_hash_new();
29
- rb_global_variable(&HASH);
30
- rb_hash_aset(HASH, rb_str_new_literal("\\a"), rb_str_new_literal("\a"));
31
- rb_hash_aset(HASH, rb_str_new_literal("\\b"), rb_str_new_literal("\b"));
32
- rb_hash_aset(HASH, rb_str_new_literal("\\e"), rb_str_new_literal("\033"));
33
- rb_hash_aset(HASH, rb_str_new_literal("\\f"), rb_str_new_literal("\f"));
34
- rb_hash_aset(HASH, rb_str_new_literal("\\n"), rb_str_new_literal("\n"));
35
- rb_hash_aset(HASH, rb_str_new_literal("\\r"), rb_str_new_literal("\r"));
36
- rb_hash_aset(HASH, rb_str_new_literal("\\s"), rb_str_new_literal(" "));
37
- rb_hash_aset(HASH, rb_str_new_literal("\\t"), rb_str_new_literal("\t"));
38
- rb_hash_aset(HASH, rb_str_new_literal("\\v"), rb_str_new_literal("\v"));
39
- rb_hash_aset(HASH, rb_str_new_literal("\\\""), rb_str_new_literal("\""));
40
- rb_hash_aset(HASH, rb_str_new_literal("\\\'"), rb_str_new_literal("'"));
41
- rb_hash_aset(HASH, rb_str_new_literal("\\\\"), rb_str_new_literal("\\"));
42
- }
43
-
44
- rb_funcall(string, gsub, 2, dq_string ? DQ_REGEXP : SQ_REGEXP, HASH);
45
- }
46
-
47
3
  VALUE rbs_unquote_string(parserstate *state, range rg, int offset_bytes) {
48
4
  VALUE string = state->lexstate->string;
49
5
  rb_encoding *enc = rb_enc_get(string);
@@ -65,8 +21,12 @@ VALUE rbs_unquote_string(parserstate *state, range rg, int offset_bytes) {
65
21
  char *buffer = RSTRING_PTR(state->lexstate->string) + rg.start.byte_pos + offset_bytes;
66
22
  VALUE str = rb_enc_str_new(buffer, byte_length, enc);
67
23
 
68
- rbs_unescape_string(str, first_char == '\"');
69
-
70
- return str;
24
+ return rb_funcall(
25
+ RBS_Types_Literal,
26
+ rb_intern("unescape_string"),
27
+ 2,
28
+ str,
29
+ first_char == '\"' ? Qtrue : Qfalse
30
+ );
71
31
  }
72
32
 
data/lib/rbs/cli/diff.rb CHANGED
@@ -13,6 +13,7 @@ module RBS
13
13
  library_options = library_options
14
14
  before_path = []
15
15
  after_path = []
16
+ detail = false
16
17
 
17
18
  opt = OptionParser.new do |o|
18
19
  o.banner = <<~HELP
@@ -35,6 +36,7 @@ module RBS
35
36
  o.on("--type-name NAME") { |arg| type_name = arg }
36
37
  o.on("--before DIR") { |arg| before_path << arg }
37
38
  o.on("--after DIR") { |arg| after_path << arg }
39
+ o.on("--[no-]detail") { |arg| detail = arg }
38
40
  end
39
41
  opt.parse!(argv)
40
42
 
@@ -47,7 +49,8 @@ module RBS
47
49
  type_name: TypeName(type_name).absolute!,
48
50
  library_options: library_options,
49
51
  after_path: after_path,
50
- before_path: before_path
52
+ before_path: before_path,
53
+ detail: detail,
51
54
  )
52
55
  end
53
56
 
@@ -0,0 +1,280 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBS
4
+ class CLI
5
+ class Validate
6
+ class Errors
7
+ def initialize(limit:, exit_error:)
8
+ @limit = limit
9
+ @exit_error = exit_error
10
+ @errors = []
11
+ @has_syntax_error = false
12
+ end
13
+
14
+ def add(error)
15
+ if error.instance_of?(WillSyntaxError)
16
+ RBS.logger.warn(build_message(error))
17
+ @has_syntax_error = true
18
+ else
19
+ @errors << error
20
+ end
21
+ finish if @limit == 1
22
+ end
23
+
24
+ def finish
25
+ if @errors.empty?
26
+ if @exit_error && @has_syntax_error
27
+ exit 1
28
+ else
29
+ # success
30
+ end
31
+ else
32
+ @errors.each do |error|
33
+ RBS.logger.error(build_message(error))
34
+ end
35
+ exit 1
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def build_message(error)
42
+ if error.respond_to?(:detailed_message)
43
+ highlight = RBS.logger_output ? RBS.logger_output.tty? : true
44
+ error.detailed_message(highlight: highlight)
45
+ else
46
+ "#{error.message} (#{error.class})"
47
+ end
48
+ end
49
+ end
50
+
51
+ def initialize(args:, options:)
52
+ loader = options.loader()
53
+ @env = Environment.from_loader(loader).resolve_type_names
54
+ @builder = DefinitionBuilder.new(env: @env)
55
+ @validator = Validator.new(env: @env, resolver: Resolver::TypeNameResolver.new(@env))
56
+ exit_error = false
57
+ limit = nil #: Integer?
58
+ OptionParser.new do |opts|
59
+ opts.banner = <<EOU
60
+ Usage: rbs validate
61
+
62
+ Validate RBS files. It ensures the type names in RBS files are present and the type applications have correct arity.
63
+
64
+ Examples:
65
+
66
+ $ rbs validate
67
+ EOU
68
+
69
+ opts.on("--silent") do
70
+ RBS.print_warning { "`--silent` option is deprecated." }
71
+ end
72
+ opts.on("--[no-]exit-error-on-syntax-error", "exit(1) if syntax error is detected") {|bool|
73
+ exit_error = bool
74
+ }
75
+ opts.on("--fail-fast", "Exit immediately as soon as a validation error is found.") do |arg|
76
+ limit = 1
77
+ end
78
+ end.parse!(args)
79
+
80
+ @errors = Errors.new(limit: limit, exit_error: exit_error)
81
+ end
82
+
83
+ def run
84
+ validate_class_module_definition
85
+ validate_class_module_alias_definition
86
+ validate_interface
87
+ validate_constant
88
+ validate_global
89
+ validate_type_alias
90
+
91
+ @errors.finish
92
+ end
93
+
94
+ private
95
+
96
+ def validate_class_module_definition
97
+ @env.class_decls.each do |name, decl|
98
+ RBS.logger.info "Validating class/module definition: `#{name}`..."
99
+ @builder.build_instance(name).each_type do |type|
100
+ @validator.validate_type type, context: nil
101
+ rescue BaseError => error
102
+ @errors.add(error)
103
+ end
104
+ @builder.build_singleton(name).each_type do |type|
105
+ @validator.validate_type type, context: nil
106
+ rescue BaseError => error
107
+ @errors.add(error)
108
+ end
109
+
110
+ case decl
111
+ when Environment::ClassEntry
112
+ decl.decls.each do |decl|
113
+ if super_class = decl.decl.super_class
114
+ super_class.args.each do |arg|
115
+ void_type_context_validator(arg, true)
116
+ no_self_type_validator(arg)
117
+ no_classish_type_validator(arg)
118
+ end
119
+ end
120
+ end
121
+ when Environment::ModuleEntry
122
+ decl.decls.each do |decl|
123
+ decl.decl.self_types.each do |self_type|
124
+ self_type.args.each do |arg|
125
+ void_type_context_validator(arg, true)
126
+ no_self_type_validator(arg)
127
+ no_classish_type_validator(arg)
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ d = decl.primary.decl
134
+
135
+ @validator.validate_type_params(
136
+ d.type_params,
137
+ type_name: name,
138
+ location: d.location&.aref(:type_params)
139
+ )
140
+
141
+ d.type_params.each do |param|
142
+ if ub = param.upper_bound
143
+ void_type_context_validator(ub)
144
+ no_self_type_validator(ub)
145
+ no_classish_type_validator(ub)
146
+ end
147
+ end
148
+
149
+ decl.decls.each do |d|
150
+ d.decl.each_member do |member|
151
+ case member
152
+ when AST::Members::MethodDefinition
153
+ @validator.validate_method_definition(member, type_name: name)
154
+ member.overloads.each do |ov|
155
+ void_type_context_validator(ov.method_type)
156
+ end
157
+ when AST::Members::Attribute
158
+ void_type_context_validator(member.type)
159
+ when AST::Members::Mixin
160
+ member.args.each do |arg|
161
+ no_self_type_validator(arg)
162
+ unless arg.is_a?(Types::Bases::Void)
163
+ void_type_context_validator(arg, true)
164
+ end
165
+ end
166
+ when AST::Members::Var
167
+ void_type_context_validator(member.type)
168
+ if member.is_a?(AST::Members::ClassVariable)
169
+ no_self_type_validator(member.type)
170
+ end
171
+ end
172
+ end
173
+ end
174
+ rescue BaseError => error
175
+ @errors.add(error)
176
+ end
177
+ end
178
+
179
+ def validate_class_module_alias_definition
180
+ @env.class_alias_decls.each do |name, entry|
181
+ RBS.logger.info "Validating class/module alias definition: `#{name}`..."
182
+ @validator.validate_class_alias(entry: entry)
183
+ rescue BaseError => error
184
+ @errors.add error
185
+ end
186
+ end
187
+
188
+ def validate_interface
189
+ @env.interface_decls.each do |name, decl|
190
+ RBS.logger.info "Validating interface: `#{name}`..."
191
+ @builder.build_interface(name).each_type do |type|
192
+ @validator.validate_type type, context: nil
193
+ end
194
+
195
+ @validator.validate_type_params(
196
+ decl.decl.type_params,
197
+ type_name: name,
198
+ location: decl.decl.location&.aref(:type_params)
199
+ )
200
+
201
+ decl.decl.members.each do |member|
202
+ case member
203
+ when AST::Members::MethodDefinition
204
+ @validator.validate_method_definition(member, type_name: name)
205
+ member.overloads.each do |ov|
206
+ void_type_context_validator(ov.method_type)
207
+ no_classish_type_validator(ov.method_type)
208
+ end
209
+ end
210
+ end
211
+ rescue BaseError => error
212
+ @errors.add(error)
213
+ end
214
+ end
215
+
216
+ def validate_constant
217
+ @env.constant_decls.each do |name, const|
218
+ RBS.logger.info "Validating constant: `#{name}`..."
219
+ @validator.validate_type const.decl.type, context: const.context
220
+ @builder.ensure_namespace!(name.namespace, location: const.decl.location)
221
+ no_self_type_validator(const.decl.type)
222
+ no_classish_type_validator(const.decl.type)
223
+ void_type_context_validator(const.decl.type)
224
+ rescue BaseError => error
225
+ @errors.add(error)
226
+ end
227
+ end
228
+
229
+ def validate_global
230
+ @env.global_decls.each do |name, global|
231
+ RBS.logger.info "Validating global: `#{name}`..."
232
+ @validator.validate_type global.decl.type, context: nil
233
+ no_self_type_validator(global.decl.type)
234
+ no_classish_type_validator(global.decl.type)
235
+ void_type_context_validator(global.decl.type)
236
+ rescue BaseError => error
237
+ @errors.add(error)
238
+ end
239
+ end
240
+
241
+ def validate_type_alias
242
+ @env.type_alias_decls.each do |name, decl|
243
+ RBS.logger.info "Validating alias: `#{name}`..."
244
+ @builder.expand_alias1(name).tap do |type|
245
+ @validator.validate_type type, context: nil
246
+ end
247
+ @validator.validate_type_alias(entry: decl)
248
+ no_self_type_validator(decl.decl.type)
249
+ no_classish_type_validator(decl.decl.type)
250
+ void_type_context_validator(decl.decl.type)
251
+ rescue BaseError => error
252
+ @errors.add(error)
253
+ end
254
+ end
255
+
256
+ private
257
+
258
+ def no_self_type_validator(type)
259
+ if type.has_self_type?
260
+ @errors.add WillSyntaxError.new("`self` type is not allowed in this context", location: type.location)
261
+ end
262
+ end
263
+
264
+ def no_classish_type_validator(type)
265
+ if type.has_classish_type?
266
+ @errors.add WillSyntaxError.new("`instance` or `class` type is not allowed in this context", location: type.location)
267
+ end
268
+ end
269
+
270
+ def void_type_context_validator(type, allowed_here = false)
271
+ if allowed_here
272
+ return if type.is_a?(Types::Bases::Void)
273
+ end
274
+ if type.with_nonreturn_void?
275
+ @errors.add WillSyntaxError.new("`void` type is only allowed in return type or generics parameter", location: type.location)
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end
data/lib/rbs/cli.rb CHANGED
@@ -10,6 +10,7 @@ module RBS
10
10
  class CLI
11
11
  autoload :ColoredIO, 'rbs/cli/colored_io'
12
12
  autoload :Diff, 'rbs/cli/diff'
13
+ autoload :Validate, 'rbs/cli/validate'
13
14
 
14
15
  class LibraryOptions
15
16
  attr_accessor :core_root
@@ -444,200 +445,7 @@ EOU
444
445
  end
445
446
 
446
447
  def run_validate(args, options)
447
- stdout = stdout()
448
- exit_error = false
449
-
450
- OptionParser.new do |opts|
451
- opts.banner = <<EOU
452
- Usage: rbs validate
453
-
454
- Validate RBS files. It ensures the type names in RBS files are present and the type applications have correct arity.
455
-
456
- Examples:
457
-
458
- $ rbs validate
459
- EOU
460
-
461
- opts.on("--silent") do
462
- stdout = StringIO.new
463
- end
464
- opts.on("--[no-]exit-error-on-syntax-error", "exit(1) if syntax error is detected") {|bool|
465
- exit_error = bool
466
- }
467
- end.parse!(args)
468
-
469
- loader = options.loader()
470
- env = Environment.from_loader(loader).resolve_type_names
471
-
472
- builder = DefinitionBuilder.new(env: env)
473
- validator = Validator.new(env: env, resolver: Resolver::TypeNameResolver.new(env))
474
-
475
- syntax_errors = [] #: Array[String]
476
-
477
- no_self_type_validator = ->(type) {
478
- # @type var type: Types::t | MethodType
479
- if type.has_self_type?
480
- syntax_errors << "#{type.location}: `self` type is not allowed in this context"
481
- end
482
- }
483
-
484
- no_classish_type_validator = ->(type) {
485
- # @type var type: Types::t | MethodType
486
- if type.has_classish_type?
487
- syntax_errors << "#{type.location}: `instance` or `class` type is not allowed in this context"
488
- end
489
- }
490
-
491
- void_type_context_validator = ->(type, allowed_here = false) {
492
- # @type var type: Types::t | MethodType
493
- if allowed_here
494
- next if type.is_a?(Types::Bases::Void)
495
- end
496
- if type.with_nonreturn_void?
497
- syntax_errors << "#{type.location}: `void` type is only allowed in return type or generics parameter"
498
- end
499
- }
500
-
501
- env.class_decls.each do |name, decl|
502
- stdout.puts "Validating class/module definition: `#{name}`..."
503
- builder.build_instance(name).each_type do |type|
504
- validator.validate_type type, context: nil
505
- end
506
- builder.build_singleton(name).each_type do |type|
507
- validator.validate_type type, context: nil
508
- end
509
-
510
- case decl
511
- when Environment::ClassEntry
512
- decl.decls.each do |decl|
513
- if super_class = decl.decl.super_class
514
- super_class.args.each do |arg|
515
- void_type_context_validator[arg, true]
516
- no_self_type_validator[arg]
517
- no_classish_type_validator[arg]
518
- end
519
- end
520
- end
521
- when Environment::ModuleEntry
522
- decl.decls.each do |decl|
523
- decl.decl.self_types.each do |self_type|
524
- self_type.args.each do |arg|
525
- void_type_context_validator[arg, true]
526
- no_self_type_validator[arg]
527
- no_classish_type_validator[arg]
528
- end
529
- end
530
- end
531
- end
532
-
533
- d = decl.primary.decl
534
-
535
- validator.validate_type_params(
536
- d.type_params,
537
- type_name: name,
538
- location: d.location&.aref(:type_params)
539
- )
540
-
541
- d.type_params.each do |param|
542
- if ub = param.upper_bound
543
- void_type_context_validator[ub]
544
- no_self_type_validator[ub]
545
- no_classish_type_validator[ub]
546
- end
547
- end
548
-
549
- decl.decls.each do |d|
550
- d.decl.each_member do |member|
551
- case member
552
- when AST::Members::MethodDefinition
553
- validator.validate_method_definition(member, type_name: name)
554
- member.overloads.each do |ov|
555
- void_type_context_validator[ov.method_type]
556
- end
557
- when AST::Members::Attribute
558
- void_type_context_validator[member.type]
559
- when AST::Members::Mixin
560
- member.args.each do |arg|
561
- no_self_type_validator[arg]
562
- unless arg.is_a?(Types::Bases::Void)
563
- void_type_context_validator[arg, true]
564
- end
565
- end
566
- when AST::Members::Var
567
- void_type_context_validator[member.type]
568
- if member.is_a?(AST::Members::ClassVariable)
569
- no_self_type_validator[member.type]
570
- end
571
- end
572
- end
573
- end
574
- end
575
-
576
- env.class_alias_decls.each do |name, entry|
577
- stdout.puts "Validating class/module alias definition: `#{name}`..."
578
- validator.validate_class_alias(entry: entry)
579
- end
580
-
581
- env.interface_decls.each do |name, decl|
582
- stdout.puts "Validating interface: `#{name}`..."
583
- builder.build_interface(name).each_type do |type|
584
- validator.validate_type type, context: nil
585
- end
586
-
587
- validator.validate_type_params(
588
- decl.decl.type_params,
589
- type_name: name,
590
- location: decl.decl.location&.aref(:type_params)
591
- )
592
-
593
- decl.decl.members.each do |member|
594
- case member
595
- when AST::Members::MethodDefinition
596
- validator.validate_method_definition(member, type_name: name)
597
- member.overloads.each do |ov|
598
- void_type_context_validator[ov.method_type]
599
- no_classish_type_validator[ov.method_type]
600
- end
601
- end
602
- end
603
- end
604
-
605
- env.constant_decls.each do |name, const|
606
- stdout.puts "Validating constant: `#{name}`..."
607
- validator.validate_type const.decl.type, context: const.context
608
- builder.ensure_namespace!(name.namespace, location: const.decl.location)
609
- no_self_type_validator[const.decl.type]
610
- no_classish_type_validator[const.decl.type]
611
- void_type_context_validator[const.decl.type]
612
- end
613
-
614
- env.global_decls.each do |name, global|
615
- stdout.puts "Validating global: `#{name}`..."
616
- validator.validate_type global.decl.type, context: nil
617
- no_self_type_validator[global.decl.type]
618
- no_classish_type_validator[global.decl.type]
619
- void_type_context_validator[global.decl.type]
620
- end
621
-
622
- env.type_alias_decls.each do |name, decl|
623
- stdout.puts "Validating alias: `#{name}`..."
624
- builder.expand_alias1(name).tap do |type|
625
- validator.validate_type type, context: nil
626
- end
627
- validator.validate_type_alias(entry: decl)
628
- no_self_type_validator[decl.decl.type]
629
- no_classish_type_validator[decl.decl.type]
630
- void_type_context_validator[decl.decl.type]
631
- end
632
-
633
- unless syntax_errors.empty?
634
- syntax_errors.sort!
635
- syntax_errors.uniq!
636
- syntax_errors.each do |message|
637
- self.stdout.puts message
638
- end
639
- exit 1 if exit_error
640
- end
448
+ CLI::Validate.new(args: args, options: options).run
641
449
  end
642
450
 
643
451
  def run_constant(args, options)
@@ -64,12 +64,11 @@ module RBS
64
64
  end
65
65
 
66
66
  def sources
67
- @sources ||= (
68
- @data['sources']
69
- .map { |c| Sources.from_config_entry(c, base_directory: @config_path.dirname) }
70
- .push(Sources::Stdlib.instance)
71
- .push(Sources::Rubygems.instance)
72
- )
67
+ @sources ||= [
68
+ Sources::Stdlib.instance,
69
+ Sources::Rubygems.instance,
70
+ *@data['sources'].map { |c| Sources.from_config_entry(c, base_directory: @config_path.dirname) }
71
+ ]
73
72
  end
74
73
 
75
74
  def gems
@@ -248,7 +248,7 @@ module RBS
248
248
  if gem_name
249
249
  versions[gem_name.to_s] ||= Set[]
250
250
 
251
- if version
251
+ if version && !version.basename.to_s.start_with?('_')
252
252
  versions[gem_name.to_s] << version.basename.to_s
253
253
  end
254
254
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'yaml'
4
4
 
5
+ require_relative './cli/colored_io'
5
6
  require_relative './collection/sources'
6
7
  require_relative './collection/config'
7
8
  require_relative './collection/config/lockfile'