rbs 3.3.2 → 3.4.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) 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 +50 -0
  6. data/Gemfile +1 -1
  7. data/Gemfile.lock +11 -11
  8. data/Steepfile +2 -2
  9. data/core/array.rbs +19 -49
  10. data/core/basic_object.rbs +2 -2
  11. data/core/comparable.rbs +17 -8
  12. data/core/complex.rbs +82 -43
  13. data/core/data.rbs +2 -4
  14. data/core/dir.rbs +635 -295
  15. data/core/enumerable.rbs +11 -18
  16. data/core/enumerator.rbs +37 -31
  17. data/core/errors.rbs +4 -0
  18. data/core/false_class.rbs +34 -15
  19. data/core/fiber.rbs +23 -0
  20. data/core/file.rbs +329 -120
  21. data/core/float.rbs +17 -32
  22. data/core/gc.rbs +17 -11
  23. data/core/hash.rbs +22 -44
  24. data/core/integer.rbs +82 -113
  25. data/core/io/buffer.rbs +90 -47
  26. data/core/io.rbs +39 -116
  27. data/core/kernel.rbs +442 -489
  28. data/core/match_data.rbs +55 -56
  29. data/core/module.rbs +45 -1
  30. data/core/nil_class.rbs +98 -35
  31. data/core/numeric.rbs +22 -32
  32. data/core/object_space/weak_key_map.rbs +102 -0
  33. data/core/process.rbs +1242 -655
  34. data/core/ractor.rbs +139 -120
  35. data/core/range.rbs +100 -4
  36. data/core/rational.rbs +0 -4
  37. data/core/rbs/unnamed/argf.rbs +16 -8
  38. data/core/rbs/unnamed/env_class.rbs +0 -24
  39. data/core/refinement.rbs +8 -0
  40. data/core/regexp.rbs +1149 -598
  41. data/core/ruby_vm.rbs +126 -12
  42. data/core/rubygems/platform.rbs +9 -0
  43. data/core/rubygems/rubygems.rbs +1 -1
  44. data/core/rubygems/version.rbs +5 -1
  45. data/core/set.rbs +20 -22
  46. data/core/signal.rbs +4 -4
  47. data/core/string.rbs +283 -230
  48. data/core/string_io.rbs +2 -14
  49. data/core/struct.rbs +404 -24
  50. data/core/symbol.rbs +1 -19
  51. data/core/thread.rbs +29 -12
  52. data/core/time.rbs +227 -104
  53. data/core/trace_point.rbs +2 -5
  54. data/core/true_class.rbs +54 -21
  55. data/core/warning.rbs +14 -11
  56. data/docs/data_and_struct.md +29 -0
  57. data/docs/syntax.md +3 -5
  58. data/docs/tools.md +1 -0
  59. data/ext/rbs_extension/lexer.c +643 -559
  60. data/ext/rbs_extension/lexer.re +5 -1
  61. data/ext/rbs_extension/parser.c +12 -3
  62. data/ext/rbs_extension/unescape.c +7 -47
  63. data/lib/rbs/cli/diff.rb +4 -1
  64. data/lib/rbs/cli/validate.rb +280 -0
  65. data/lib/rbs/cli.rb +2 -194
  66. data/lib/rbs/collection/config.rb +5 -6
  67. data/lib/rbs/collection/sources/git.rb +1 -1
  68. data/lib/rbs/collection.rb +1 -0
  69. data/lib/rbs/diff.rb +7 -4
  70. data/lib/rbs/errors.rb +11 -0
  71. data/lib/rbs/test/errors.rb +4 -1
  72. data/lib/rbs/test/guaranteed.rb +2 -3
  73. data/lib/rbs/test/type_check.rb +15 -10
  74. data/lib/rbs/test.rb +3 -3
  75. data/lib/rbs/types.rb +29 -0
  76. data/lib/rbs/unit_test/convertibles.rb +176 -0
  77. data/lib/rbs/unit_test/spy.rb +136 -0
  78. data/lib/rbs/unit_test/type_assertions.rb +341 -0
  79. data/lib/rbs/unit_test/with_aliases.rb +143 -0
  80. data/lib/rbs/unit_test.rb +6 -0
  81. data/lib/rbs/version.rb +1 -1
  82. data/sig/cli/validate.rbs +43 -0
  83. data/sig/diff.rbs +3 -1
  84. data/sig/errors.rbs +8 -0
  85. data/sig/rbs.rbs +1 -1
  86. data/sig/test/errors.rbs +52 -0
  87. data/sig/test/guranteed.rbs +9 -0
  88. data/sig/test/type_check.rbs +19 -0
  89. data/sig/test.rbs +82 -0
  90. data/sig/types.rbs +6 -1
  91. data/sig/unit_test/convertibles.rbs +154 -0
  92. data/sig/unit_test/spy.rbs +28 -0
  93. data/sig/unit_test/type_assertions.rbs +194 -0
  94. data/sig/unit_test/with_aliases.rbs +136 -0
  95. data/stdlib/base64/0/base64.rbs +307 -45
  96. data/stdlib/bigdecimal/0/big_decimal.rbs +35 -15
  97. data/stdlib/coverage/0/coverage.rbs +2 -2
  98. data/stdlib/csv/0/csv.rbs +25 -55
  99. data/stdlib/date/0/date.rbs +1 -43
  100. data/stdlib/date/0/date_time.rbs +1 -13
  101. data/stdlib/delegate/0/delegator.rbs +186 -0
  102. data/stdlib/delegate/0/kernel.rbs +47 -0
  103. data/stdlib/delegate/0/simple_delegator.rbs +98 -0
  104. data/stdlib/did_you_mean/0/did_you_mean.rbs +1 -1
  105. data/stdlib/erb/0/erb.rbs +2 -2
  106. data/stdlib/fileutils/0/fileutils.rbs +0 -19
  107. data/stdlib/io-console/0/io-console.rbs +12 -1
  108. data/stdlib/ipaddr/0/ipaddr.rbs +2 -1
  109. data/stdlib/json/0/json.rbs +320 -81
  110. data/stdlib/logger/0/logger.rbs +9 -5
  111. data/stdlib/monitor/0/monitor.rbs +78 -0
  112. data/stdlib/net-http/0/net-http.rbs +1880 -543
  113. data/stdlib/objspace/0/objspace.rbs +19 -13
  114. data/stdlib/openssl/0/openssl.rbs +508 -127
  115. data/stdlib/optparse/0/optparse.rbs +25 -11
  116. data/stdlib/pathname/0/pathname.rbs +1 -1
  117. data/stdlib/pp/0/pp.rbs +2 -5
  118. data/stdlib/prettyprint/0/prettyprint.rbs +2 -2
  119. data/stdlib/pstore/0/pstore.rbs +2 -4
  120. data/stdlib/rdoc/0/comment.rbs +1 -2
  121. data/stdlib/resolv/0/resolv.rbs +4 -2
  122. data/stdlib/socket/0/socket.rbs +2 -2
  123. data/stdlib/socket/0/unix_socket.rbs +2 -2
  124. data/stdlib/strscan/0/string_scanner.rbs +3 -2
  125. data/stdlib/tempfile/0/tempfile.rbs +1 -1
  126. data/stdlib/uri/0/common.rbs +245 -123
  127. metadata +23 -4
  128. 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'