steep 0.30.0 → 0.34.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/CHANGELOG.md +26 -0
- data/bin/steep-prof +1 -2
- data/lib/steep.rb +3 -2
- data/lib/steep/annotation_parser.rb +1 -1
- data/lib/steep/ast/types/factory.rb +79 -60
- data/lib/steep/cli.rb +14 -1
- data/lib/steep/drivers/stats.rb +85 -0
- data/lib/steep/errors.rb +19 -15
- data/lib/steep/interface/method_type.rb +12 -23
- data/lib/steep/method_name.rb +28 -0
- data/lib/steep/project/completion_provider.rb +33 -22
- data/lib/steep/project/hover_content.rb +91 -80
- data/lib/steep/project/source_file.rb +2 -1
- data/lib/steep/server/interaction_worker.rb +43 -39
- data/lib/steep/server/utils.rb +1 -1
- data/lib/steep/source.rb +60 -3
- data/lib/steep/subtyping/variable_occurrence.rb +2 -0
- data/lib/steep/type_construction.rb +577 -415
- data/lib/steep/type_inference/context.rb +7 -3
- data/lib/steep/type_inference/context_array.rb +1 -1
- data/lib/steep/type_inference/local_variable_type_env.rb +10 -1
- data/lib/steep/type_inference/logic_type_interpreter.rb +6 -0
- data/lib/steep/type_inference/method_call.rb +116 -0
- data/lib/steep/typing.rb +38 -8
- data/lib/steep/version.rb +1 -1
- data/smoke/regression/fun.rb +8 -0
- data/smoke/regression/fun.rbs +4 -0
- data/smoke/regression/range.rb +5 -0
- data/steep.gemspec +2 -2
- metadata +12 -8
- data/lib/steep/ast/buffer.rb +0 -51
- data/lib/steep/ast/location.rb +0 -86
data/lib/steep/errors.rb
CHANGED
@@ -101,20 +101,6 @@ module Steep
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
class IncompatibleBlockParameters < Base
|
105
|
-
attr_reader :node
|
106
|
-
attr_reader :method_type
|
107
|
-
|
108
|
-
def initialize(node:, method_type:)
|
109
|
-
super(node: node)
|
110
|
-
@method_type = method_type
|
111
|
-
end
|
112
|
-
|
113
|
-
def to_s
|
114
|
-
"#{location_to_str}: IncompatibleBlockParameters: method_type=#{method_type}"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
104
|
class BlockParameterTypeMismatch < Base
|
119
105
|
attr_reader :expected
|
120
106
|
attr_reader :actual
|
@@ -186,7 +172,7 @@ module Steep
|
|
186
172
|
end
|
187
173
|
|
188
174
|
def to_s
|
189
|
-
"#{location_to_str}: RequiredBlockMissing: method_type=#{method_type.
|
175
|
+
"#{location_to_str}: RequiredBlockMissing: method_type=#{method_type.to_s}"
|
190
176
|
end
|
191
177
|
end
|
192
178
|
|
@@ -557,5 +543,23 @@ module Steep
|
|
557
543
|
"#{location_to_str}: UnsupportedSyntax: #{msg}"
|
558
544
|
end
|
559
545
|
end
|
546
|
+
|
547
|
+
class UnexpectedError < Base
|
548
|
+
attr_reader :message
|
549
|
+
attr_reader :error
|
550
|
+
|
551
|
+
def initialize(node:, error:)
|
552
|
+
super(node: node)
|
553
|
+
@error = error
|
554
|
+
@message = error.message
|
555
|
+
end
|
556
|
+
|
557
|
+
def to_s
|
558
|
+
<<-MESSAGE
|
559
|
+
#{location_to_str}: UnexpectedError: #{error.class}
|
560
|
+
>> #{message}
|
561
|
+
MESSAGE
|
562
|
+
end
|
563
|
+
end
|
560
564
|
end
|
561
565
|
end
|
@@ -774,16 +774,14 @@ module Steep
|
|
774
774
|
attr_reader :params
|
775
775
|
attr_reader :block
|
776
776
|
attr_reader :return_type
|
777
|
-
attr_reader :
|
778
|
-
attr_reader :method_def
|
777
|
+
attr_reader :method_decls
|
779
778
|
|
780
|
-
def initialize(type_params:, params:, block:, return_type:,
|
779
|
+
def initialize(type_params:, params:, block:, return_type:, method_decls:)
|
781
780
|
@type_params = type_params
|
782
781
|
@params = params
|
783
782
|
@block = block
|
784
783
|
@return_type = return_type
|
785
|
-
@
|
786
|
-
@method_def = method_def
|
784
|
+
@method_decls = method_decls
|
787
785
|
end
|
788
786
|
|
789
787
|
def ==(other)
|
@@ -791,9 +789,7 @@ module Steep
|
|
791
789
|
other.type_params == type_params &&
|
792
790
|
other.params == params &&
|
793
791
|
other.block == block &&
|
794
|
-
other.return_type == return_type
|
795
|
-
(!other.method_def || !method_def || other.method_def == method_def) &&
|
796
|
-
(!other.location || !location || other.location == location)
|
792
|
+
other.return_type == return_type
|
797
793
|
end
|
798
794
|
|
799
795
|
alias eql? ==
|
@@ -824,8 +820,7 @@ module Steep
|
|
824
820
|
params: params.subst(s_),
|
825
821
|
block: block&.subst(s_),
|
826
822
|
return_type: return_type.subst(s_),
|
827
|
-
|
828
|
-
location: location
|
823
|
+
method_decls: method_decls
|
829
824
|
)
|
830
825
|
end
|
831
826
|
|
@@ -847,17 +842,15 @@ module Steep
|
|
847
842
|
params: params.subst(s),
|
848
843
|
block: block&.subst(s),
|
849
844
|
return_type: return_type.subst(s),
|
850
|
-
|
851
|
-
method_def: method_def)
|
845
|
+
method_decls: method_decls)
|
852
846
|
end
|
853
847
|
|
854
|
-
def with(type_params: self.type_params, params: self.params, block: self.block, return_type: self.return_type,
|
848
|
+
def with(type_params: self.type_params, params: self.params, block: self.block, return_type: self.return_type, method_decls: self.method_decls)
|
855
849
|
self.class.new(type_params: type_params,
|
856
850
|
params: params,
|
857
851
|
block: block,
|
858
852
|
return_type: return_type,
|
859
|
-
|
860
|
-
location: location)
|
853
|
+
method_decls: method_decls)
|
861
854
|
end
|
862
855
|
|
863
856
|
def to_s
|
@@ -873,8 +866,7 @@ module Steep
|
|
873
866
|
params: params.map_type(&block),
|
874
867
|
block: self.block&.yield_self {|blk| blk.map_type(&block) },
|
875
868
|
return_type: yield(return_type),
|
876
|
-
|
877
|
-
method_def: method_def)
|
869
|
+
method_decls: method_decls)
|
878
870
|
end
|
879
871
|
|
880
872
|
# Returns a new method type which can be used for the method implementation type of both `self` and `other`.
|
@@ -902,8 +894,7 @@ module Steep
|
|
902
894
|
return_type: AST::Types::Union.build(
|
903
895
|
types: [return_type.subst(s1),other.return_type.subst(s2)]
|
904
896
|
),
|
905
|
-
|
906
|
-
location: nil
|
897
|
+
method_decls: method_decls + other.method_decls
|
907
898
|
)
|
908
899
|
end
|
909
900
|
|
@@ -958,8 +949,7 @@ module Steep
|
|
958
949
|
block: block,
|
959
950
|
return_type: return_type,
|
960
951
|
type_params: type_params,
|
961
|
-
|
962
|
-
location: nil
|
952
|
+
method_decls: method_decls + other.method_decls
|
963
953
|
)
|
964
954
|
end
|
965
955
|
|
@@ -1006,8 +996,7 @@ module Steep
|
|
1006
996
|
block: block,
|
1007
997
|
return_type: return_type,
|
1008
998
|
type_params: type_params,
|
1009
|
-
|
1010
|
-
location: nil
|
999
|
+
method_decls: method_decls + other.method_decls
|
1011
1000
|
)
|
1012
1001
|
end
|
1013
1002
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Steep
|
2
|
+
InstanceMethodName = Struct.new(:type_name, :method_name, keyword_init: true) do
|
3
|
+
def to_s
|
4
|
+
"#{type_name}##{method_name}"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
SingletonMethodName = Struct.new(:type_name, :method_name, keyword_init: true) do
|
9
|
+
def to_s
|
10
|
+
"#{type_name}.#{method_name}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ::Kernel
|
15
|
+
def MethodName(string)
|
16
|
+
case string
|
17
|
+
when /#/
|
18
|
+
type_name, method_name = string.split(/#/, 2)
|
19
|
+
InstanceMethodName.new(type_name: TypeName(type_name), method_name: method_name.to_sym)
|
20
|
+
when /\./
|
21
|
+
type_name, method_name = string.split(/\./, 2)
|
22
|
+
SingletonMethodName.new(type_name: TypeName(type_name), method_name: method_name.to_sym)
|
23
|
+
else
|
24
|
+
raise "Unexpected method name: #{string}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -10,9 +10,27 @@ module Steep
|
|
10
10
|
|
11
11
|
InstanceVariableItem = Struct.new(:identifier, :range, :type, keyword_init: true)
|
12
12
|
LocalVariableItem = Struct.new(:identifier, :range, :type, keyword_init: true)
|
13
|
-
MethodNameItem = Struct.new(:identifier, :range, :
|
13
|
+
MethodNameItem = Struct.new(:identifier, :range, :receiver_type, :method_type, :method_decls, keyword_init: true) do
|
14
14
|
def comment
|
15
|
-
|
15
|
+
case method_decls.size
|
16
|
+
when 0
|
17
|
+
nil
|
18
|
+
when 1
|
19
|
+
method_decls.to_a.first.method_def&.comment
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def inherited?
|
26
|
+
case receiver_type
|
27
|
+
when AST::Types::Name::Instance, AST::Types::Name::Singleton, AST::Types::Name::Interface
|
28
|
+
method_decls.any? do |decl|
|
29
|
+
decl.method_name.type_name != receiver_type.name
|
30
|
+
end
|
31
|
+
else
|
32
|
+
false
|
33
|
+
end
|
16
34
|
end
|
17
35
|
end
|
18
36
|
|
@@ -29,11 +47,13 @@ module Steep
|
|
29
47
|
@subtyping = subtyping
|
30
48
|
end
|
31
49
|
|
32
|
-
def type_check!(text)
|
50
|
+
def type_check!(text, line:, column:)
|
33
51
|
@modified_text = text
|
34
52
|
|
35
53
|
Steep.measure "parsing" do
|
36
|
-
@source = SourceFile
|
54
|
+
@source = SourceFile
|
55
|
+
.parse(text, path: path, factory: subtyping.factory)
|
56
|
+
.without_unrelated_defs(line: line, column: column)
|
37
57
|
end
|
38
58
|
|
39
59
|
Steep.measure "typechecking" do
|
@@ -53,7 +73,7 @@ module Steep
|
|
53
73
|
begin
|
54
74
|
Steep.logger.tagged "completion_provider#run(line: #{line}, column: #{column})" do
|
55
75
|
Steep.measure "type_check!" do
|
56
|
-
type_check!(source_text)
|
76
|
+
type_check!(source_text, line: line, column: column)
|
57
77
|
end
|
58
78
|
end
|
59
79
|
|
@@ -66,11 +86,11 @@ module Steep
|
|
66
86
|
case possible_trigger
|
67
87
|
when "."
|
68
88
|
source_text[index-1] = " "
|
69
|
-
type_check!(source_text)
|
89
|
+
type_check!(source_text, line: line, column: column)
|
70
90
|
items_for_dot(position: position)
|
71
91
|
when "@"
|
72
92
|
source_text[index-1] = " "
|
73
|
-
type_check!(source_text)
|
93
|
+
type_check!(source_text, line: line, column: column)
|
74
94
|
items_for_atmark(position: position)
|
75
95
|
else
|
76
96
|
[]
|
@@ -219,14 +239,14 @@ module Steep
|
|
219
239
|
def items_for_atmark(position:)
|
220
240
|
# @ ←
|
221
241
|
shift_pos = position-1
|
222
|
-
node, *
|
242
|
+
node, *_ = source.find_nodes(line: shift_pos.line, column: shift_pos.column)
|
223
243
|
node ||= source.node
|
224
244
|
|
225
245
|
return [] unless node
|
226
246
|
|
227
247
|
context = typing.context_at(line: position.line, column: position.column)
|
228
248
|
items = []
|
229
|
-
instance_variable_items_for_context(context, prefix: "", position: position, items: items)
|
249
|
+
instance_variable_items_for_context(context, prefix: "@", position: position, items: items)
|
230
250
|
items
|
231
251
|
end
|
232
252
|
|
@@ -243,15 +263,15 @@ module Steep
|
|
243
263
|
items << MethodNameItem.new(
|
244
264
|
identifier: name,
|
245
265
|
range: range,
|
246
|
-
|
247
|
-
method_type:
|
248
|
-
|
266
|
+
receiver_type: type,
|
267
|
+
method_type: subtyping.factory.method_type_1(method_type, self_type: type),
|
268
|
+
method_decls: method_type.method_decls
|
249
269
|
)
|
250
270
|
end
|
251
271
|
end
|
252
272
|
end
|
253
273
|
end
|
254
|
-
rescue
|
274
|
+
rescue RuntimeError => exn
|
255
275
|
# nop
|
256
276
|
end
|
257
277
|
|
@@ -296,15 +316,6 @@ module Steep
|
|
296
316
|
index
|
297
317
|
end
|
298
318
|
|
299
|
-
def inherited_method?(method_def, type)
|
300
|
-
case type
|
301
|
-
when AST::Types::Name::Instance, AST::Types::Name::Singleton, AST::Types::Name::Interface
|
302
|
-
method_def.implemented_in != type.name
|
303
|
-
else
|
304
|
-
false
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
319
|
def disallowed_method?(name)
|
309
320
|
# initialize isn't invoked by developers when creating
|
310
321
|
# instances of new classes, so don't show it as
|
@@ -36,102 +36,113 @@ module Steep
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
def typecheck(target, path:, line:, column:)
|
40
|
+
target.type_check(target_sources: [], validate_signatures: false)
|
41
|
+
|
42
|
+
case (status = target.status)
|
43
|
+
when Project::Target::TypeCheckStatus
|
44
|
+
subtyping = status.subtyping
|
45
|
+
source = SourceFile
|
46
|
+
.parse(target.source_files[path].content, path: path, factory: subtyping.factory)
|
47
|
+
.without_unrelated_defs(line: line, column: column)
|
48
|
+
SourceFile.type_check(source, subtyping: subtyping)
|
49
|
+
end
|
50
|
+
rescue
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
|
39
54
|
def content_for(path:, line:, column:)
|
40
|
-
target = project.
|
55
|
+
target = project.target_for_source_path(path)
|
41
56
|
|
42
57
|
if target
|
43
|
-
|
44
|
-
|
58
|
+
typing = typecheck(target, path: path, line: line, column: column) or return
|
59
|
+
|
60
|
+
node, *parents = typing.source.find_nodes(line: line, column: column)
|
61
|
+
|
62
|
+
if node
|
63
|
+
case node.type
|
64
|
+
when :lvar
|
65
|
+
var_name = node.children[0]
|
66
|
+
context = typing.context_at(line: line, column: column)
|
67
|
+
var_type = context.lvar_env[var_name.name] || AST::Types::Any.new(location: nil)
|
45
68
|
|
46
|
-
|
47
|
-
|
48
|
-
|
69
|
+
VariableContent.new(node: node, name: var_name.name, type: var_type, location: node.location.name)
|
70
|
+
when :lvasgn
|
71
|
+
var_name, rhs = node.children
|
72
|
+
context = typing.context_at(line: line, column: column)
|
73
|
+
type = context.lvar_env[var_name.name] || typing.type_of(node: rhs)
|
49
74
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
var_name = node.children[0]
|
54
|
-
context = status.typing.context_at(line: line, column: column)
|
55
|
-
var_type = context.lvar_env[var_name.name] || AST::Types::Any.new(location: nil)
|
75
|
+
VariableContent.new(node: node, name: var_name.name, type: type, location: node.location.name)
|
76
|
+
when :send
|
77
|
+
receiver, method_name, *_ = node.children
|
56
78
|
|
57
|
-
VariableContent.new(node: node, name: var_name.name, type: var_type, location: node.location.name)
|
58
|
-
when :lvasgn
|
59
|
-
var_name, rhs = node.children
|
60
|
-
context = status.typing.context_at(line: line, column: column)
|
61
|
-
type = context.lvar_env[var_name.name] || status.typing.type_of(node: rhs)
|
62
79
|
|
63
|
-
|
64
|
-
|
65
|
-
|
80
|
+
result_node = if parents[0]&.type == :block
|
81
|
+
parents[0]
|
82
|
+
else
|
83
|
+
node
|
84
|
+
end
|
66
85
|
|
86
|
+
context = typing.context_at(line: line, column: column)
|
67
87
|
|
68
|
-
|
69
|
-
|
88
|
+
receiver_type = if receiver
|
89
|
+
typing.type_of(node: receiver)
|
70
90
|
else
|
71
|
-
|
91
|
+
context.self_type
|
72
92
|
end
|
73
93
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
when AST::Types::Name::Instance
|
85
|
-
method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
|
86
|
-
if method_definition&.defined_in
|
87
|
-
owner_name = method_definition.defined_in
|
88
|
-
[
|
89
|
-
InstanceMethodName.new(owner_name, method_name),
|
90
|
-
method_definition
|
91
|
-
]
|
92
|
-
end
|
93
|
-
when AST::Types::Name::Singleton
|
94
|
-
method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
|
95
|
-
if method_definition&.defined_in
|
96
|
-
owner_name = method_definition.defined_in
|
97
|
-
[
|
98
|
-
SingletonMethodName.new(owner_name, method_name),
|
99
|
-
method_definition
|
100
|
-
]
|
101
|
-
end
|
102
|
-
else
|
103
|
-
nil
|
94
|
+
factory = context.type_env.subtyping.factory
|
95
|
+
method_name, definition = case receiver_type
|
96
|
+
when AST::Types::Name::Instance
|
97
|
+
method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
|
98
|
+
if method_definition&.defined_in
|
99
|
+
owner_name = method_definition.defined_in
|
100
|
+
[
|
101
|
+
InstanceMethodName.new(owner_name, method_name),
|
102
|
+
method_definition
|
103
|
+
]
|
104
104
|
end
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
105
|
+
when AST::Types::Name::Singleton
|
106
|
+
method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
|
107
|
+
if method_definition&.defined_in
|
108
|
+
owner_name = method_definition.defined_in
|
109
|
+
[
|
110
|
+
SingletonMethodName.new(owner_name, method_name),
|
111
|
+
method_definition
|
112
|
+
]
|
113
|
+
end
|
114
|
+
else
|
115
|
+
nil
|
116
|
+
end
|
117
|
+
|
118
|
+
MethodCallContent.new(
|
119
|
+
node: node,
|
120
|
+
method_name: method_name,
|
121
|
+
type: typing.type_of(node: result_node),
|
122
|
+
definition: definition,
|
123
|
+
location: result_node.location.expression
|
124
|
+
)
|
125
|
+
when :def, :defs
|
126
|
+
context = typing.context_at(line: line, column: column)
|
127
|
+
method_context = context.method_context
|
128
|
+
|
129
|
+
if method_context && method_context.method
|
130
|
+
DefinitionContent.new(
|
130
131
|
node: node,
|
131
|
-
|
132
|
-
|
132
|
+
method_name: method_context.name,
|
133
|
+
method_type: method_context.method_type,
|
134
|
+
definition: method_context.method,
|
135
|
+
location: node.loc.expression
|
133
136
|
)
|
134
137
|
end
|
138
|
+
else
|
139
|
+
type = typing.type_of(node: node)
|
140
|
+
|
141
|
+
TypeContent.new(
|
142
|
+
node: node,
|
143
|
+
type: type,
|
144
|
+
location: node.location.expression
|
145
|
+
)
|
135
146
|
end
|
136
147
|
end
|
137
148
|
end
|