rbs 1.7.0.beta.4 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|