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.
- checksums.yaml +4 -4
- data/.github/workflows/comments.yml +2 -5
- data/.github/workflows/ruby.yml +7 -8
- data/.github/workflows/typecheck.yml +37 -0
- data/CHANGELOG.md +65 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +11 -11
- data/README.md +1 -0
- data/Rakefile +2 -2
- data/Steepfile +2 -2
- data/core/array.rbs +19 -49
- data/core/basic_object.rbs +2 -2
- data/core/comparable.rbs +17 -8
- data/core/complex.rbs +82 -43
- data/core/data.rbs +2 -4
- data/core/dir.rbs +635 -295
- data/core/enumerable.rbs +11 -18
- data/core/enumerator.rbs +37 -31
- data/core/errors.rbs +4 -0
- data/core/false_class.rbs +34 -15
- data/core/fiber.rbs +23 -0
- data/core/file.rbs +329 -120
- data/core/float.rbs +17 -32
- data/core/gc.rbs +17 -11
- data/core/hash.rbs +22 -44
- data/core/integer.rbs +82 -113
- data/core/io/buffer.rbs +90 -47
- data/core/io.rbs +54 -121
- data/core/kernel.rbs +442 -489
- data/core/match_data.rbs +55 -56
- data/core/module.rbs +45 -1
- data/core/nil_class.rbs +98 -35
- data/core/numeric.rbs +22 -32
- data/core/object_space/weak_key_map.rbs +102 -0
- data/core/process.rbs +1242 -655
- data/core/ractor.rbs +139 -120
- data/core/range.rbs +100 -4
- data/core/rational.rbs +0 -4
- data/core/rbs/unnamed/argf.rbs +16 -8
- data/core/rbs/unnamed/env_class.rbs +0 -24
- data/core/refinement.rbs +8 -0
- data/core/regexp.rbs +1149 -598
- data/core/ruby_vm.rbs +126 -12
- data/core/rubygems/platform.rbs +9 -0
- data/core/rubygems/rubygems.rbs +1 -1
- data/core/rubygems/version.rbs +5 -1
- data/core/set.rbs +20 -22
- data/core/signal.rbs +4 -4
- data/core/string.rbs +283 -230
- data/core/string_io.rbs +2 -14
- data/core/struct.rbs +404 -24
- data/core/symbol.rbs +1 -19
- data/core/thread.rbs +29 -12
- data/core/time.rbs +227 -104
- data/core/trace_point.rbs +2 -5
- data/core/true_class.rbs +54 -21
- data/core/warning.rbs +14 -11
- data/docs/data_and_struct.md +29 -0
- data/docs/gem.md +58 -0
- data/docs/syntax.md +3 -5
- data/docs/tools.md +1 -0
- data/ext/rbs_extension/lexer.c +643 -559
- data/ext/rbs_extension/lexer.re +5 -1
- data/ext/rbs_extension/parser.c +12 -3
- data/ext/rbs_extension/unescape.c +7 -47
- data/lib/rbs/cli/diff.rb +4 -1
- data/lib/rbs/cli/validate.rb +280 -0
- data/lib/rbs/cli.rb +2 -194
- data/lib/rbs/collection/config.rb +5 -6
- data/lib/rbs/collection/sources/git.rb +1 -1
- data/lib/rbs/collection.rb +1 -0
- data/lib/rbs/diff.rb +7 -4
- data/lib/rbs/errors.rb +11 -0
- data/lib/rbs/test/errors.rb +10 -2
- data/lib/rbs/test/guaranteed.rb +2 -3
- data/lib/rbs/test/type_check.rb +15 -10
- data/lib/rbs/test.rb +3 -3
- data/lib/rbs/types.rb +29 -0
- data/lib/rbs/unit_test/convertibles.rb +176 -0
- data/lib/rbs/unit_test/spy.rb +136 -0
- data/lib/rbs/unit_test/type_assertions.rb +341 -0
- data/lib/rbs/unit_test/with_aliases.rb +143 -0
- data/lib/rbs/unit_test.rb +6 -0
- data/lib/rbs/version.rb +1 -1
- data/sig/cli/validate.rbs +43 -0
- data/sig/diff.rbs +3 -1
- data/sig/errors.rbs +8 -0
- data/sig/rbs.rbs +1 -1
- data/sig/test/errors.rbs +52 -0
- data/sig/test/guranteed.rbs +9 -0
- data/sig/test/type_check.rbs +19 -0
- data/sig/test.rbs +82 -0
- data/sig/types.rbs +6 -1
- data/sig/unit_test/convertibles.rbs +154 -0
- data/sig/unit_test/spy.rbs +28 -0
- data/sig/unit_test/type_assertions.rbs +194 -0
- data/sig/unit_test/with_aliases.rbs +136 -0
- data/stdlib/base64/0/base64.rbs +307 -45
- data/stdlib/bigdecimal/0/big_decimal.rbs +35 -15
- data/stdlib/coverage/0/coverage.rbs +2 -2
- data/stdlib/csv/0/csv.rbs +25 -55
- data/stdlib/date/0/date.rbs +1 -43
- data/stdlib/date/0/date_time.rbs +1 -13
- data/stdlib/delegate/0/delegator.rbs +186 -0
- data/stdlib/delegate/0/kernel.rbs +47 -0
- data/stdlib/delegate/0/simple_delegator.rbs +98 -0
- data/stdlib/did_you_mean/0/did_you_mean.rbs +1 -1
- data/stdlib/erb/0/erb.rbs +2 -2
- data/stdlib/fileutils/0/fileutils.rbs +0 -19
- data/stdlib/io-console/0/io-console.rbs +12 -1
- data/stdlib/ipaddr/0/ipaddr.rbs +2 -1
- data/stdlib/json/0/json.rbs +320 -81
- data/stdlib/logger/0/logger.rbs +9 -5
- data/stdlib/minitest/0/minitest/test/lifecycle_hooks.rbs +6 -6
- data/stdlib/monitor/0/monitor.rbs +78 -0
- data/stdlib/net-http/0/net-http.rbs +1880 -543
- data/stdlib/objspace/0/objspace.rbs +19 -13
- data/stdlib/openssl/0/openssl.rbs +508 -127
- data/stdlib/optparse/0/optparse.rbs +25 -11
- data/stdlib/pathname/0/pathname.rbs +1 -1
- data/stdlib/pp/0/pp.rbs +2 -5
- data/stdlib/prettyprint/0/prettyprint.rbs +2 -2
- data/stdlib/pstore/0/pstore.rbs +2 -4
- data/stdlib/rdoc/0/comment.rbs +1 -2
- data/stdlib/resolv/0/resolv.rbs +4 -2
- data/stdlib/socket/0/socket.rbs +2 -2
- data/stdlib/socket/0/unix_socket.rbs +2 -2
- data/stdlib/strscan/0/string_scanner.rbs +3 -2
- data/stdlib/tempfile/0/tempfile.rbs +1 -1
- data/stdlib/uri/0/common.rbs +245 -123
- metadata +24 -4
- data/lib/rbs/test/spy.rb +0 -6
data/ext/rbs_extension/lexer.re
CHANGED
|
@@ -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
|
-
|
|
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); }
|
data/ext/rbs_extension/parser.c
CHANGED
|
@@ -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(
|
|
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
|
-
* | {
|
|
1480
|
-
* | {
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|