rbs 1.7.0.beta.4 → 1.8.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/.gitignore +0 -1
- data/CHANGELOG.md +58 -2
- data/Steepfile +0 -1
- data/core/array.rbs +3 -3
- data/core/binding.rbs +2 -0
- data/core/builtin.rbs +4 -0
- data/core/complex.rbs +0 -2
- data/core/enumerable.rbs +3 -3
- data/core/env.rbs +881 -0
- data/core/false_class.rbs +2 -0
- data/core/float.rbs +0 -2
- data/core/integer.rbs +0 -2
- data/core/nil_class.rbs +2 -0
- data/core/numeric.rbs +7 -0
- data/core/object.rbs +1 -1
- data/core/proc.rbs +2 -0
- data/core/rational.rbs +0 -2
- data/core/symbol.rbs +2 -0
- data/core/thread.rbs +1 -1
- data/core/true_class.rbs +2 -0
- data/core/unbound_method.rbs +13 -0
- data/docs/rbs_by_example.md +2 -2
- data/docs/syntax.md +25 -23
- data/ext/rbs_extension/parser.c +99 -95
- data/ext/rbs_extension/parserstate.c +0 -1
- data/ext/rbs_extension/rbs_extension.h +1 -1
- data/ext/rbs_extension/ruby_objs.c +8 -6
- data/ext/rbs_extension/ruby_objs.h +2 -4
- data/lib/rbs/ast/declarations.rb +6 -2
- data/lib/rbs/cli.rb +1 -1
- data/lib/rbs/collection/sources/git.rb +6 -1
- data/lib/rbs/definition_builder.rb +29 -2
- data/lib/rbs/environment.rb +1 -0
- data/lib/rbs/environment_walker.rb +4 -1
- data/lib/rbs/errors.rb +12 -0
- data/lib/rbs/prototype/helpers.rb +113 -0
- data/lib/rbs/prototype/rb.rb +2 -105
- data/lib/rbs/prototype/runtime.rb +16 -0
- data/lib/rbs/test/setup.rb +1 -0
- data/lib/rbs/type_alias_regularity.rb +115 -0
- data/lib/rbs/types.rb +11 -23
- data/lib/rbs/validator.rb +40 -7
- data/lib/rbs/variance_calculator.rb +52 -24
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/writer.rb +1 -1
- data/lib/rbs.rb +2 -0
- data/schema/decls.json +13 -1
- data/schema/types.json +8 -2
- data/sig/collection/collections.rbs +2 -0
- data/sig/declarations.rbs +9 -6
- data/sig/definition_builder.rbs +29 -0
- data/sig/environment_walker.rbs +26 -0
- data/sig/errors.rbs +10 -0
- data/sig/type_alias_regularity.rbs +92 -0
- data/sig/types.rbs +11 -8
- data/sig/validator.rbs +7 -0
- data/sig/variance_calculator.rbs +50 -0
- data/stdlib/bigdecimal/0/big_decimal.rbs +44 -0
- data/stdlib/csv/0/csv.rbs +49 -3
- data/stdlib/date/0/date.rbs +2 -2
- data/stdlib/set/0/set.rbs +3 -3
- data/steep/Gemfile.lock +10 -10
- metadata +8 -6
- data/lib/rbs/parser.y +0 -1805
- data/lib/ruby/signature.rb +0 -7
@@ -781,9 +781,36 @@ module RBS
|
|
781
781
|
end
|
782
782
|
|
783
783
|
def expand_alias(type_name)
|
784
|
-
|
784
|
+
expand_alias2(type_name, [])
|
785
|
+
end
|
786
|
+
|
787
|
+
def expand_alias1(type_name)
|
788
|
+
entry = env.alias_decls[type_name] or raise "Unknown alias name: #{type_name}"
|
789
|
+
as = entry.decl.type_params.each.map { Types::Bases::Any.new(location: nil) }
|
790
|
+
expand_alias2(type_name, as)
|
791
|
+
end
|
792
|
+
|
793
|
+
def expand_alias2(type_name, args)
|
794
|
+
entry = env.alias_decls[type_name] or raise "Unknown alias name: #{type_name}"
|
795
|
+
|
785
796
|
ensure_namespace!(type_name.namespace, location: entry.decl.location)
|
786
|
-
entry.decl.
|
797
|
+
params = entry.decl.type_params.each.map(&:name)
|
798
|
+
|
799
|
+
unless params.size == args.size
|
800
|
+
as = "[#{args.join(", ")}]" unless args.empty?
|
801
|
+
ps = "[#{params.join(", ")}]" unless params.empty?
|
802
|
+
|
803
|
+
raise "Invalid type application: type = #{type_name}#{as}, decl = #{type_name}#{ps}"
|
804
|
+
end
|
805
|
+
|
806
|
+
type = entry.decl.type
|
807
|
+
|
808
|
+
unless params.empty?
|
809
|
+
subst = Substitution.build(params, args)
|
810
|
+
type = type.sub(subst)
|
811
|
+
end
|
812
|
+
|
813
|
+
type
|
787
814
|
end
|
788
815
|
|
789
816
|
def update(env:, except:, ancestor_builder:)
|
data/lib/rbs/environment.rb
CHANGED
@@ -319,6 +319,7 @@ module RBS
|
|
319
319
|
when AST::Declarations::Alias
|
320
320
|
AST::Declarations::Alias.new(
|
321
321
|
name: decl.name.with_prefix(prefix),
|
322
|
+
type_params: decl.type_params,
|
322
323
|
type: absolute_type(resolver, decl.type, context: context),
|
323
324
|
location: decl.location,
|
324
325
|
annotations: decl.annotations,
|
@@ -57,7 +57,7 @@ module RBS
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
when name.alias?
|
60
|
-
each_type_node builder.
|
60
|
+
each_type_node builder.expand_alias1(name), &block
|
61
61
|
else
|
62
62
|
raise "Unexpected TypeNameNode with type_name=#{name}"
|
63
63
|
end
|
@@ -126,6 +126,9 @@ module RBS
|
|
126
126
|
end
|
127
127
|
when RBS::Types::Alias
|
128
128
|
yield TypeNameNode.new(type_name: type.name)
|
129
|
+
type.args.each do |ty|
|
130
|
+
each_type_node(ty, &block)
|
131
|
+
end
|
129
132
|
when RBS::Types::Union, RBS::Types::Intersection, RBS::Types::Tuple
|
130
133
|
type.types.each do |ty|
|
131
134
|
each_type_node ty, &block
|
data/lib/rbs/errors.rb
CHANGED
@@ -431,4 +431,16 @@ module RBS
|
|
431
431
|
@alias_names.map(&:name).join(', ')
|
432
432
|
end
|
433
433
|
end
|
434
|
+
|
435
|
+
class NonregularTypeAliasError < LoadingError
|
436
|
+
attr_reader :diagnostic
|
437
|
+
attr_reader :location
|
438
|
+
|
439
|
+
def initialize(diagnostic:, location:)
|
440
|
+
@diagnostic = diagnostic
|
441
|
+
@location = location
|
442
|
+
|
443
|
+
super "#{Location.to_string location}: Nonregular generic type alias is prohibited: #{diagnostic.type_name}, #{diagnostic.nonregular_type}"
|
444
|
+
end
|
445
|
+
end
|
434
446
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module RBS
|
2
|
+
module Prototype
|
3
|
+
module Helpers
|
4
|
+
private
|
5
|
+
|
6
|
+
def block_from_body(node)
|
7
|
+
_, args_node, body_node = node.children
|
8
|
+
|
9
|
+
_pre_num, _pre_init, _opt, _first_post, _post_num, _post_init, _rest, _kw, _kwrest, block = args_from_node(args_node)
|
10
|
+
|
11
|
+
method_block = nil
|
12
|
+
|
13
|
+
if block
|
14
|
+
method_block = Types::Block.new(
|
15
|
+
# HACK: The `block` is :& on `def m(...)` syntax.
|
16
|
+
# In this case the block looks optional in most cases, so it marks optional.
|
17
|
+
# In other cases, we can't determine which is required or optional, so it marks required.
|
18
|
+
required: block != :&,
|
19
|
+
type: Types::Function.empty(untyped)
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
if body_node
|
24
|
+
if (yields = any_node?(body_node) {|n| n.type == :YIELD })
|
25
|
+
method_block = Types::Block.new(
|
26
|
+
required: true,
|
27
|
+
type: Types::Function.empty(untyped)
|
28
|
+
)
|
29
|
+
|
30
|
+
yields.each do |yield_node|
|
31
|
+
array_content = yield_node.children[0]&.children&.compact || []
|
32
|
+
|
33
|
+
positionals, keywords = if keyword_hash?(array_content.last)
|
34
|
+
[array_content.take(array_content.size - 1), array_content.last]
|
35
|
+
else
|
36
|
+
[array_content, nil]
|
37
|
+
end
|
38
|
+
|
39
|
+
if (diff = positionals.size - method_block.type.required_positionals.size) > 0
|
40
|
+
diff.times do
|
41
|
+
method_block.type.required_positionals << Types::Function::Param.new(
|
42
|
+
type: untyped,
|
43
|
+
name: nil
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if keywords
|
49
|
+
keywords.children[0].children.each_slice(2) do |key_node, value_node|
|
50
|
+
if key_node
|
51
|
+
key = key_node.children[0]
|
52
|
+
method_block.type.required_keywords[key] ||=
|
53
|
+
Types::Function::Param.new(
|
54
|
+
type: untyped,
|
55
|
+
name: nil
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
method_block
|
65
|
+
end
|
66
|
+
|
67
|
+
def each_child(node, &block)
|
68
|
+
each_node node.children, &block
|
69
|
+
end
|
70
|
+
|
71
|
+
def each_node(nodes)
|
72
|
+
nodes.each do |child|
|
73
|
+
if child.is_a?(RubyVM::AbstractSyntaxTree::Node)
|
74
|
+
yield child
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def any_node?(node, nodes: [], &block)
|
81
|
+
if yield(node)
|
82
|
+
nodes << node
|
83
|
+
end
|
84
|
+
|
85
|
+
each_child node do |child|
|
86
|
+
any_node? child, nodes: nodes, &block
|
87
|
+
end
|
88
|
+
|
89
|
+
nodes.empty? ? nil : nodes
|
90
|
+
end
|
91
|
+
|
92
|
+
def keyword_hash?(node)
|
93
|
+
if node
|
94
|
+
if node.type == :HASH
|
95
|
+
node.children[0].children.compact.each_slice(2).all? {|key, _|
|
96
|
+
key.type == :LIT && key.children[0].is_a?(Symbol)
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# NOTE: args_node may be a nil by a bug
|
103
|
+
# https://bugs.ruby-lang.org/issues/17495
|
104
|
+
def args_from_node(args_node)
|
105
|
+
args_node&.children || [0, nil, nil, nil, 0, nil, nil, nil, nil, nil]
|
106
|
+
end
|
107
|
+
|
108
|
+
def untyped
|
109
|
+
@untyped ||= Types::Bases::Any.new(location: nil)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/rbs/prototype/rb.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module RBS
|
2
2
|
module Prototype
|
3
3
|
class RB
|
4
|
+
include Helpers
|
5
|
+
|
4
6
|
Context = Struct.new(:module_function, :singleton, :namespace, keyword_init: true) do
|
5
7
|
def self.initial(namespace: Namespace.root)
|
6
8
|
self.new(module_function: false, singleton: false, namespace: namespace)
|
@@ -372,18 +374,6 @@ module RBS
|
|
372
374
|
end
|
373
375
|
end
|
374
376
|
|
375
|
-
def each_node(nodes)
|
376
|
-
nodes.each do |child|
|
377
|
-
if child.is_a?(RubyVM::AbstractSyntaxTree::Node)
|
378
|
-
yield child
|
379
|
-
end
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
def each_child(node, &block)
|
384
|
-
each_node node.children, &block
|
385
|
-
end
|
386
|
-
|
387
377
|
def function_type_from_body(node, def_name)
|
388
378
|
table_node, args_node, *_ = node.children
|
389
379
|
|
@@ -568,95 +558,6 @@ module RBS
|
|
568
558
|
end
|
569
559
|
end
|
570
560
|
|
571
|
-
def block_from_body(node)
|
572
|
-
_, args_node, body_node = node.children
|
573
|
-
|
574
|
-
_pre_num, _pre_init, _opt, _first_post, _post_num, _post_init, _rest, _kw, _kwrest, block = args_from_node(args_node)
|
575
|
-
|
576
|
-
method_block = nil
|
577
|
-
|
578
|
-
if block
|
579
|
-
method_block = Types::Block.new(
|
580
|
-
# HACK: The `block` is :& on `def m(...)` syntax.
|
581
|
-
# In this case the block looks optional in most cases, so it marks optional.
|
582
|
-
# In other cases, we can't determine which is required or optional, so it marks required.
|
583
|
-
required: block != :&,
|
584
|
-
type: Types::Function.empty(untyped)
|
585
|
-
)
|
586
|
-
end
|
587
|
-
|
588
|
-
if body_node
|
589
|
-
if (yields = any_node?(body_node) {|n| n.type == :YIELD })
|
590
|
-
method_block = Types::Block.new(
|
591
|
-
required: true,
|
592
|
-
type: Types::Function.empty(untyped)
|
593
|
-
)
|
594
|
-
|
595
|
-
yields.each do |yield_node|
|
596
|
-
array_content = yield_node.children[0]&.children&.compact || []
|
597
|
-
|
598
|
-
positionals, keywords = if keyword_hash?(array_content.last)
|
599
|
-
[array_content.take(array_content.size - 1), array_content.last]
|
600
|
-
else
|
601
|
-
[array_content, nil]
|
602
|
-
end
|
603
|
-
|
604
|
-
if (diff = positionals.size - method_block.type.required_positionals.size) > 0
|
605
|
-
diff.times do
|
606
|
-
method_block.type.required_positionals << Types::Function::Param.new(
|
607
|
-
type: untyped,
|
608
|
-
name: nil
|
609
|
-
)
|
610
|
-
end
|
611
|
-
end
|
612
|
-
|
613
|
-
if keywords
|
614
|
-
keywords.children[0].children.each_slice(2) do |key_node, value_node|
|
615
|
-
if key_node
|
616
|
-
key = key_node.children[0]
|
617
|
-
method_block.type.required_keywords[key] ||=
|
618
|
-
Types::Function::Param.new(
|
619
|
-
type: untyped,
|
620
|
-
name: nil
|
621
|
-
)
|
622
|
-
end
|
623
|
-
end
|
624
|
-
end
|
625
|
-
end
|
626
|
-
end
|
627
|
-
end
|
628
|
-
|
629
|
-
method_block
|
630
|
-
end
|
631
|
-
|
632
|
-
# NOTE: args_node may be a nil by a bug
|
633
|
-
# https://bugs.ruby-lang.org/issues/17495
|
634
|
-
def args_from_node(args_node)
|
635
|
-
args_node&.children || [0, nil, nil, nil, 0, nil, nil, nil, nil, nil]
|
636
|
-
end
|
637
|
-
|
638
|
-
def keyword_hash?(node)
|
639
|
-
if node
|
640
|
-
if node.type == :HASH
|
641
|
-
node.children[0].children.compact.each_slice(2).all? {|key, _|
|
642
|
-
key.type == :LIT && key.children[0].is_a?(Symbol)
|
643
|
-
}
|
644
|
-
end
|
645
|
-
end
|
646
|
-
end
|
647
|
-
|
648
|
-
def any_node?(node, nodes: [], &block)
|
649
|
-
if yield(node)
|
650
|
-
nodes << node
|
651
|
-
end
|
652
|
-
|
653
|
-
each_child node do |child|
|
654
|
-
any_node? child, nodes: nodes, &block
|
655
|
-
end
|
656
|
-
|
657
|
-
nodes.empty? ? nil : nodes
|
658
|
-
end
|
659
|
-
|
660
561
|
def node_type(node, default: Types::Bases::Any.new(location: nil))
|
661
562
|
case node.type
|
662
563
|
when :LIT
|
@@ -689,10 +590,6 @@ module RBS
|
|
689
590
|
end
|
690
591
|
end
|
691
592
|
|
692
|
-
def untyped
|
693
|
-
@untyped ||= Types::Bases::Any.new(location: nil)
|
694
|
-
end
|
695
|
-
|
696
593
|
def private
|
697
594
|
@private ||= AST::Members::Private.new(location: nil)
|
698
595
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module RBS
|
2
2
|
module Prototype
|
3
3
|
class Runtime
|
4
|
+
include Helpers
|
5
|
+
|
4
6
|
attr_reader :patterns
|
5
7
|
attr_reader :env
|
6
8
|
attr_reader :merge
|
@@ -138,6 +140,8 @@ module RBS
|
|
138
140
|
end
|
139
141
|
end
|
140
142
|
|
143
|
+
block ||= block_from_ast_of(method)
|
144
|
+
|
141
145
|
return_type = if method.name == :initialize
|
142
146
|
Types::Bases::Void.new(location: nil)
|
143
147
|
else
|
@@ -522,6 +526,18 @@ module RBS
|
|
522
526
|
[]
|
523
527
|
end
|
524
528
|
end
|
529
|
+
|
530
|
+
def block_from_ast_of(method)
|
531
|
+
return nil if RUBY_VERSION < '3.1'
|
532
|
+
|
533
|
+
begin
|
534
|
+
ast = RubyVM::AbstractSyntaxTree.of(method)
|
535
|
+
rescue ArgumentError
|
536
|
+
return # When the method is defined in eval
|
537
|
+
end
|
538
|
+
|
539
|
+
block_from_body(ast) if ast&.type == :SCOPE
|
540
|
+
end
|
525
541
|
end
|
526
542
|
end
|
527
543
|
end
|
data/lib/rbs/test/setup.rb
CHANGED
@@ -13,6 +13,7 @@ begin
|
|
13
13
|
filter = ENV.fetch('RBS_TEST_TARGET', "").split(',').map! { |e| e.strip }
|
14
14
|
skips = (ENV['RBS_TEST_SKIP'] || '').split(',').map! { |e| e.strip }
|
15
15
|
RBS.logger_level = (ENV["RBS_TEST_LOGLEVEL"] || "info")
|
16
|
+
logger.level = RBS.logger_level
|
16
17
|
sample_size = get_sample_size(ENV['RBS_TEST_SAMPLE_SIZE'] || '')
|
17
18
|
double_class = to_double_class(ENV['RBS_TEST_DOUBLE_SUITE'])
|
18
19
|
unchecked_classes = (ENV['RBS_TEST_UNCHECKED_CLASSES'] || '').split(',').map! { |unchecked_class| unchecked_class.strip }.push(*double_class)
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module RBS
|
2
|
+
class TypeAliasRegularity
|
3
|
+
class Diagnostic
|
4
|
+
attr_reader :type_name, :nonregular_type
|
5
|
+
|
6
|
+
def initialize(type_name:, nonregular_type:)
|
7
|
+
@type_name = type_name
|
8
|
+
@nonregular_type = nonregular_type
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :env, :builder, :diagnostics
|
13
|
+
|
14
|
+
def initialize(env:)
|
15
|
+
@env = env
|
16
|
+
@builder = DefinitionBuilder.new(env: env)
|
17
|
+
@diagnostics = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate
|
21
|
+
diagnostics.clear
|
22
|
+
|
23
|
+
each_mutual_alias_defs do |names|
|
24
|
+
# Find the first generic type alias in strongly connected component.
|
25
|
+
# This is to skip the regularity check when the alias is not generic.
|
26
|
+
names.each do |name|
|
27
|
+
# @type break: nil
|
28
|
+
if type = build_alias_type(name)
|
29
|
+
# Running validation only once from the first generic type is enough, because they are mutual recursive definition.
|
30
|
+
validate_alias_type(type, names, {})
|
31
|
+
break
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_alias_type(alias_type, names, types)
|
38
|
+
if names.include?(alias_type.name)
|
39
|
+
if ex_type = types[alias_type.name]
|
40
|
+
unless compatible_args?(ex_type.args, alias_type.args)
|
41
|
+
diagnostics[alias_type.name] ||=
|
42
|
+
Diagnostic.new(type_name: alias_type.name, nonregular_type: alias_type)
|
43
|
+
end
|
44
|
+
|
45
|
+
return
|
46
|
+
else
|
47
|
+
types[alias_type.name] = alias_type
|
48
|
+
end
|
49
|
+
|
50
|
+
expanded = builder.expand_alias2(alias_type.name, alias_type.args)
|
51
|
+
each_alias_type(expanded) do |at|
|
52
|
+
validate_alias_type(at, names, types)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_alias_type(name)
|
58
|
+
entry = env.alias_decls[name] or raise "Unknown alias name: #{name}"
|
59
|
+
unless entry.decl.type_params.empty?
|
60
|
+
as = entry.decl.type_params.each.map {|param| Types::Variable.new(name: param.name, location: nil) }
|
61
|
+
Types::Alias.new(name: name, args: as, location: nil)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def compatible_args?(args1, args2)
|
66
|
+
if args1.size == args2.size
|
67
|
+
args1.zip(args2).all? do |t1, t2|
|
68
|
+
t1.is_a?(Types::Bases::Any) ||
|
69
|
+
t2.is_a?(Types::Bases::Any) ||
|
70
|
+
t1 == t2
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def nonregular?(type_name)
|
76
|
+
diagnostics[type_name]
|
77
|
+
end
|
78
|
+
|
79
|
+
def each_mutual_alias_defs(&block)
|
80
|
+
# @type var each_node: TSort::_EachNode[TypeName]
|
81
|
+
each_node = __skip__ = -> (&block) do
|
82
|
+
env.alias_decls.each_value do |decl|
|
83
|
+
block[decl.name]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
# @type var each_child: TSort::_EachChild[TypeName]
|
87
|
+
each_child = __skip__ = -> (name, &block) do
|
88
|
+
type = builder.expand_alias1(name)
|
89
|
+
each_alias_type(type) do |ty|
|
90
|
+
block[ty.name]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
TSort.each_strongly_connected_component(each_node, each_child) do |names|
|
95
|
+
yield Set.new(names)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def each_alias_type(type, &block)
|
100
|
+
if type.is_a?(RBS::Types::Alias)
|
101
|
+
yield type
|
102
|
+
end
|
103
|
+
|
104
|
+
type.each_type do |ty|
|
105
|
+
each_alias_type(ty, &block)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.validate(env:)
|
110
|
+
self.new(env: env).tap do |validator|
|
111
|
+
validator.validate()
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/lib/rbs/types.rb
CHANGED
@@ -295,39 +295,27 @@ module RBS
|
|
295
295
|
|
296
296
|
class Alias
|
297
297
|
attr_reader :location
|
298
|
-
attr_reader :name
|
299
298
|
|
300
|
-
|
299
|
+
include Application
|
300
|
+
|
301
|
+
def initialize(name:, args:, location:)
|
301
302
|
@name = name
|
303
|
+
@args = args
|
302
304
|
@location = location
|
303
305
|
end
|
304
306
|
|
305
|
-
def ==(other)
|
306
|
-
other.is_a?(Alias) && other.name == name
|
307
|
-
end
|
308
|
-
|
309
|
-
alias eql? ==
|
310
|
-
|
311
|
-
def hash
|
312
|
-
self.class.hash ^ name.hash
|
313
|
-
end
|
314
|
-
|
315
|
-
include NoFreeVariables
|
316
|
-
include NoSubst
|
317
|
-
|
318
307
|
def to_json(state = _ = nil)
|
319
|
-
{ class: :alias, name: name, location: location }.to_json(state)
|
308
|
+
{ class: :alias, name: name, args: args, location: location }.to_json(state)
|
320
309
|
end
|
321
310
|
|
322
|
-
def
|
323
|
-
name.
|
311
|
+
def sub(s)
|
312
|
+
Alias.new(name: name, args: args.map {|ty| ty.sub(s) }, location: location)
|
324
313
|
end
|
325
314
|
|
326
|
-
|
327
|
-
|
328
|
-
def map_type_name
|
315
|
+
def map_type_name(&block)
|
329
316
|
Alias.new(
|
330
317
|
name: yield(name, location, self),
|
318
|
+
args: args.map {|arg| arg.map_type_name(&block) },
|
331
319
|
location: location
|
332
320
|
)
|
333
321
|
end
|
@@ -433,7 +421,7 @@ module RBS
|
|
433
421
|
return "{ }" if self.fields.empty?
|
434
422
|
|
435
423
|
fields = self.fields.map do |key, type|
|
436
|
-
if key.is_a?(Symbol) && key.match?(/\A[A-Za-z_][A-Za-z_]*\z/)
|
424
|
+
if key.is_a?(Symbol) && key.match?(/\A[A-Za-z_][A-Za-z_]*\z/)
|
437
425
|
"#{key}: #{type}"
|
438
426
|
else
|
439
427
|
"#{key.inspect} => #{type}"
|
@@ -690,7 +678,7 @@ module RBS
|
|
690
678
|
|
691
679
|
def to_s
|
692
680
|
if name
|
693
|
-
if Parser::KEYWORDS.include?(name)
|
681
|
+
if Parser::KEYWORDS.include?(name.to_s)
|
694
682
|
"#{type} `#{name}`"
|
695
683
|
else
|
696
684
|
"#{type} #{name}"
|
data/lib/rbs/validator.rb
CHANGED
@@ -2,10 +2,12 @@ module RBS
|
|
2
2
|
class Validator
|
3
3
|
attr_reader :env
|
4
4
|
attr_reader :resolver
|
5
|
+
attr_reader :definition_builder
|
5
6
|
|
6
7
|
def initialize(env:, resolver:)
|
7
8
|
@env = env
|
8
9
|
@resolver = resolver
|
10
|
+
@definition_builder = DefinitionBuilder.new(env: env)
|
9
11
|
end
|
10
12
|
|
11
13
|
def absolute_type(type, context:)
|
@@ -17,8 +19,8 @@ module RBS
|
|
17
19
|
# Validates presence of the relative type, and application arity match.
|
18
20
|
def validate_type(type, context:)
|
19
21
|
case type
|
20
|
-
when Types::ClassInstance, Types::Interface
|
21
|
-
# @type var type: Types::ClassInstance | Types::Interface
|
22
|
+
when Types::ClassInstance, Types::Interface, Types::Alias
|
23
|
+
# @type var type: Types::ClassInstance | Types::Interface | Types::Alias
|
22
24
|
if type.name.namespace.relative?
|
23
25
|
type = _ = absolute_type(type, context: context) do |_|
|
24
26
|
NoTypeFoundError.check!(type.name.absolute!, env: env, location: type.location)
|
@@ -30,6 +32,8 @@ module RBS
|
|
30
32
|
env.class_decls[type.name]&.type_params
|
31
33
|
when Types::Interface
|
32
34
|
env.interface_decls[type.name]&.decl&.type_params
|
35
|
+
when Types::Alias
|
36
|
+
env.alias_decls[type.name]&.decl&.type_params
|
33
37
|
end
|
34
38
|
|
35
39
|
unless type_params
|
@@ -43,8 +47,8 @@ module RBS
|
|
43
47
|
location: type.location
|
44
48
|
)
|
45
49
|
|
46
|
-
when Types::
|
47
|
-
# @type var type: Types::
|
50
|
+
when Types::ClassSingleton
|
51
|
+
# @type var type: Types::ClassSingleton
|
48
52
|
type = _ = absolute_type(type, context: context) { type.name.absolute! }
|
49
53
|
NoTypeFoundError.check!(type.name, env: env, location: type.location)
|
50
54
|
end
|
@@ -55,11 +59,40 @@ module RBS
|
|
55
59
|
end
|
56
60
|
|
57
61
|
def validate_type_alias(entry:)
|
58
|
-
|
59
|
-
|
62
|
+
type_name = entry.decl.name
|
63
|
+
|
64
|
+
if type_alias_dependency.circular_definition?(type_name)
|
60
65
|
location = entry.decl.location or raise
|
61
|
-
raise RecursiveTypeAliasError.new(alias_names: [
|
66
|
+
raise RecursiveTypeAliasError.new(alias_names: [type_name], location: location)
|
67
|
+
end
|
68
|
+
|
69
|
+
if diagnostic = type_alias_regularity.nonregular?(type_name)
|
70
|
+
location = entry.decl.location or raise
|
71
|
+
raise NonregularTypeAliasError.new(diagnostic: diagnostic, location: location)
|
72
|
+
end
|
73
|
+
|
74
|
+
unless entry.decl.type_params.empty?
|
75
|
+
calculator = VarianceCalculator.new(builder: definition_builder)
|
76
|
+
result = calculator.in_type_alias(name: type_name)
|
77
|
+
if set = result.incompatible?(entry.decl.type_params)
|
78
|
+
set.each do |param_name|
|
79
|
+
param = entry.decl.type_params[param_name] or raise
|
80
|
+
raise InvalidVarianceAnnotationError.new(
|
81
|
+
type_name: type_name,
|
82
|
+
param: param,
|
83
|
+
location: entry.decl.type.location
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
62
87
|
end
|
63
88
|
end
|
89
|
+
|
90
|
+
def type_alias_dependency
|
91
|
+
@type_alias_dependency ||= TypeAliasDependency.new(env: env)
|
92
|
+
end
|
93
|
+
|
94
|
+
def type_alias_regularity
|
95
|
+
@type_alias_regularity ||= TypeAliasRegularity.validate(env: env)
|
96
|
+
end
|
64
97
|
end
|
65
98
|
end
|