steep 0.1.0.pre
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 +7 -0
- data/.gitignore +11 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/README.md +95 -0
- data/Rakefile +23 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/smoke_runner.rb +106 -0
- data/exe/steep +18 -0
- data/lib/steep.rb +33 -0
- data/lib/steep/annotation.rb +223 -0
- data/lib/steep/cli.rb +79 -0
- data/lib/steep/drivers/check.rb +141 -0
- data/lib/steep/errors.rb +207 -0
- data/lib/steep/interface.rb +280 -0
- data/lib/steep/parser.y +311 -0
- data/lib/steep/signature/class.rb +358 -0
- data/lib/steep/signature/errors.rb +78 -0
- data/lib/steep/signature/extension.rb +51 -0
- data/lib/steep/signature/interface.rb +48 -0
- data/lib/steep/source.rb +98 -0
- data/lib/steep/type_assignability.rb +362 -0
- data/lib/steep/type_construction.rb +993 -0
- data/lib/steep/type_name.rb +37 -0
- data/lib/steep/types.rb +4 -0
- data/lib/steep/types/any.rb +31 -0
- data/lib/steep/types/class.rb +27 -0
- data/lib/steep/types/instance.rb +27 -0
- data/lib/steep/types/merge.rb +32 -0
- data/lib/steep/types/name.rb +57 -0
- data/lib/steep/types/union.rb +42 -0
- data/lib/steep/types/var.rb +38 -0
- data/lib/steep/typing.rb +70 -0
- data/lib/steep/version.rb +3 -0
- data/manual/annotations.md +144 -0
- data/sig/signature.rbi +54 -0
- data/sig/types.rbi +43 -0
- data/smoke/and/a.rb +9 -0
- data/smoke/array/a.rb +22 -0
- data/smoke/block/a.rb +12 -0
- data/smoke/block/a.rbi +4 -0
- data/smoke/case/a.rb +20 -0
- data/smoke/class/a.rb +31 -0
- data/smoke/class/a.rbi +9 -0
- data/smoke/class/b.rb +7 -0
- data/smoke/class/c.rb +10 -0
- data/smoke/const/a.rb +30 -0
- data/smoke/dstr/a.rb +6 -0
- data/smoke/extension/a.rb +11 -0
- data/smoke/extension/a.rbi +8 -0
- data/smoke/extension/b.rb +12 -0
- data/smoke/extension/c.rb +9 -0
- data/smoke/hello/hello.rb +13 -0
- data/smoke/hello/hello.rbi +7 -0
- data/smoke/if/a.rb +20 -0
- data/smoke/implements/a.rb +14 -0
- data/smoke/implements/a.rbi +6 -0
- data/smoke/literal/a.rb +16 -0
- data/smoke/map/a.rb +5 -0
- data/smoke/method/a.rb +26 -0
- data/smoke/method/a.rbi +0 -0
- data/smoke/module/a.rb +21 -0
- data/smoke/module/a.rbi +7 -0
- data/smoke/module/b.rb +8 -0
- data/smoke/self/a.rb +23 -0
- data/smoke/self/a.rbi +4 -0
- data/smoke/super/a.rb +34 -0
- data/smoke/super/a.rbi +10 -0
- data/smoke/yield/a.rb +18 -0
- data/stdlib/builtin.rbi +89 -0
- data/steep.gemspec +32 -0
- metadata +214 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
module Steep
|
2
|
+
module Signature
|
3
|
+
module Errors
|
4
|
+
class Base
|
5
|
+
# @implements Steep__Signature__Error
|
6
|
+
|
7
|
+
# @dynamic signature
|
8
|
+
attr_reader :signature
|
9
|
+
|
10
|
+
def initialize(signature:)
|
11
|
+
@signature = signature
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class UnknownTypeName < Base
|
16
|
+
# @implements Steep__Signature__Errors__UnknownTypeName
|
17
|
+
|
18
|
+
# @dynamic type
|
19
|
+
attr_reader :type
|
20
|
+
|
21
|
+
def initialize(signature:, type:)
|
22
|
+
super(signature: signature)
|
23
|
+
@type = type
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class IncompatibleOverride < Base
|
28
|
+
# @implements Steep__Signature__Errors__IncompatibleOverride
|
29
|
+
|
30
|
+
# @dynamic method_name
|
31
|
+
attr_reader :method_name
|
32
|
+
# @dynamic this_method
|
33
|
+
attr_reader :this_method
|
34
|
+
# @dynamic super_method
|
35
|
+
attr_reader :super_method
|
36
|
+
|
37
|
+
def initialize(signature:, method_name:, this_method:, super_method:)
|
38
|
+
super(signature: signature)
|
39
|
+
@method_name = method_name
|
40
|
+
@this_method = this_method
|
41
|
+
@super_method = super_method
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class InvalidTypeApplication < Base
|
46
|
+
attr_reader :type_name
|
47
|
+
attr_reader :type_args
|
48
|
+
|
49
|
+
def initialize(signature:, type_name:, type_args:)
|
50
|
+
super(signature: signature)
|
51
|
+
@type_name = type_name
|
52
|
+
@type_args = type_args
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class InvalidSelfType < Base
|
57
|
+
attr_reader :member
|
58
|
+
|
59
|
+
def initialize(signature:, member:)
|
60
|
+
super(signature: signature)
|
61
|
+
@member = member
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class UnexpectedTypeNameKind < Base
|
66
|
+
attr_reader :type
|
67
|
+
attr_reader :expected_kind
|
68
|
+
|
69
|
+
def initialize(signature:, type:, expected_kind:)
|
70
|
+
super(signature: signature)
|
71
|
+
@type = type
|
72
|
+
@expected_kind = expected_kind
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Steep
|
2
|
+
module Signature
|
3
|
+
class Extension
|
4
|
+
# @implements Steep__Signature__Extension
|
5
|
+
|
6
|
+
def initialize(module_name:, extension_name:, members:)
|
7
|
+
@module_name = module_name
|
8
|
+
@extension_name = extension_name
|
9
|
+
@members = members
|
10
|
+
end
|
11
|
+
|
12
|
+
def module_name; @module_name; end
|
13
|
+
def extension_name; @extension_name; end
|
14
|
+
def members; @members; end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
# @type var other_: Steep__Signature__Extension
|
18
|
+
other_ = other
|
19
|
+
other.is_a?(self.class) &&
|
20
|
+
other_.module_name == module_name &&
|
21
|
+
other_.extension_name == extension_name &&
|
22
|
+
other_.members == members
|
23
|
+
end
|
24
|
+
|
25
|
+
def name
|
26
|
+
:"#{module_name} (#{extension_name})"
|
27
|
+
end
|
28
|
+
|
29
|
+
include WithMembers
|
30
|
+
prepend WithMethods
|
31
|
+
|
32
|
+
def validate(assignability)
|
33
|
+
each_type do |type|
|
34
|
+
assignability.validate_type_presence self, type
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def instance_methods(assignability:, klass:, instance:, params:)
|
39
|
+
{}
|
40
|
+
end
|
41
|
+
|
42
|
+
def module_methods(assignability:, klass:, instance:, params:)
|
43
|
+
{}
|
44
|
+
end
|
45
|
+
|
46
|
+
def type_application_hash(args)
|
47
|
+
{}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Steep
|
2
|
+
module Signature
|
3
|
+
class Interface
|
4
|
+
# @implements Steep__Signature__Interface
|
5
|
+
# @type const Hash: Hash.class
|
6
|
+
# @type const Interface: Steep__Signature__Interface.class
|
7
|
+
# @type const Steep::Interface: Steep__Interface.class
|
8
|
+
# @type const Steep::Interface::Method: Steep__Method.class
|
9
|
+
|
10
|
+
# @dynamic name
|
11
|
+
attr_reader :name
|
12
|
+
# @dynamic params
|
13
|
+
attr_reader :params
|
14
|
+
# @dynamic methods
|
15
|
+
attr_reader :methods
|
16
|
+
|
17
|
+
def initialize(name:, params:, methods:)
|
18
|
+
@name = name
|
19
|
+
@params = params
|
20
|
+
@methods = methods
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other)
|
24
|
+
# @type var other_: Steep__Signature__Interface
|
25
|
+
other_ = other
|
26
|
+
other_.is_a?(Interface) && other_.name == name && other_.params == params && other_.methods == methods
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_interface(klass:, instance:, params:)
|
30
|
+
raise "Invalid type application: expected: #{self.params.size}, actual: #{params.size}" if params.size != self.params.size
|
31
|
+
|
32
|
+
# @type var map: Hash<Symbol, Steep__Type>
|
33
|
+
map = Hash[self.params.zip(params)]
|
34
|
+
Steep::Interface.new(name: name,
|
35
|
+
methods: methods.transform_values {|method|
|
36
|
+
types = method.map {|method_type|
|
37
|
+
method_type.substitute(klass: klass, instance: instance, params: map)
|
38
|
+
}
|
39
|
+
Steep::Interface::Method.new(types: types, super_method: nil)
|
40
|
+
})
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate(assignability)
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/steep/source.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
module Steep
|
2
|
+
class Source
|
3
|
+
class LocatedAnnotation
|
4
|
+
attr_reader :line
|
5
|
+
attr_reader :annotation
|
6
|
+
attr_reader :source
|
7
|
+
|
8
|
+
def initialize(line:, source:, annotation:)
|
9
|
+
@line = line
|
10
|
+
@source = source
|
11
|
+
@annotation = annotation
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
other.is_a?(LocatedAnnotation) &&
|
16
|
+
other.line == line &&
|
17
|
+
other.annotation == annotation
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :path
|
22
|
+
attr_reader :node
|
23
|
+
attr_reader :mapping
|
24
|
+
|
25
|
+
def initialize(path:, node:, mapping:)
|
26
|
+
@path = path
|
27
|
+
@node = node
|
28
|
+
@mapping = mapping
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.parse(source_code, path:, labeling: ASTUtils::Labeling.new)
|
32
|
+
node = labeling.translate(::Parser::CurrentRuby.parse(source_code, path.to_s), {})
|
33
|
+
|
34
|
+
annotations = []
|
35
|
+
|
36
|
+
buffer = ::Parser::Source::Buffer.new(path.to_s)
|
37
|
+
buffer.source = source_code
|
38
|
+
parser = ::Parser::CurrentRuby.new
|
39
|
+
|
40
|
+
_, comments, _ = parser.tokenize(buffer)
|
41
|
+
comments.each do |comment|
|
42
|
+
src = comment.text.gsub(/\A#\s*/, '')
|
43
|
+
annotation = Steep::Parser.parse_annotation_opt(src)
|
44
|
+
if annotation
|
45
|
+
annotations << LocatedAnnotation.new(line: comment.location.line, source: src, annotation: annotation)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
mapping = {}
|
50
|
+
construct_mapping(node: node, annotations: annotations, mapping: mapping)
|
51
|
+
|
52
|
+
annotations.each do |annot|
|
53
|
+
mapping[node.__id__] = [] unless mapping.key?(node.__id__)
|
54
|
+
mapping[node.__id__] << annot.annotation
|
55
|
+
end
|
56
|
+
|
57
|
+
new(path: path, node: node, mapping: mapping)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.construct_mapping(node:, annotations:, mapping:)
|
61
|
+
each_child_node(node) do |child|
|
62
|
+
construct_mapping(node: child, annotations: annotations, mapping: mapping)
|
63
|
+
end
|
64
|
+
|
65
|
+
case node.type
|
66
|
+
when :def, :block, :module, :class
|
67
|
+
start_line = node.loc.line
|
68
|
+
end_line = node.loc.last_line
|
69
|
+
|
70
|
+
consumed = []
|
71
|
+
|
72
|
+
annotations.each do |annot|
|
73
|
+
if start_line <= annot.line && annot.line < end_line
|
74
|
+
consumed << annot
|
75
|
+
mapping[node.__id__] = [] unless mapping.key?(node.__id__)
|
76
|
+
mapping[node.__id__] << annot.annotation
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
consumed.each do |annot|
|
81
|
+
annotations.delete annot
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.each_child_node(node)
|
87
|
+
node.children.each do |child|
|
88
|
+
if child.is_a?(AST::Node)
|
89
|
+
yield child
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def annotations(block:)
|
95
|
+
Annotation::Collection.new(annotations: mapping[block.__id__] || [])
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,362 @@
|
|
1
|
+
module Steep
|
2
|
+
class TypeAssignability
|
3
|
+
attr_reader :signatures
|
4
|
+
attr_reader :errors
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
@signatures = {}
|
8
|
+
@klasses = []
|
9
|
+
@instances = []
|
10
|
+
@errors = []
|
11
|
+
|
12
|
+
if block_given?
|
13
|
+
yield self
|
14
|
+
validate
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def with(klass: nil, instance: nil, &block)
|
19
|
+
@klasses.push(klass) if klass
|
20
|
+
@instances.push(instance) if instance
|
21
|
+
yield
|
22
|
+
ensure
|
23
|
+
@klasses.pop if klass
|
24
|
+
@instances.pop if instance
|
25
|
+
end
|
26
|
+
|
27
|
+
def klass
|
28
|
+
@klasses.last
|
29
|
+
end
|
30
|
+
|
31
|
+
def instance
|
32
|
+
@instances.last
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_signature(signature)
|
36
|
+
raise "Signature Duplicated: #{signature.name}" if signatures.key?(signature.name)
|
37
|
+
signatures[signature.name] = signature
|
38
|
+
end
|
39
|
+
|
40
|
+
def test(src:, dest:, known_pairs: [])
|
41
|
+
case
|
42
|
+
when src.is_a?(Types::Any) || dest.is_a?(Types::Any)
|
43
|
+
true
|
44
|
+
when src == dest
|
45
|
+
true
|
46
|
+
when src.is_a?(Types::Union)
|
47
|
+
src.types.all? do |type|
|
48
|
+
test(src: type, dest: dest, known_pairs: known_pairs)
|
49
|
+
end
|
50
|
+
when dest.is_a?(Types::Union)
|
51
|
+
dest.types.any? do |type|
|
52
|
+
test(src: src, dest: type, known_pairs: known_pairs)
|
53
|
+
end
|
54
|
+
when src.is_a?(Types::Var) || dest.is_a?(Types::Var)
|
55
|
+
known_pairs.include?([src, dest])
|
56
|
+
when src.is_a?(Types::Name) && dest.is_a?(Types::Name)
|
57
|
+
test_interface(resolve_interface(src.name, src.params), resolve_interface(dest.name, dest.params), known_pairs)
|
58
|
+
else
|
59
|
+
raise "Unexpected type: src=#{src.inspect}, dest=#{dest.inspect}, known_pairs=#{known_pairs.inspect}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_application(params:, argument:, index:)
|
64
|
+
param_type = params.flat_unnamed_params[index]&.last
|
65
|
+
if param_type
|
66
|
+
unless test(src: argument, dest: param_type)
|
67
|
+
yield param_type
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_interface(src, dest, known_pairs)
|
73
|
+
if src.name == dest.name
|
74
|
+
return true
|
75
|
+
end
|
76
|
+
|
77
|
+
if known_pairs.include?([src, dest])
|
78
|
+
return true
|
79
|
+
end
|
80
|
+
|
81
|
+
pairs = known_pairs + [[src, dest]]
|
82
|
+
|
83
|
+
dest.methods.all? do |name, dest_methods|
|
84
|
+
if src.methods.key?(name)
|
85
|
+
src_methods = src.methods[name]
|
86
|
+
|
87
|
+
dest_methods.types.all? do |dest_method|
|
88
|
+
src_methods.types.any? do |src_method|
|
89
|
+
test_method(src_method, dest_method, pairs)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_method(src, dest, known_pairs)
|
97
|
+
test_params(src.params, dest.params, known_pairs) &&
|
98
|
+
test_block(src.block, dest.block, known_pairs) &&
|
99
|
+
test(src: src.return_type, dest: dest.return_type, known_pairs: known_pairs)
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_params(src, dest, known_pairs)
|
103
|
+
assigning_pairs = []
|
104
|
+
|
105
|
+
src_flat = src.flat_unnamed_params
|
106
|
+
dest_flat = dest.flat_unnamed_params
|
107
|
+
|
108
|
+
case
|
109
|
+
when dest.rest
|
110
|
+
return false unless src.rest
|
111
|
+
|
112
|
+
while src_flat.size > 0
|
113
|
+
src_type = src_flat.shift
|
114
|
+
dest_type = dest_flat.shift
|
115
|
+
|
116
|
+
if dest_type
|
117
|
+
assigning_pairs << [src_type.last, dest_type.last]
|
118
|
+
else
|
119
|
+
assigning_pairs << [src_type.last, dest.rest]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
if src.rest
|
124
|
+
assigning_pairs << [src.rest, dest.rest]
|
125
|
+
end
|
126
|
+
when src.rest
|
127
|
+
while src_flat.size > 0
|
128
|
+
src_type = src_flat.shift
|
129
|
+
dest_type = dest_flat.shift
|
130
|
+
|
131
|
+
if dest_type
|
132
|
+
assigning_pairs << [src_type.last, dest_type.last]
|
133
|
+
else
|
134
|
+
break
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
if src.rest && !dest_flat.empty?
|
139
|
+
dest_flat.each do |dest_type|
|
140
|
+
assigning_pairs << [src.rest, dest_type.last]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
when src.required.size + src.optional.size >= dest.required.size + dest.optional.size && !src.rest
|
144
|
+
while src_flat.size > 0
|
145
|
+
src_type = src_flat.shift
|
146
|
+
dest_type = dest_flat.shift
|
147
|
+
|
148
|
+
if dest_type
|
149
|
+
assigning_pairs << [src_type.last, dest_type.last]
|
150
|
+
else
|
151
|
+
break
|
152
|
+
end
|
153
|
+
end
|
154
|
+
else
|
155
|
+
return false
|
156
|
+
end
|
157
|
+
|
158
|
+
src_flat_kws = src.flat_keywords
|
159
|
+
dest_flat_kws = dest.flat_keywords
|
160
|
+
|
161
|
+
dest_flat_kws.each do |name, _|
|
162
|
+
if src_flat_kws.key?(name)
|
163
|
+
assigning_pairs << [src_flat_kws[name], dest_flat_kws[name]]
|
164
|
+
else
|
165
|
+
if src.rest_keywords
|
166
|
+
assigning_pairs << [src.rest_keywords, dest_flat_kws[name]]
|
167
|
+
else
|
168
|
+
return false
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
src.required_keywords.each do |name, _|
|
174
|
+
unless dest.required_keywords.key?(name)
|
175
|
+
return false
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
if src.rest_keywords && dest.rest_keywords
|
180
|
+
assigning_pairs << [src.rest_keywords, dest.rest_keywords]
|
181
|
+
end
|
182
|
+
|
183
|
+
assigning_pairs.all? do |pair|
|
184
|
+
src_type = pair.first
|
185
|
+
dest_type = pair.last
|
186
|
+
|
187
|
+
test(src: dest_type, dest: src_type, known_pairs: known_pairs)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_block(src, dest, known_pairs)
|
192
|
+
return true if !src && !dest
|
193
|
+
return false if !src || !dest
|
194
|
+
|
195
|
+
raise "Keyword args for block is not yet supported" unless src.params&.flat_keywords&.empty?
|
196
|
+
raise "Keyword args for block is not yet supported" unless dest.params&.flat_keywords&.empty?
|
197
|
+
|
198
|
+
ss = src.params.flat_unnamed_params
|
199
|
+
ds = dest.params.flat_unnamed_params
|
200
|
+
|
201
|
+
max = ss.size > ds.size ? ss.size : ds.size
|
202
|
+
|
203
|
+
for i in 0...max
|
204
|
+
s = ss[i]&.last || src.params.rest
|
205
|
+
d = ds[i]&.last || dest.params.rest
|
206
|
+
|
207
|
+
if s && d
|
208
|
+
test(src: s, dest: d, known_pairs: known_pairs) or return false
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
if src.params.rest && dest.params.rest
|
213
|
+
test(src: src.params.rest, dest: dest.params.rest, known_pairs: known_pairs) or return false
|
214
|
+
end
|
215
|
+
|
216
|
+
test(src: dest.return_type, dest: src.return_type, known_pairs: known_pairs)
|
217
|
+
end
|
218
|
+
|
219
|
+
def resolve_interface(name, params, klass: nil, instance: nil)
|
220
|
+
klass ||= Types::Name.module(name: name.name, params: params)
|
221
|
+
instance ||= Types::Name.instance(name: name.name, params: params)
|
222
|
+
|
223
|
+
case name
|
224
|
+
when TypeName::Interface
|
225
|
+
signatures[name.name].to_interface(klass: klass, instance: instance, params: params)
|
226
|
+
when TypeName::Instance
|
227
|
+
methods = signatures[name.name].instance_methods(assignability: self, klass: klass, instance: instance, params: params)
|
228
|
+
Interface.new(name: name, methods: methods)
|
229
|
+
when TypeName::Module
|
230
|
+
methods = signatures[name.name].module_methods(assignability: self, klass: klass, instance: instance, params: params)
|
231
|
+
Interface.new(name: name, methods: methods)
|
232
|
+
else
|
233
|
+
raise "Unexpected type name: #{name.inspect}"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def lookup_included_signature(type)
|
238
|
+
raise "#{self.class}#lookup_included_signature expects type name: #{type.inspect}" unless type.is_a?(Types::Name)
|
239
|
+
raise "#{self.class}#lookup_included_signature expects module instance name: #{type.name.inspect}" unless type.name.is_a?(TypeName::Instance)
|
240
|
+
|
241
|
+
signatures[type.name.name]
|
242
|
+
end
|
243
|
+
|
244
|
+
def lookup_super_class_signature(type)
|
245
|
+
raise "#{self.class}#lookup_super_class_signature expects type name: #{type.inspect}" unless type.is_a?(Types::Name)
|
246
|
+
raise "#{self.class}#lookup_super_class_signature expects module instance name: #{type.name.inspect}" unless type.name.is_a?(TypeName::Instance)
|
247
|
+
|
248
|
+
signature = signatures[type.name.name]
|
249
|
+
|
250
|
+
raise "#{self.class}#lookup_super_class_signature expects class: #{type.name.inspect}" unless signature.is_a?(Signature::Class)
|
251
|
+
|
252
|
+
signature
|
253
|
+
end
|
254
|
+
|
255
|
+
def lookup_class_signature(type)
|
256
|
+
raise "#{self.class}#lookup_class_signature expects type name: #{type.inspect}" unless type.is_a?(Types::Name)
|
257
|
+
raise "#{self.class}#lookup_class_signature expects instance name: #{type.name.inspect}" unless type.name.is_a?(TypeName::Instance)
|
258
|
+
|
259
|
+
signature = signatures[type.name.name]
|
260
|
+
|
261
|
+
raise "#{self.class}#lookup_super_class_signature expects class: #{signature.inspect}" unless signature.is_a?(Signature::Class)
|
262
|
+
|
263
|
+
signature
|
264
|
+
end
|
265
|
+
|
266
|
+
def lookup_extensions(module_name)
|
267
|
+
signatures.values.select do |signature|
|
268
|
+
case signature
|
269
|
+
when Signature::Extension
|
270
|
+
signature.module_name == module_name
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def method_type(type, name)
|
276
|
+
case type
|
277
|
+
when Types::Any
|
278
|
+
return type
|
279
|
+
when Types::Merge
|
280
|
+
methods = type.types.map {|t|
|
281
|
+
resolve_interface(t.name, t.params, klass: Types::Var.new(name: :some_klass), instance: Types::Var.new(name: :some_instance))
|
282
|
+
}.each.with_object({}) {|interface, methods|
|
283
|
+
methods.merge! interface.methods
|
284
|
+
}
|
285
|
+
method = methods[name]
|
286
|
+
when Types::Name
|
287
|
+
interface = resolve_interface(type.name, type.params)
|
288
|
+
method = interface.methods[name]
|
289
|
+
else
|
290
|
+
raise "Unexpected type: #{type}"
|
291
|
+
end
|
292
|
+
|
293
|
+
if method
|
294
|
+
yield(method) || Types::Any.new
|
295
|
+
else
|
296
|
+
yield(nil) || Types::Any.new
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def validate
|
301
|
+
signatures.each do |name, signature|
|
302
|
+
signature.validate(self)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def validate_type_presence(signature, type)
|
307
|
+
if type.is_a?(Types::Name)
|
308
|
+
unless signatures[type.name.name]
|
309
|
+
errors << Signature::Errors::UnknownTypeName.new(signature: signature, type: type)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def validate_method_compatibility(signature, method_name, method)
|
315
|
+
if method.super_method
|
316
|
+
test = method.types.all? {|method_type|
|
317
|
+
method.super_method.types.any? {|super_type|
|
318
|
+
test_method(method_type, super_type, [])
|
319
|
+
}
|
320
|
+
}
|
321
|
+
|
322
|
+
unless test
|
323
|
+
errors << Signature::Errors::IncompatibleOverride.new(signature: signature,
|
324
|
+
method_name: method_name,
|
325
|
+
this_method: method.types,
|
326
|
+
super_method: method.super_method.types)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def compact(types)
|
332
|
+
types = types.reject {|type| type.is_a?(Types::Any) }
|
333
|
+
|
334
|
+
if types.empty?
|
335
|
+
[Types::Any.new]
|
336
|
+
else
|
337
|
+
compact0(types)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def compact0(types)
|
342
|
+
if types.size == 1
|
343
|
+
types
|
344
|
+
else
|
345
|
+
type, *types_ = types
|
346
|
+
compacted = compact0(types_)
|
347
|
+
compacted.flat_map do |type_|
|
348
|
+
case
|
349
|
+
when type == type_
|
350
|
+
[type]
|
351
|
+
when test(src: type_, dest: type)
|
352
|
+
[type]
|
353
|
+
when test(src: type, dest: type_)
|
354
|
+
[type_]
|
355
|
+
else
|
356
|
+
[type, type_]
|
357
|
+
end
|
358
|
+
end.uniq
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|