rbs 0.4.0 → 0.5.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/ruby.yml +7 -1
- data/.gitignore +1 -1
- data/CHANGELOG.md +7 -0
- data/Gemfile +12 -0
- data/README.md +86 -47
- data/Rakefile +54 -21
- data/bin/rbs-prof +9 -0
- data/bin/run_in_md.rb +49 -0
- data/lib/rbs.rb +2 -0
- data/lib/rbs/ast/declarations.rb +62 -7
- data/lib/rbs/ast/members.rb +41 -17
- data/lib/rbs/cli.rb +299 -121
- data/lib/rbs/constant.rb +4 -4
- data/lib/rbs/constant_table.rb +50 -44
- data/lib/rbs/definition.rb +175 -59
- data/lib/rbs/definition_builder.rb +647 -603
- data/lib/rbs/environment.rb +338 -209
- data/lib/rbs/environment_walker.rb +14 -23
- data/lib/rbs/errors.rb +141 -3
- data/lib/rbs/parser.y +14 -9
- data/lib/rbs/prototype/rb.rb +100 -112
- data/lib/rbs/prototype/rbi.rb +4 -2
- data/lib/rbs/prototype/runtime.rb +10 -6
- data/lib/rbs/substitution.rb +8 -1
- data/lib/rbs/test/hook.rb +2 -2
- data/lib/rbs/test/setup.rb +3 -1
- data/lib/rbs/test/test_helper.rb +2 -5
- data/lib/rbs/test/type_check.rb +1 -2
- data/lib/rbs/type_name_resolver.rb +58 -0
- data/lib/rbs/types.rb +94 -2
- data/lib/rbs/validator.rb +51 -0
- data/lib/rbs/variance_calculator.rb +12 -2
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/writer.rb +125 -89
- data/rbs.gemspec +0 -10
- data/schema/decls.json +15 -0
- data/schema/members.json +3 -0
- data/stdlib/benchmark/benchmark.rbs +151 -151
- data/stdlib/builtin/enumerable.rbs +1 -1
- data/stdlib/builtin/file.rbs +0 -3
- data/stdlib/builtin/io.rbs +4 -4
- data/stdlib/builtin/thread.rbs +2 -2
- data/stdlib/csv/csv.rbs +4 -6
- data/stdlib/fiber/fiber.rbs +1 -1
- data/stdlib/json/json.rbs +1 -1
- data/stdlib/mutex_m/mutex_m.rbs +77 -0
- data/stdlib/pathname/pathname.rbs +6 -6
- data/stdlib/prime/integer-extension.rbs +1 -1
- data/stdlib/prime/prime.rbs +44 -44
- data/stdlib/tmpdir/tmpdir.rbs +1 -1
- metadata +8 -129
data/lib/rbs/prototype/rbi.rb
CHANGED
@@ -173,7 +173,8 @@ module RBS
|
|
173
173
|
types: types,
|
174
174
|
kind: :singleton,
|
175
175
|
comment: comment,
|
176
|
-
attributes: []
|
176
|
+
attributes: [],
|
177
|
+
overload: false
|
177
178
|
)
|
178
179
|
end
|
179
180
|
|
@@ -193,7 +194,8 @@ module RBS
|
|
193
194
|
types: types,
|
194
195
|
kind: :instance,
|
195
196
|
comment: comment,
|
196
|
-
attributes: []
|
197
|
+
attributes: [],
|
198
|
+
overload: false
|
197
199
|
)
|
198
200
|
end
|
199
201
|
|
@@ -128,7 +128,7 @@ module RBS
|
|
128
128
|
|
129
129
|
def merge_rbs(module_name, members, instance: nil, singleton: nil)
|
130
130
|
if merge
|
131
|
-
if env.
|
131
|
+
if env.class_decls[module_name.absolute!]
|
132
132
|
case
|
133
133
|
when instance
|
134
134
|
method = builder.build_instance(module_name.absolute!).methods[instance]
|
@@ -152,9 +152,10 @@ module RBS
|
|
152
152
|
},
|
153
153
|
kind: kind,
|
154
154
|
location: nil,
|
155
|
-
comment: method.
|
155
|
+
comment: method.comments[0],
|
156
156
|
annotations: method.annotations,
|
157
|
-
attributes: method.attributes
|
157
|
+
attributes: method.attributes,
|
158
|
+
overload: false
|
158
159
|
)
|
159
160
|
return
|
160
161
|
end
|
@@ -192,7 +193,8 @@ module RBS
|
|
192
193
|
location: nil,
|
193
194
|
comment: nil,
|
194
195
|
annotations: [],
|
195
|
-
attributes: []
|
196
|
+
attributes: [],
|
197
|
+
overload: false
|
196
198
|
)
|
197
199
|
end
|
198
200
|
else
|
@@ -225,7 +227,8 @@ module RBS
|
|
225
227
|
location: nil,
|
226
228
|
comment: nil,
|
227
229
|
annotations: [],
|
228
|
-
attributes: []
|
230
|
+
attributes: [],
|
231
|
+
overload: false
|
229
232
|
)
|
230
233
|
end
|
231
234
|
else
|
@@ -259,7 +262,8 @@ module RBS
|
|
259
262
|
location: nil,
|
260
263
|
comment: nil,
|
261
264
|
annotations: [],
|
262
|
-
attributes: []
|
265
|
+
attributes: [],
|
266
|
+
overload: false
|
263
267
|
)
|
264
268
|
end
|
265
269
|
else
|
data/lib/rbs/substitution.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module RBS
|
2
2
|
class Substitution
|
3
3
|
attr_reader :mapping
|
4
|
+
attr_accessor :instance_type
|
4
5
|
|
5
6
|
def initialize()
|
6
7
|
@mapping = {}
|
@@ -10,7 +11,7 @@ module RBS
|
|
10
11
|
mapping[from] = to
|
11
12
|
end
|
12
13
|
|
13
|
-
def self.build(variables, types, &block)
|
14
|
+
def self.build(variables, types, instance_type: Types::Bases::Instance.new(location: nil), &block)
|
14
15
|
unless variables.size == types.size
|
15
16
|
raise "Broken substitution: variables=#{variables}, types=#{types}"
|
16
17
|
end
|
@@ -22,6 +23,8 @@ module RBS
|
|
22
23
|
type = block_given? ? yield(t) : t
|
23
24
|
subst.add(from: v, to: type)
|
24
25
|
end
|
26
|
+
|
27
|
+
subst.instance_type = instance_type
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
@@ -29,6 +32,8 @@ module RBS
|
|
29
32
|
case ty
|
30
33
|
when Types::Variable
|
31
34
|
mapping[ty.name] || ty
|
35
|
+
when Types::Bases::Instance
|
36
|
+
instance_type
|
32
37
|
else
|
33
38
|
ty
|
34
39
|
end
|
@@ -40,6 +45,8 @@ module RBS
|
|
40
45
|
vars.each do |var|
|
41
46
|
subst.mapping.delete(var)
|
42
47
|
end
|
48
|
+
|
49
|
+
subst.instance_type = self.instance_type
|
43
50
|
end
|
44
51
|
end
|
45
52
|
end
|
data/lib/rbs/test/hook.rb
CHANGED
@@ -94,7 +94,7 @@ module RBS
|
|
94
94
|
|
95
95
|
builder.build_instance(type_name).tap do |definition|
|
96
96
|
definition.methods.each do |name, method|
|
97
|
-
if method.defined_in
|
97
|
+
if method.defined_in == type_name
|
98
98
|
unless method.annotations.any? {|a| a.string == "rbs:test:skip" }
|
99
99
|
logger.info "Installing a hook on #{type_name}##{name}: #{method.method_types.join(" | ")}"
|
100
100
|
verify instance_method: name, types: method.method_types
|
@@ -107,7 +107,7 @@ module RBS
|
|
107
107
|
|
108
108
|
builder.build_singleton(type_name).tap do |definition|
|
109
109
|
definition.methods.each do |name, method|
|
110
|
-
if method.defined_in
|
110
|
+
if method.defined_in == type_name || name == :new
|
111
111
|
unless method.annotations.any? {|a| a.string == "rbs:test:skip" }
|
112
112
|
logger.info "Installing a hook on #{type_name}.#{name}: #{method.method_types.join(" | ")}"
|
113
113
|
verify singleton_method: name, types: method.method_types
|
data/lib/rbs/test/setup.rb
CHANGED
@@ -33,6 +33,8 @@ OptionParser.new do |opts|
|
|
33
33
|
end.parse!(opts)
|
34
34
|
loader.load(env: env)
|
35
35
|
|
36
|
+
env = env.resolve_type_names
|
37
|
+
|
36
38
|
def match(filter, name)
|
37
39
|
if filter.end_with?("*")
|
38
40
|
name.start_with?(filter[0, filter.size - 1]) || name == filter[0, filter.size-3]
|
@@ -48,7 +50,7 @@ TracePoint.trace :end do |tp|
|
|
48
50
|
if filter.any? {|f| match(f, class_name) } && skips.none? {|f| match(f, class_name) }
|
49
51
|
type_name = RBS::Namespace.parse(class_name).absolute!.to_type_name
|
50
52
|
if hooks.none? {|hook| hook.klass == tp.self }
|
51
|
-
if env.
|
53
|
+
if env.class_decls.key?(type_name)
|
52
54
|
logger.info "Setting up hooks for #{class_name}"
|
53
55
|
hooks << RBS::Test::Hook.install(env, tp.self, logger: logger).verify_all.raise_on_error!(raise_on_error)
|
54
56
|
end
|
data/lib/rbs/test/test_helper.rb
CHANGED
@@ -17,9 +17,7 @@ module RBS
|
|
17
17
|
loader.add library: lib
|
18
18
|
end
|
19
19
|
|
20
|
-
RBS::Environment.
|
21
|
-
loader.load(env: env)
|
22
|
-
end
|
20
|
+
RBS::Environment.from_loader(loader).resolve_type_names
|
23
21
|
end
|
24
22
|
end
|
25
23
|
|
@@ -126,8 +124,7 @@ module RBS
|
|
126
124
|
type, definition = target
|
127
125
|
method_types = case
|
128
126
|
when definition.instance_type?
|
129
|
-
subst = Substitution.build(definition.
|
130
|
-
type.args)
|
127
|
+
subst = Substitution.build(definition.type_params, type.args)
|
131
128
|
definition.methods[method].method_types.map do |method_type|
|
132
129
|
method_type.sub(subst)
|
133
130
|
end
|
data/lib/rbs/test/type_check.rb
CHANGED
@@ -220,8 +220,7 @@ module RBS
|
|
220
220
|
val == klass
|
221
221
|
when Types::Interface
|
222
222
|
methods = Set.new(Test.call(val, METHODS))
|
223
|
-
|
224
|
-
if (definition = builder.build_interface(type.name, decl))
|
223
|
+
if (definition = builder.build_interface(type.name))
|
225
224
|
definition.methods.each_key.all? do |method_name|
|
226
225
|
methods.member?(method_name)
|
227
226
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module RBS
|
2
|
+
class TypeNameResolver
|
3
|
+
Query = Struct.new(:type_name, :context, keyword_init: true)
|
4
|
+
|
5
|
+
attr_reader :all_names
|
6
|
+
attr_reader :cache
|
7
|
+
|
8
|
+
def initialize()
|
9
|
+
@all_names = Set[]
|
10
|
+
@cache = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_env(env)
|
14
|
+
new.add_names(env.class_decls.keys)
|
15
|
+
.add_names(env.interface_decls.keys)
|
16
|
+
.add_names(env.alias_decls.keys)
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_names(names)
|
20
|
+
all_names.merge(names)
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def try_cache(query)
|
25
|
+
cache.fetch(query) do
|
26
|
+
result = yield
|
27
|
+
cache[query] = result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def resolve(type_name, context:)
|
32
|
+
if type_name.absolute?
|
33
|
+
return type_name
|
34
|
+
end
|
35
|
+
|
36
|
+
query = Query.new(type_name: type_name, context: context)
|
37
|
+
try_cache(query) do
|
38
|
+
path_head, *path_tail = type_name.to_namespace.path
|
39
|
+
name_head = TypeName.new(name: path_head, namespace: Namespace.empty)
|
40
|
+
|
41
|
+
absolute_head = context.each.find do |namespace|
|
42
|
+
full_name = name_head.with_prefix(namespace)
|
43
|
+
has_name?(full_name) and break full_name
|
44
|
+
end
|
45
|
+
|
46
|
+
if absolute_head
|
47
|
+
has_name?(Namespace.new(path: absolute_head.to_namespace.path.push(*path_tail), absolute: true).to_type_name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def has_name?(full_name)
|
53
|
+
if all_names.include?(full_name)
|
54
|
+
full_name
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/rbs/types.rb
CHANGED
@@ -12,6 +12,12 @@ module RBS
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
module NoTypeName
|
16
|
+
def map_type_name
|
17
|
+
self
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
15
21
|
module EmptyEachType
|
16
22
|
def each_type
|
17
23
|
if block_given?
|
@@ -43,6 +49,7 @@ module RBS
|
|
43
49
|
include NoFreeVariables
|
44
50
|
include NoSubst
|
45
51
|
include EmptyEachType
|
52
|
+
include NoTypeName
|
46
53
|
|
47
54
|
def to_json(*a)
|
48
55
|
klass = to_s.to_sym
|
@@ -82,7 +89,11 @@ module RBS
|
|
82
89
|
class Top < Base; end
|
83
90
|
class Bottom < Base; end
|
84
91
|
class Self < Base; end
|
85
|
-
class Instance < Base
|
92
|
+
class Instance < Base
|
93
|
+
def sub(s)
|
94
|
+
s.apply(self)
|
95
|
+
end
|
96
|
+
end
|
86
97
|
class Class < Base; end
|
87
98
|
end
|
88
99
|
|
@@ -90,6 +101,8 @@ module RBS
|
|
90
101
|
attr_reader :name
|
91
102
|
attr_reader :location
|
92
103
|
|
104
|
+
include NoTypeName
|
105
|
+
|
93
106
|
def initialize(name:, location:)
|
94
107
|
@name = name
|
95
108
|
@location = location
|
@@ -174,6 +187,13 @@ module RBS
|
|
174
187
|
end
|
175
188
|
|
176
189
|
include EmptyEachType
|
190
|
+
|
191
|
+
def map_type_name
|
192
|
+
ClassSingleton.new(
|
193
|
+
name: yield(name, location, self),
|
194
|
+
location: location
|
195
|
+
)
|
196
|
+
end
|
177
197
|
end
|
178
198
|
|
179
199
|
module Application
|
@@ -235,6 +255,14 @@ module RBS
|
|
235
255
|
args: args.map {|ty| ty.sub(s) },
|
236
256
|
location: location)
|
237
257
|
end
|
258
|
+
|
259
|
+
def map_type_name(&block)
|
260
|
+
Interface.new(
|
261
|
+
name: yield(name, location, self),
|
262
|
+
args: args.map {|type| type.map_type_name(&block) },
|
263
|
+
location: location
|
264
|
+
)
|
265
|
+
end
|
238
266
|
end
|
239
267
|
|
240
268
|
class ClassInstance
|
@@ -257,6 +285,14 @@ module RBS
|
|
257
285
|
args: args.map {|ty| ty.sub(s) },
|
258
286
|
location: location)
|
259
287
|
end
|
288
|
+
|
289
|
+
def map_type_name(&block)
|
290
|
+
ClassInstance.new(
|
291
|
+
name: yield(name, location, self),
|
292
|
+
args: args.map {|type| type.map_type_name(&block) },
|
293
|
+
location: location
|
294
|
+
)
|
295
|
+
end
|
260
296
|
end
|
261
297
|
|
262
298
|
class Alias
|
@@ -290,6 +326,13 @@ module RBS
|
|
290
326
|
end
|
291
327
|
|
292
328
|
include EmptyEachType
|
329
|
+
|
330
|
+
def map_type_name
|
331
|
+
Alias.new(
|
332
|
+
name: yield(name, location, self),
|
333
|
+
location: location
|
334
|
+
)
|
335
|
+
end
|
293
336
|
end
|
294
337
|
|
295
338
|
class Tuple
|
@@ -343,6 +386,13 @@ module RBS
|
|
343
386
|
enum_for :each_type
|
344
387
|
end
|
345
388
|
end
|
389
|
+
|
390
|
+
def map_type_name(&block)
|
391
|
+
Tuple.new(
|
392
|
+
types: types.map {|type| type.map_type_name(&block) },
|
393
|
+
location: location
|
394
|
+
)
|
395
|
+
end
|
346
396
|
end
|
347
397
|
|
348
398
|
class Record
|
@@ -401,6 +451,13 @@ module RBS
|
|
401
451
|
enum_for :each_type
|
402
452
|
end
|
403
453
|
end
|
454
|
+
|
455
|
+
def map_type_name(&block)
|
456
|
+
Record.new(
|
457
|
+
fields: fields.transform_values {|ty| ty.map_type_name(&block) },
|
458
|
+
location: location
|
459
|
+
)
|
460
|
+
end
|
404
461
|
end
|
405
462
|
|
406
463
|
class Optional
|
@@ -449,6 +506,13 @@ module RBS
|
|
449
506
|
enum_for :each_type
|
450
507
|
end
|
451
508
|
end
|
509
|
+
|
510
|
+
def map_type_name(&block)
|
511
|
+
Optional.new(
|
512
|
+
type: type.map_type_name(&block),
|
513
|
+
location: location
|
514
|
+
)
|
515
|
+
end
|
452
516
|
end
|
453
517
|
|
454
518
|
class Union
|
@@ -510,6 +574,13 @@ module RBS
|
|
510
574
|
enum_for :map_type
|
511
575
|
end
|
512
576
|
end
|
577
|
+
|
578
|
+
def map_type_name(&block)
|
579
|
+
Union.new(
|
580
|
+
types: types.map {|type| type.map_type_name(&block) },
|
581
|
+
location: location
|
582
|
+
)
|
583
|
+
end
|
513
584
|
end
|
514
585
|
|
515
586
|
class Intersection
|
@@ -572,6 +643,13 @@ module RBS
|
|
572
643
|
enum_for :map_type
|
573
644
|
end
|
574
645
|
end
|
646
|
+
|
647
|
+
def map_type_name(&block)
|
648
|
+
Intersection.new(
|
649
|
+
types: types.map {|type| type.map_type_name(&block) },
|
650
|
+
location: location
|
651
|
+
)
|
652
|
+
end
|
575
653
|
end
|
576
654
|
|
577
655
|
class Function
|
@@ -648,7 +726,7 @@ module RBS
|
|
648
726
|
other.required_keywords == required_keywords &&
|
649
727
|
other.optional_keywords == optional_keywords &&
|
650
728
|
other.rest_keywords == rest_keywords &&
|
651
|
-
return_type == return_type
|
729
|
+
other.return_type == return_type
|
652
730
|
end
|
653
731
|
|
654
732
|
alias eql? ==
|
@@ -710,6 +788,12 @@ module RBS
|
|
710
788
|
end
|
711
789
|
end
|
712
790
|
|
791
|
+
def map_type_name(&block)
|
792
|
+
map_type do |type|
|
793
|
+
type.map_type_name(&block)
|
794
|
+
end
|
795
|
+
end
|
796
|
+
|
713
797
|
def each_type
|
714
798
|
if block_given?
|
715
799
|
required_positionals.each {|param| yield param.type }
|
@@ -899,6 +983,13 @@ module RBS
|
|
899
983
|
enum_for :each_type
|
900
984
|
end
|
901
985
|
end
|
986
|
+
|
987
|
+
def map_type_name(&block)
|
988
|
+
Proc.new(
|
989
|
+
type: type.map_type_name(&block),
|
990
|
+
location: location
|
991
|
+
)
|
992
|
+
end
|
902
993
|
end
|
903
994
|
|
904
995
|
class Literal
|
@@ -923,6 +1014,7 @@ module RBS
|
|
923
1014
|
include NoFreeVariables
|
924
1015
|
include NoSubst
|
925
1016
|
include EmptyEachType
|
1017
|
+
include NoTypeName
|
926
1018
|
|
927
1019
|
def to_json(*a)
|
928
1020
|
{ class: :literal, literal: literal.inspect, location: location }.to_json(*a)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module RBS
|
2
|
+
class Validator
|
3
|
+
attr_reader :env
|
4
|
+
attr_reader :resolver
|
5
|
+
|
6
|
+
def initialize(env:, resolver:)
|
7
|
+
@env = env
|
8
|
+
@resolver = resolver
|
9
|
+
end
|
10
|
+
|
11
|
+
def absolute_type(type, context:)
|
12
|
+
type.map_type_name do |type_name, _, type|
|
13
|
+
resolver.resolve(type_name, context: context) || yield(type)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Validates presence of the relative type, and application arity match.
|
18
|
+
def validate_type(type, context:)
|
19
|
+
case type
|
20
|
+
when Types::ClassInstance, Types::Interface
|
21
|
+
if type.name.namespace.relative?
|
22
|
+
type = absolute_type(type, context: context) do |type|
|
23
|
+
NoTypeFoundError.check!(type.name.absolute!, env: env, location: type.location)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
type_params = case type
|
28
|
+
when Types::ClassInstance
|
29
|
+
env.class_decls[type.name]&.type_params
|
30
|
+
when Types::Interface
|
31
|
+
env.interface_decls[type.name]&.decl&.type_params
|
32
|
+
end
|
33
|
+
|
34
|
+
unless type_params
|
35
|
+
raise NoTypeFoundError.new(type_name: type.name, location: type.location)
|
36
|
+
end
|
37
|
+
|
38
|
+
InvalidTypeApplicationError.check!(
|
39
|
+
type_name: type.name,
|
40
|
+
args: type.args,
|
41
|
+
params: type_params.each.map(&:name),
|
42
|
+
location: type.location
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
type.each_type do |type|
|
47
|
+
validate_type(type, context: context)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|