steep 0.31.0 → 0.35.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 +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
|