steep 0.49.1 → 0.50.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 +10 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +2 -2
- data/lib/steep/cli.rb +5 -0
- data/lib/steep/drivers/check.rb +1 -0
- data/lib/steep/drivers/langserver.rb +2 -2
- data/lib/steep/drivers/stats.rb +1 -0
- data/lib/steep/drivers/utils/jobs_count.rb +1 -1
- data/lib/steep/drivers/watch.rb +1 -1
- data/lib/steep/interface/function.rb +5 -0
- data/lib/steep/project.rb +15 -1
- data/lib/steep/server/interaction_worker.rb +2 -2
- data/lib/steep/server/master.rb +9 -4
- data/lib/steep/server/type_check_worker.rb +19 -4
- data/lib/steep/server/worker_process.rb +15 -6
- data/lib/steep/services/goto_service.rb +19 -4
- data/lib/steep/type_construction.rb +31 -14
- data/lib/steep/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ff552f6d8f112693dc9969f20d851ddbc6d7d2f16cebd45f802a5d703618b58
|
4
|
+
data.tar.gz: 723464fe34c81c3e83b66338dfc6fd3e7c3da2aaf30c1fc48116c7de794ca961
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf9f83791cfb636c65a26f404fb164fa7fc3906376e36a79a1ca4ae7eeab8020e23c5b9ce5e649a38ed79080d0aa2c00fe53a5cce8a1c76c259237f38880bbf2
|
7
|
+
data.tar.gz: 25bd9e11db283acdfc957682860e674d544b82be1b5a68bc87ca96888907966b721301c937cdaa3e06bf0226ec82fa8c78eacfaf4987637a601f75ca8d8e950c
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
# 0.50.0 (2022-03-22)
|
6
|
+
|
7
|
+
* CLI option for override steep command at spawn worker ([\#511](https://github.com/soutaro/steep/pull/511))
|
8
|
+
* LSP related improvements for Sublime LSP ([\#513](https://github.com/soutaro/steep/pull/513))
|
9
|
+
* Support Windows environment ([\#514](https://github.com/soutaro/steep/pull/514))
|
10
|
+
* Let `&:foo` proc work with methods with optional parameters ([\#516](https://github.com/soutaro/steep/pull/516))
|
11
|
+
* Fix unexpected error when or-asgn/and-asgn ([\#517](https://github.com/soutaro/steep/pull/517))
|
12
|
+
* Fix goto-definition from method call inside block ([\#518](https://github.com/soutaro/steep/pull/518))
|
13
|
+
* Better splat in array typing ([\#519](https://github.com/soutaro/steep/pull/519))
|
14
|
+
|
5
15
|
## 0.49.1 (2022-03-11)
|
6
16
|
|
7
17
|
* Fix lambda typing ([\#506](https://github.com/soutaro/steep/pull/506))
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
steep (0.
|
4
|
+
steep (0.50.0)
|
5
5
|
activesupport (>= 5.1)
|
6
6
|
language_server-protocol (>= 3.15, < 4.0)
|
7
7
|
listen (~> 3.0)
|
@@ -41,7 +41,7 @@ GEM
|
|
41
41
|
minitest (5.15.0)
|
42
42
|
minitest-hooks (1.5.0)
|
43
43
|
minitest (> 5.3)
|
44
|
-
parallel (1.
|
44
|
+
parallel (1.22.0)
|
45
45
|
parser (3.1.1.0)
|
46
46
|
ast (~> 2.4.1)
|
47
47
|
rainbow (3.1.1)
|
data/lib/steep/cli.rb
CHANGED
@@ -72,6 +72,11 @@ module Steep
|
|
72
72
|
opts.on("-j N", "--jobs=N", "Specify the number of type check workers (defaults: #{default})") do |count|
|
73
73
|
command.jobs_count = Integer(count) if Integer(count) > 0
|
74
74
|
end
|
75
|
+
|
76
|
+
command.steep_command = "steep"
|
77
|
+
opts.on("--steep-command=COMMAND", "Specify command to exec Steep CLI for worker (defaults: steep)") do |cmd|
|
78
|
+
command.steep_command = cmd
|
79
|
+
end
|
75
80
|
end
|
76
81
|
|
77
82
|
def process_init
|
data/lib/steep/drivers/check.rb
CHANGED
@@ -37,8 +37,8 @@ module Steep
|
|
37
37
|
def run
|
38
38
|
@project = load_config()
|
39
39
|
|
40
|
-
interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: project.steepfile_path)
|
41
|
-
typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: [], count: jobs_count)
|
40
|
+
interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: project.steepfile_path, steep_command: steep_command)
|
41
|
+
typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: [], steep_command: steep_command, count: jobs_count)
|
42
42
|
|
43
43
|
master = Server::Master.new(
|
44
44
|
project: project,
|
data/lib/steep/drivers/stats.rb
CHANGED
data/lib/steep/drivers/watch.rb
CHANGED
@@ -41,7 +41,7 @@ module Steep
|
|
41
41
|
server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read)
|
42
42
|
server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write)
|
43
43
|
|
44
|
-
typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: dirs.map(&:to_s), count: jobs_count)
|
44
|
+
typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: dirs.map(&:to_s), steep_command: steep_command, count: jobs_count)
|
45
45
|
|
46
46
|
master = Server::Master.new(
|
47
47
|
project: project,
|
@@ -879,6 +879,11 @@ module Steep
|
|
879
879
|
!has_positional? && !has_keywords?
|
880
880
|
end
|
881
881
|
|
882
|
+
# Returns true if all arguments are non-required.
|
883
|
+
def optional?
|
884
|
+
required.empty? && required_keywords.empty?
|
885
|
+
end
|
886
|
+
|
882
887
|
# self + params returns a new params for overloading.
|
883
888
|
#
|
884
889
|
def +(other)
|
data/lib/steep/project.rb
CHANGED
@@ -16,7 +16,21 @@ module Steep
|
|
16
16
|
steepfile_path.parent
|
17
17
|
end
|
18
18
|
|
19
|
-
def relative_path(
|
19
|
+
def relative_path(orig_path)
|
20
|
+
path = if Gem.win_platform?
|
21
|
+
path_str = URI.decode_www_form_component(
|
22
|
+
orig_path.to_s.delete_prefix("/")
|
23
|
+
)
|
24
|
+
unless path_str.start_with?(%r{[a-z]:/}i)
|
25
|
+
# FIXME: Sometimes drive letter is missing, taking from base_dir
|
26
|
+
path_str = base_dir.to_s.split("/")[0] + "/" + path_str
|
27
|
+
end
|
28
|
+
Pathname.new(
|
29
|
+
path_str
|
30
|
+
)
|
31
|
+
else
|
32
|
+
orig_path
|
33
|
+
end
|
20
34
|
path.relative_path_from(base_dir)
|
21
35
|
end
|
22
36
|
|
@@ -89,7 +89,7 @@ module Steep
|
|
89
89
|
end
|
90
90
|
|
91
91
|
LSP::Interface::Hover.new(
|
92
|
-
contents: { kind: "markdown", value: format_hover(content) },
|
92
|
+
contents: { kind: "markdown", value: format_hover(content)&.gsub(/<!--(?~-->)-->/, "") },
|
93
93
|
range: range
|
94
94
|
)
|
95
95
|
end
|
@@ -271,7 +271,7 @@ HOVER
|
|
271
271
|
),
|
272
272
|
end: LanguageServer::Protocol::Interface::Position.new(
|
273
273
|
line: job.line - 1,
|
274
|
-
character: job.column
|
274
|
+
character: job.column
|
275
275
|
)
|
276
276
|
)
|
277
277
|
|
data/lib/steep/server/master.rb
CHANGED
@@ -49,9 +49,14 @@ module Steep
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def checking_path?(path)
|
52
|
-
library_paths.
|
53
|
-
|
54
|
-
|
52
|
+
[library_paths, signature_paths, code_paths].any? do |paths|
|
53
|
+
if Gem.win_platform?
|
54
|
+
# FIXME: Sometimes drive letter is missing, so comparing without drive letter.
|
55
|
+
paths.any? {|p| p.to_s.split("/", 2)[1] == path.to_s.split("/", 2)[1]}
|
56
|
+
else
|
57
|
+
paths.include?(path)
|
58
|
+
end
|
59
|
+
end
|
55
60
|
end
|
56
61
|
|
57
62
|
def checked(path)
|
@@ -739,7 +744,7 @@ module Steep
|
|
739
744
|
{ kind: "end" }
|
740
745
|
else
|
741
746
|
progress_string = ("▮"*(percentage/5)) + ("▯"*(20 - percentage/5))
|
742
|
-
{ kind: "report", percentage: percentage, message: "#{progress_string}
|
747
|
+
{ kind: "report", percentage: percentage, message: "#{progress_string}" }
|
743
748
|
end
|
744
749
|
|
745
750
|
job_queue << SendMessageJob.to_client(
|
@@ -135,6 +135,21 @@ module Steep
|
|
135
135
|
end
|
136
136
|
|
137
137
|
def handle_job(job)
|
138
|
+
job_path = if job.respond_to?(:path)
|
139
|
+
if Gem.win_platform?
|
140
|
+
# FIXME: Sometimes drive letter is missing, using base_dir
|
141
|
+
if job.path.to_s.start_with?(%r{/[a-z](:|%3A)/}i)
|
142
|
+
job.path.to_s
|
143
|
+
else
|
144
|
+
"/#{project.base_dir.to_s.split("/").first}/#{job.path}"
|
145
|
+
end
|
146
|
+
else
|
147
|
+
job.path.to_s
|
148
|
+
end
|
149
|
+
else
|
150
|
+
nil
|
151
|
+
end
|
152
|
+
|
138
153
|
case job
|
139
154
|
when StartTypeCheckJob
|
140
155
|
Steep.logger.info { "Processing StartTypeCheckJob for guid=#{job.guid}" }
|
@@ -149,7 +164,7 @@ module Steep
|
|
149
164
|
writer.write(
|
150
165
|
method: :"textDocument/publishDiagnostics",
|
151
166
|
params: LSP::Interface::PublishDiagnosticsParams.new(
|
152
|
-
uri: URI.parse(
|
167
|
+
uri: URI.parse(job_path).tap {|uri| uri.scheme = "file"},
|
153
168
|
diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq
|
154
169
|
)
|
155
170
|
)
|
@@ -167,7 +182,7 @@ module Steep
|
|
167
182
|
writer.write(
|
168
183
|
method: :"textDocument/publishDiagnostics",
|
169
184
|
params: LSP::Interface::PublishDiagnosticsParams.new(
|
170
|
-
uri: URI.parse(
|
185
|
+
uri: URI.parse(job_path).tap {|uri| uri.scheme = "file"},
|
171
186
|
diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq.compact
|
172
187
|
)
|
173
188
|
)
|
@@ -186,7 +201,7 @@ module Steep
|
|
186
201
|
writer.write(
|
187
202
|
method: :"textDocument/publishDiagnostics",
|
188
203
|
params: LSP::Interface::PublishDiagnosticsParams.new(
|
189
|
-
uri: URI.parse(
|
204
|
+
uri: URI.parse(job_path).tap {|uri| uri.scheme = "file"},
|
190
205
|
diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq.compact
|
191
206
|
)
|
192
207
|
)
|
@@ -268,7 +283,7 @@ module Steep
|
|
268
283
|
line = job.params[:position][:line] + 1
|
269
284
|
column = job.params[:position][:character]
|
270
285
|
|
271
|
-
goto_service = Services::GotoService.new(type_check: service)
|
286
|
+
goto_service = Services::GotoService.new(type_check: service, assignment: assignment)
|
272
287
|
locations =
|
273
288
|
case
|
274
289
|
when job.definition?
|
@@ -18,13 +18,17 @@ module Steep
|
|
18
18
|
@index = index
|
19
19
|
end
|
20
20
|
|
21
|
-
def self.spawn_worker(type, name:, steepfile:, options: [], delay_shutdown: false, index: nil)
|
22
|
-
|
21
|
+
def self.spawn_worker(type, name:, steepfile:, steep_command: "steep", options: [], delay_shutdown: false, index: nil)
|
22
|
+
args = ["--name=#{name}", "--steepfile=#{steepfile}"]
|
23
|
+
args << (%w(debug info warn error fatal unknown)[Steep.logger.level].yield_self {|log_level| "--log-level=#{log_level}" })
|
24
|
+
if Steep.log_output.is_a?(String)
|
25
|
+
args << "--log-output=#{Steep.log_output}"
|
26
|
+
end
|
23
27
|
command = case type
|
24
28
|
when :interaction
|
25
|
-
[
|
29
|
+
[steep_command, "worker", "--interaction", *args, *options]
|
26
30
|
when :typecheck
|
27
|
-
[
|
31
|
+
[steep_command, "worker", "--typecheck", *args, *options]
|
28
32
|
else
|
29
33
|
raise "Unknown type: #{type}"
|
30
34
|
end
|
@@ -33,7 +37,11 @@ module Steep
|
|
33
37
|
command << "--delay-shutdown"
|
34
38
|
end
|
35
39
|
|
36
|
-
stdin, stdout, thread =
|
40
|
+
stdin, stdout, thread = if Gem.win_platform?
|
41
|
+
Open3.popen2(*command, new_pgroup: true)
|
42
|
+
else
|
43
|
+
Open3.popen2(*command, pgroup: true)
|
44
|
+
end
|
37
45
|
stderr = nil
|
38
46
|
|
39
47
|
writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdin)
|
@@ -42,11 +50,12 @@ module Steep
|
|
42
50
|
new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread, name: name, index: index)
|
43
51
|
end
|
44
52
|
|
45
|
-
def self.spawn_typecheck_workers(steepfile:, args:, count: [Etc.nprocessors - 1, 1].max, delay_shutdown: false)
|
53
|
+
def self.spawn_typecheck_workers(steepfile:, args:, steep_command: "steep", count: [Etc.nprocessors - 1, 1].max, delay_shutdown: false)
|
46
54
|
count.times.map do |i|
|
47
55
|
spawn_worker(:typecheck,
|
48
56
|
name: "typecheck@#{i}",
|
49
57
|
steepfile: steepfile,
|
58
|
+
steep_command: steep_command,
|
50
59
|
options: ["--max-index=#{count}", "--index=#{i}", *args],
|
51
60
|
delay_shutdown: delay_shutdown,
|
52
61
|
index: i)
|
@@ -21,10 +21,11 @@ module Steep
|
|
21
21
|
end
|
22
22
|
TypeNameQuery = Struct.new(:name, keyword_init: true)
|
23
23
|
|
24
|
-
attr_reader :type_check
|
24
|
+
attr_reader :type_check, :assignment
|
25
25
|
|
26
|
-
def initialize(type_check:)
|
26
|
+
def initialize(type_check:, assignment:)
|
27
27
|
@type_check = type_check
|
28
|
+
@assignment = assignment
|
28
29
|
end
|
29
30
|
|
30
31
|
def project
|
@@ -78,7 +79,17 @@ module Steep
|
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
81
|
-
|
82
|
+
# Drop un-assigned paths here.
|
83
|
+
# The path assignment makes sense only for `.rbs` files, because un-assigned `.rb` files are already skipped since they are not type checked.
|
84
|
+
#
|
85
|
+
locations.uniq.select do |loc|
|
86
|
+
case loc
|
87
|
+
when RBS::Location
|
88
|
+
assignment =~ loc.name
|
89
|
+
else
|
90
|
+
true
|
91
|
+
end
|
92
|
+
end
|
82
93
|
end
|
83
94
|
|
84
95
|
def test_ast_location(loc, line:, column:)
|
@@ -100,6 +111,7 @@ module Steep
|
|
100
111
|
typing, signature = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
|
101
112
|
if typing
|
102
113
|
node, *parents = typing.source.find_nodes(line: line, column: column)
|
114
|
+
|
103
115
|
if node
|
104
116
|
case node.type
|
105
117
|
when :const, :casgn
|
@@ -125,7 +137,10 @@ module Steep
|
|
125
137
|
end
|
126
138
|
when :send
|
127
139
|
if test_ast_location(node.location.selector, line: line, column: column)
|
128
|
-
|
140
|
+
if (parent = parents[0]) && parent.type == :block && parent.children[0] == node
|
141
|
+
node = parents[0]
|
142
|
+
end
|
143
|
+
|
129
144
|
case call = typing.call_of(node: node)
|
130
145
|
when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
|
131
146
|
call.method_decls.each do |decl|
|
@@ -2275,13 +2275,10 @@ module Steep
|
|
2275
2275
|
type, constr = synthesize(rhs, hint: hint)
|
2276
2276
|
constr.ivasgn(asgn, type)
|
2277
2277
|
when :send
|
2278
|
-
|
2279
|
-
|
2280
|
-
|
2281
|
-
|
2282
|
-
asgn.children[2],
|
2283
|
-
rhs
|
2284
|
-
])
|
2278
|
+
children = asgn.children.dup
|
2279
|
+
children[1] = :"#{children[1]}="
|
2280
|
+
send_arg_nodes = [*children, rhs]
|
2281
|
+
rhs_ = node.updated(:send, send_arg_nodes)
|
2285
2282
|
node_type = case node.type
|
2286
2283
|
when :or_asgn
|
2287
2284
|
:or
|
@@ -2348,11 +2345,11 @@ module Steep
|
|
2348
2345
|
interface = calculate_interface(param_type, private: true)
|
2349
2346
|
method = interface.methods[value.children[0]]
|
2350
2347
|
if method
|
2351
|
-
return_types = method.method_types.
|
2352
|
-
method_type.type.params.
|
2353
|
-
|
2354
|
-
|
2355
|
-
|
2348
|
+
return_types = method.method_types.filter_map do |method_type|
|
2349
|
+
if method_type.type.params.optional?
|
2350
|
+
method_type.type.return_type
|
2351
|
+
end
|
2352
|
+
end
|
2356
2353
|
|
2357
2354
|
unless return_types.empty?
|
2358
2355
|
type = AST::Types::Proc.new(
|
@@ -2360,7 +2357,7 @@ module Steep
|
|
2360
2357
|
params: Interface::Function::Params.empty.with_first_param(
|
2361
2358
|
Interface::Function::Params::PositionalParams::Required.new(param_type)
|
2362
2359
|
),
|
2363
|
-
return_type:
|
2360
|
+
return_type: return_types[0],
|
2364
2361
|
location: nil
|
2365
2362
|
),
|
2366
2363
|
block: nil
|
@@ -3948,6 +3945,20 @@ module Steep
|
|
3948
3945
|
constr.add_typing(node, type: AST::Types::Tuple.new(types: element_types))
|
3949
3946
|
end
|
3950
3947
|
|
3948
|
+
def try_convert(type, method)
|
3949
|
+
interface = checker.factory.interface(type, private: false)
|
3950
|
+
if entry = interface.methods[method]
|
3951
|
+
method_type = entry.method_types.find do |method_type|
|
3952
|
+
method_type.type.params.optional?
|
3953
|
+
end
|
3954
|
+
|
3955
|
+
method_type.type.return_type
|
3956
|
+
end
|
3957
|
+
rescue => exn
|
3958
|
+
Steep.log_error(exn, message: "Unexpected error when converting #{type.to_s} with #{method}")
|
3959
|
+
nil
|
3960
|
+
end
|
3961
|
+
|
3951
3962
|
def try_array_type(node, hint)
|
3952
3963
|
element_hint = hint ? hint.args[0] : nil
|
3953
3964
|
|
@@ -3958,8 +3969,14 @@ module Steep
|
|
3958
3969
|
case child.type
|
3959
3970
|
when :splat
|
3960
3971
|
type, constr = constr.synthesize(child.children[0], hint: hint)
|
3961
|
-
|
3972
|
+
|
3973
|
+
type = try_convert(type, :to_a) || type
|
3974
|
+
|
3975
|
+
case
|
3976
|
+
when AST::Builtin::Array.instance_type?(type)
|
3962
3977
|
element_types << type.args[0]
|
3978
|
+
when type.is_a?(AST::Types::Tuple)
|
3979
|
+
element_types.push(*type.types)
|
3963
3980
|
else
|
3964
3981
|
element_types.push(*flatten_array_elements(type))
|
3965
3982
|
end
|
data/lib/steep/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: steep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.50.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Soutaro Matsumoto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|