steep 0.31.0 → 0.35.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/lib/steep.rb +3 -2
- data/lib/steep/annotation_parser.rb +1 -1
- data/lib/steep/ast/types/factory.rb +66 -60
- data/lib/steep/cli.rb +15 -2
- data/lib/steep/drivers/print_project.rb +11 -0
- data/lib/steep/drivers/stats.rb +85 -0
- data/lib/steep/drivers/vendor.rb +1 -20
- 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 +24 -15
- data/lib/steep/project/dsl.rb +13 -17
- data/lib/steep/project/options.rb +4 -4
- data/lib/steep/project/source_file.rb +2 -1
- data/lib/steep/project/target.rb +19 -10
- data/lib/steep/server/interaction_worker.rb +1 -1
- data/lib/steep/server/utils.rb +1 -1
- data/lib/steep/source.rb +3 -3
- data/lib/steep/subtyping/check.rb +30 -16
- data/lib/steep/subtyping/variable_occurrence.rb +2 -0
- data/lib/steep/type_construction.rb +585 -416
- 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 +1 -1
- metadata +10 -6
- data/lib/steep/ast/buffer.rb +0 -51
- data/lib/steep/ast/location.rb +0 -86
data/lib/steep/drivers/vendor.rb
CHANGED
@@ -18,26 +18,7 @@ module Steep
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def run
|
21
|
-
stdout.puts "
|
22
|
-
|
23
|
-
vendorer = RBS::Vendorer.new(vendor_dir: vendor_dir)
|
24
|
-
|
25
|
-
if clean_before
|
26
|
-
stdout.puts " Cleaning directory..."
|
27
|
-
vendorer.clean!
|
28
|
-
end
|
29
|
-
|
30
|
-
stdout.puts " Vendoring standard libraries..."
|
31
|
-
vendorer.stdlib!
|
32
|
-
|
33
|
-
if defined?(Bundler)
|
34
|
-
Bundler.locked_gems.specs.each do |spec|
|
35
|
-
if RBS::EnvironmentLoader.gem_sig_path(spec.name, spec.version.to_s).directory?
|
36
|
-
stdout.puts " Vendoring rubygem: #{spec.full_name}..."
|
37
|
-
vendorer.gem! spec.name, spec.version.to_s
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
21
|
+
stdout.puts "`steep vendor` is deprecated. Use `rbs vendor` command directly"
|
41
22
|
|
42
23
|
0
|
43
24
|
end
|
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
|
|
@@ -245,15 +263,15 @@ module Steep
|
|
245
263
|
items << MethodNameItem.new(
|
246
264
|
identifier: name,
|
247
265
|
range: range,
|
248
|
-
|
249
|
-
method_type:
|
250
|
-
|
266
|
+
receiver_type: type,
|
267
|
+
method_type: subtyping.factory.method_type_1(method_type, self_type: type),
|
268
|
+
method_decls: method_type.method_decls
|
251
269
|
)
|
252
270
|
end
|
253
271
|
end
|
254
272
|
end
|
255
273
|
end
|
256
|
-
rescue
|
274
|
+
rescue RuntimeError => exn
|
257
275
|
# nop
|
258
276
|
end
|
259
277
|
|
@@ -298,15 +316,6 @@ module Steep
|
|
298
316
|
index
|
299
317
|
end
|
300
318
|
|
301
|
-
def inherited_method?(method_def, type)
|
302
|
-
case type
|
303
|
-
when AST::Types::Name::Instance, AST::Types::Name::Singleton, AST::Types::Name::Interface
|
304
|
-
method_def.implemented_in != type.name
|
305
|
-
else
|
306
|
-
false
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
319
|
def disallowed_method?(name)
|
311
320
|
# initialize isn't invoked by developers when creating
|
312
321
|
# instances of new classes, so don't show it as
|
data/lib/steep/project/dsl.rb
CHANGED
@@ -7,12 +7,12 @@ module Steep
|
|
7
7
|
attr_reader :libraries
|
8
8
|
attr_reader :signatures
|
9
9
|
attr_reader :ignored_sources
|
10
|
-
attr_reader :no_builtin
|
11
10
|
attr_reader :vendor_dir
|
12
11
|
attr_reader :strictness_level
|
13
12
|
attr_reader :typing_option_hash
|
13
|
+
attr_reader :repo_paths
|
14
14
|
|
15
|
-
def initialize(name, sources: [], libraries: [], signatures: [], ignored_sources: [])
|
15
|
+
def initialize(name, sources: [], libraries: [], signatures: [], ignored_sources: [], repo_paths: [])
|
16
16
|
@name = name
|
17
17
|
@sources = sources
|
18
18
|
@libraries = libraries
|
@@ -21,6 +21,7 @@ module Steep
|
|
21
21
|
@vendor_dir = nil
|
22
22
|
@strictness_level = :default
|
23
23
|
@typing_option_hash = {}
|
24
|
+
@repo_paths = []
|
24
25
|
end
|
25
26
|
|
26
27
|
def initialize_copy(other)
|
@@ -32,6 +33,7 @@ module Steep
|
|
32
33
|
@vendor_dir = other.vendor_dir
|
33
34
|
@strictness_level = other.strictness_level
|
34
35
|
@typing_option_hash = other.typing_option_hash
|
36
|
+
@repo_paths = other.repo_paths.dup
|
35
37
|
end
|
36
38
|
|
37
39
|
def check(*args)
|
@@ -71,13 +73,14 @@ module Steep
|
|
71
73
|
|
72
74
|
def vendor(dir = "vendor/sigs", stdlib: nil, gems: nil)
|
73
75
|
if stdlib || gems
|
74
|
-
|
75
|
-
stdlib&.yield_self {|x| Pathname(x) },
|
76
|
-
gems&.yield_self {|x| Pathname(x) }
|
77
|
-
]
|
78
|
-
else
|
79
|
-
@vendor_dir = Pathname(dir)
|
76
|
+
Steep.logger.warn { "#vendor with stdlib: or gems: keyword is deprecated." }
|
80
77
|
end
|
78
|
+
|
79
|
+
@vendor_dir = Pathname(dir)
|
80
|
+
end
|
81
|
+
|
82
|
+
def repo_path(*paths)
|
83
|
+
@repo_paths.push(*paths.map {|s| Pathname(s) })
|
81
84
|
end
|
82
85
|
end
|
83
86
|
|
@@ -124,6 +127,8 @@ module Steep
|
|
124
127
|
signature_patterns: target.signatures,
|
125
128
|
options: Options.new.tap do |options|
|
126
129
|
options.libraries.push(*target.libraries)
|
130
|
+
options.repository_paths.push(*target.repo_paths)
|
131
|
+
options.vendor_path = target.vendor_dir
|
127
132
|
|
128
133
|
case target.strictness_level
|
129
134
|
when :strict
|
@@ -133,15 +138,6 @@ module Steep
|
|
133
138
|
end
|
134
139
|
|
135
140
|
options.merge!(target.typing_option_hash)
|
136
|
-
|
137
|
-
case target.vendor_dir
|
138
|
-
when Array
|
139
|
-
options.vendored_stdlib_path = target.vendor_dir[0]
|
140
|
-
options.vendored_gems_path = target.vendor_dir[1]
|
141
|
-
when Pathname
|
142
|
-
options.vendored_stdlib_path = target.vendor_dir + "stdlib"
|
143
|
-
options.vendored_gems_path = target.vendor_dir + "gems"
|
144
|
-
end
|
145
141
|
end
|
146
142
|
).tap do |target|
|
147
143
|
project.targets << target
|
@@ -5,16 +5,16 @@ module Steep
|
|
5
5
|
attr_accessor :allow_missing_definitions
|
6
6
|
attr_accessor :allow_unknown_constant_assignment
|
7
7
|
attr_accessor :allow_unknown_method_calls
|
8
|
-
attr_accessor :
|
9
|
-
attr_accessor :vendored_gems_path
|
8
|
+
attr_accessor :vendor_path
|
10
9
|
attr_reader :libraries
|
10
|
+
attr_reader :repository_paths
|
11
11
|
|
12
12
|
def initialize
|
13
13
|
apply_default_typing_options!
|
14
|
-
self.
|
15
|
-
self.vendored_stdlib_path = nil
|
14
|
+
self.vendor_path = nil
|
16
15
|
|
17
16
|
@libraries = []
|
17
|
+
@repository_paths = []
|
18
18
|
end
|
19
19
|
|
20
20
|
def apply_default_typing_options!
|
@@ -66,7 +66,8 @@ module Steep
|
|
66
66
|
break_context: nil,
|
67
67
|
self_type: AST::Builtin::Object.instance_type,
|
68
68
|
type_env: type_env,
|
69
|
-
lvar_env: lvar_env
|
69
|
+
lvar_env: lvar_env,
|
70
|
+
call_context: TypeInference::MethodCall::TopLevelContext.new
|
70
71
|
)
|
71
72
|
|
72
73
|
typing = Typing.new(source: source, root_context: context)
|
data/lib/steep/project/target.rb
CHANGED
@@ -114,18 +114,27 @@ module Steep
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
options.libraries.each do |lib|
|
123
|
-
loader.add(library: lib)
|
124
|
-
end
|
125
|
-
loader.load(env: env)
|
117
|
+
def self.construct_env_loader(options:)
|
118
|
+
repo = RBS::Repository.new(no_stdlib: options.vendor_path)
|
119
|
+
options.repository_paths.each do |path|
|
120
|
+
repo.add(path)
|
121
|
+
end
|
126
122
|
|
127
|
-
|
123
|
+
loader = RBS::EnvironmentLoader.new(
|
124
|
+
core_root: options.vendor_path ? nil : RBS::EnvironmentLoader::DEFAULT_CORE_ROOT,
|
125
|
+
repository: repo
|
126
|
+
)
|
127
|
+
loader.add(path: options.vendor_path) if options.vendor_path
|
128
|
+
options.libraries.each do |lib|
|
129
|
+
name, version = lib.split(/:/, 2)
|
130
|
+
loader.add(library: name, version: version)
|
128
131
|
end
|
132
|
+
|
133
|
+
loader
|
134
|
+
end
|
135
|
+
|
136
|
+
def environment
|
137
|
+
@environment ||= RBS::Environment.from_loader(Target.construct_env_loader(options: options))
|
129
138
|
end
|
130
139
|
|
131
140
|
def load_signatures(validate:)
|
@@ -196,7 +196,7 @@ HOVER
|
|
196
196
|
),
|
197
197
|
documentation: item.comment&.string,
|
198
198
|
insert_text_format: LanguageServer::Protocol::Constant::InsertTextFormat::SNIPPET,
|
199
|
-
sort_text: item.
|
199
|
+
sort_text: item.inherited? ? 'z' : 'a' # Ensure language server puts non-inherited methods before inherited methods
|
200
200
|
)
|
201
201
|
when Project::CompletionProvider::InstanceVariableItem
|
202
202
|
label = "#{item.identifier}: #{item.type}"
|
data/lib/steep/server/utils.rb
CHANGED
@@ -13,7 +13,7 @@ module Steep
|
|
13
13
|
if range
|
14
14
|
text = text.dup
|
15
15
|
|
16
|
-
buf =
|
16
|
+
buf = RBS::Buffer.new(name: :_, content: text)
|
17
17
|
|
18
18
|
start_pos = buf.loc_to_pos(range[:start].yield_self {|pos| [pos[:line]+1, pos[:character]] })
|
19
19
|
end_pos = buf.loc_to_pos(range[:end].yield_self {|pos| [pos[:line]+1, pos[:character]] })
|
data/lib/steep/source.rb
CHANGED
@@ -65,11 +65,11 @@ module Steep
|
|
65
65
|
parser.tokenize(buffer)
|
66
66
|
end
|
67
67
|
|
68
|
-
buffer =
|
68
|
+
buffer = RBS::Buffer.new(name: path, content: source_code)
|
69
69
|
|
70
70
|
comments.each do |comment|
|
71
71
|
src = comment.text.gsub(/\A#\s*/, '')
|
72
|
-
location =
|
72
|
+
location = RBS::Location.new(buffer: buffer,
|
73
73
|
start_pos: comment.location.expression.begin_pos + 1,
|
74
74
|
end_pos: comment.location.expression.end_pos)
|
75
75
|
annotation = AnnotationParser.new(factory: factory).parse(src, location: location)
|
@@ -107,7 +107,7 @@ module Steep
|
|
107
107
|
|
108
108
|
if node.children[1]
|
109
109
|
if node.loc.keyword.source == "if" || node.loc.keyword.source == "elsif"
|
110
|
-
then_start = node.loc.begin&.
|
110
|
+
then_start = node.loc.begin&.last_line || node.children[0].loc.last_line
|
111
111
|
then_end = node.children[2] ? node.loc.else.line : node.loc.last_line
|
112
112
|
else
|
113
113
|
then_start = node.loc.else.last_line
|