steep 0.40.0 → 0.44.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 +38 -0
- data/Gemfile +1 -0
- data/bin/output_rebaseline.rb +15 -30
- data/bin/output_test.rb +23 -57
- data/lib/steep.rb +89 -15
- data/lib/steep/annotation_parser.rb +10 -2
- data/lib/steep/ast/types/class.rb +4 -0
- data/lib/steep/cli.rb +31 -6
- data/lib/steep/diagnostic/ruby.rb +13 -8
- data/lib/steep/diagnostic/signature.rb +152 -2
- data/lib/steep/drivers/annotations.rb +18 -36
- data/lib/steep/drivers/check.rb +140 -31
- data/lib/steep/drivers/diagnostic_printer.rb +20 -11
- data/lib/steep/drivers/langserver.rb +4 -8
- data/lib/steep/drivers/print_project.rb +10 -9
- data/lib/steep/drivers/stats.rb +135 -119
- data/lib/steep/drivers/utils/driver_helper.rb +35 -0
- data/lib/steep/drivers/utils/jobs_count.rb +9 -0
- data/lib/steep/drivers/validate.rb +29 -18
- data/lib/steep/drivers/watch.rb +55 -49
- data/lib/steep/drivers/worker.rb +11 -8
- data/lib/steep/expectations.rb +159 -0
- data/lib/steep/index/signature_symbol_provider.rb +23 -1
- data/lib/steep/index/source_index.rb +55 -5
- data/lib/steep/interface/block.rb +4 -0
- data/lib/steep/project.rb +0 -30
- data/lib/steep/project/dsl.rb +5 -3
- data/lib/steep/project/pattern.rb +56 -0
- data/lib/steep/project/target.rb +11 -227
- data/lib/steep/server/base_worker.rb +1 -3
- data/lib/steep/server/change_buffer.rb +63 -0
- data/lib/steep/server/interaction_worker.rb +72 -57
- data/lib/steep/server/master.rb +652 -234
- data/lib/steep/server/type_check_worker.rb +304 -0
- data/lib/steep/server/worker_process.rb +16 -11
- data/lib/steep/{project → services}/completion_provider.rb +5 -5
- data/lib/steep/services/content_change.rb +61 -0
- data/lib/steep/services/file_loader.rb +48 -0
- data/lib/steep/services/goto_service.rb +321 -0
- data/lib/steep/{project → services}/hover_content.rb +19 -20
- data/lib/steep/services/path_assignment.rb +27 -0
- data/lib/steep/services/signature_service.rb +403 -0
- data/lib/steep/services/stats_calculator.rb +69 -0
- data/lib/steep/services/type_check_service.rb +413 -0
- data/lib/steep/signature/validator.rb +187 -85
- data/lib/steep/source.rb +21 -18
- data/lib/steep/subtyping/check.rb +246 -45
- data/lib/steep/subtyping/constraints.rb +4 -4
- data/lib/steep/type_construction.rb +428 -193
- data/lib/steep/type_inference/block_params.rb +1 -1
- data/lib/steep/type_inference/context.rb +22 -0
- data/lib/steep/type_inference/local_variable_type_env.rb +26 -12
- data/lib/steep/type_inference/logic.rb +1 -1
- data/lib/steep/type_inference/logic_type_interpreter.rb +4 -4
- data/lib/steep/type_inference/type_env.rb +43 -17
- data/lib/steep/version.rb +1 -1
- data/smoke/alias/test_expectations.yml +96 -0
- data/smoke/and/test_expectations.yml +31 -0
- data/smoke/array/test_expectations.yml +103 -0
- data/smoke/block/test_expectations.yml +125 -0
- data/smoke/case/test_expectations.yml +47 -0
- data/smoke/class/test_expectations.yml +120 -0
- data/smoke/const/test_expectations.yml +129 -0
- data/smoke/diagnostics-rbs-duplicated/test_expectations.yml +13 -0
- data/smoke/diagnostics-rbs/Steepfile +7 -4
- data/smoke/diagnostics-rbs/test_expectations.yml +231 -0
- data/smoke/diagnostics-rbs/unknown-type-name-2.rbs +5 -0
- data/smoke/{broken → diagnostics-ruby-unsat}/Steepfile +0 -0
- data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
- data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
- data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
- data/smoke/diagnostics/a.rbs +0 -4
- data/smoke/diagnostics/test_expectations.yml +451 -0
- data/smoke/dstr/test_expectations.yml +13 -0
- data/smoke/ensure/test_expectations.yml +62 -0
- data/smoke/enumerator/test_expectations.yml +135 -0
- data/smoke/extension/f.rb +2 -0
- data/smoke/extension/f.rbs +3 -0
- data/smoke/extension/test_expectations.yml +73 -0
- data/smoke/hash/test_expectations.yml +81 -0
- data/smoke/hello/test_expectations.yml +25 -0
- data/smoke/if/test_expectations.yml +34 -0
- data/smoke/implements/b.rb +13 -0
- data/smoke/implements/b.rbs +12 -0
- data/smoke/implements/test_expectations.yml +23 -0
- data/smoke/initialize/test_expectations.yml +1 -0
- data/smoke/integer/test_expectations.yml +101 -0
- data/smoke/interface/test_expectations.yml +23 -0
- data/smoke/kwbegin/test_expectations.yml +17 -0
- data/smoke/lambda/test_expectations.yml +39 -0
- data/smoke/literal/test_expectations.yml +106 -0
- data/smoke/map/test_expectations.yml +1 -0
- data/smoke/method/test_expectations.yml +90 -0
- data/smoke/module/test_expectations.yml +75 -0
- data/smoke/regexp/test_expectations.yml +615 -0
- data/smoke/regression/issue_328.rb +1 -0
- data/smoke/regression/issue_328.rbs +0 -0
- data/smoke/regression/issue_332.rb +11 -0
- data/smoke/regression/issue_332.rbs +19 -0
- data/smoke/regression/issue_372.rb +8 -0
- data/smoke/regression/issue_372.rbs +4 -0
- data/smoke/regression/masgn.rb +4 -0
- data/smoke/regression/test_expectations.yml +60 -0
- data/smoke/regression/thread.rb +7 -0
- data/smoke/rescue/test_expectations.yml +79 -0
- data/smoke/self/test_expectations.yml +23 -0
- data/smoke/skip/test_expectations.yml +23 -0
- data/smoke/stdout/test_expectations.yml +1 -0
- data/smoke/super/test_expectations.yml +69 -0
- data/smoke/toplevel/test_expectations.yml +15 -0
- data/smoke/tsort/Steepfile +2 -0
- data/smoke/tsort/test_expectations.yml +63 -0
- data/smoke/type_case/test_expectations.yml +48 -0
- data/smoke/unexpected/Steepfile +5 -0
- data/smoke/unexpected/test_expectations.yml +25 -0
- data/smoke/unexpected/unexpected.rb +1 -0
- data/smoke/unexpected/unexpected.rbs +3 -0
- data/smoke/yield/test_expectations.yml +68 -0
- data/steep.gemspec +4 -3
- metadata +127 -80
- data/lib/steep/project/file_loader.rb +0 -68
- data/lib/steep/project/signature_file.rb +0 -39
- data/lib/steep/project/source_file.rb +0 -129
- data/lib/steep/project/stats_calculator.rb +0 -80
- data/lib/steep/server/code_worker.rb +0 -150
- data/lib/steep/server/signature_worker.rb +0 -157
- data/lib/steep/server/utils.rb +0 -69
- data/smoke/alias/test.yaml +0 -73
- data/smoke/and/test.yaml +0 -24
- data/smoke/array/test.yaml +0 -80
- data/smoke/block/test.yaml +0 -96
- data/smoke/broken/broken.rb +0 -0
- data/smoke/broken/broken.rbs +0 -0
- data/smoke/broken/test.yaml +0 -6
- data/smoke/case/test.yaml +0 -36
- data/smoke/class/test.yaml +0 -89
- data/smoke/const/test.yaml +0 -96
- data/smoke/diagnostics-rbs-duplicated/test.yaml +0 -10
- data/smoke/diagnostics-rbs/test.yaml +0 -142
- data/smoke/diagnostics/test.yaml +0 -333
- data/smoke/dstr/test.yaml +0 -10
- data/smoke/ensure/test.yaml +0 -47
- data/smoke/enumerator/test.yaml +0 -100
- data/smoke/extension/test.yaml +0 -50
- data/smoke/hash/test.yaml +0 -62
- data/smoke/hello/test.yaml +0 -18
- data/smoke/if/test.yaml +0 -27
- data/smoke/implements/test.yaml +0 -16
- data/smoke/initialize/test.yaml +0 -4
- data/smoke/integer/test.yaml +0 -66
- data/smoke/interface/test.yaml +0 -16
- data/smoke/kwbegin/test.yaml +0 -14
- data/smoke/lambda/test.yaml +0 -28
- data/smoke/literal/test.yaml +0 -79
- data/smoke/map/test.yaml +0 -4
- data/smoke/method/test.yaml +0 -71
- data/smoke/module/test.yaml +0 -51
- data/smoke/regexp/test.yaml +0 -372
- data/smoke/regression/test.yaml +0 -38
- data/smoke/rescue/test.yaml +0 -60
- data/smoke/self/test.yaml +0 -16
- data/smoke/skip/test.yaml +0 -16
- data/smoke/stdout/test.yaml +0 -4
- data/smoke/super/test.yaml +0 -52
- data/smoke/toplevel/test.yaml +0 -12
- data/smoke/tsort/test.yaml +0 -32
- data/smoke/type_case/test.yaml +0 -33
- data/smoke/yield/test.yaml +0 -49
@@ -0,0 +1,304 @@
|
|
1
|
+
module Steep
|
2
|
+
module Server
|
3
|
+
class TypeCheckWorker < BaseWorker
|
4
|
+
attr_reader :project, :assignment, :service
|
5
|
+
attr_reader :commandline_args
|
6
|
+
attr_reader :current_type_check_guid
|
7
|
+
|
8
|
+
WorkspaceSymbolJob = Struct.new(:query, :id, keyword_init: true)
|
9
|
+
StatsJob = Struct.new(:id, keyword_init: true)
|
10
|
+
StartTypeCheckJob = Struct.new(:guid, :changes, keyword_init: true)
|
11
|
+
TypeCheckCodeJob = Struct.new(:guid, :path, keyword_init: true)
|
12
|
+
ValidateAppSignatureJob = Struct.new(:guid, :path, keyword_init: true)
|
13
|
+
ValidateLibrarySignatureJob = Struct.new(:guid, :path, keyword_init: true)
|
14
|
+
GotoJob = Struct.new(:id, :kind, :params, keyword_init: true) do
|
15
|
+
def self.implementation(id:, params:)
|
16
|
+
new(
|
17
|
+
kind: :implementation,
|
18
|
+
id: id,
|
19
|
+
params: params
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.definition(id:, params:)
|
24
|
+
new(
|
25
|
+
kind: :definition,
|
26
|
+
id: id,
|
27
|
+
params: params
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def implementation?
|
32
|
+
kind == :implementation
|
33
|
+
end
|
34
|
+
|
35
|
+
def definition?
|
36
|
+
kind == :definition
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
include ChangeBuffer
|
41
|
+
|
42
|
+
def initialize(project:, reader:, writer:, assignment:, commandline_args:)
|
43
|
+
super(project: project, reader: reader, writer: writer)
|
44
|
+
|
45
|
+
@assignment = assignment
|
46
|
+
@service = Services::TypeCheckService.new(project: project)
|
47
|
+
@buffered_changes = {}
|
48
|
+
@mutex = Mutex.new()
|
49
|
+
@queue = Queue.new
|
50
|
+
@commandline_args = commandline_args
|
51
|
+
@current_type_check_guid = nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def handle_request(request)
|
55
|
+
case request[:method]
|
56
|
+
when "initialize"
|
57
|
+
load_files(project: project, commandline_args: commandline_args)
|
58
|
+
writer.write({ id: request[:id], result: nil})
|
59
|
+
when "textDocument/didChange"
|
60
|
+
collect_changes(request)
|
61
|
+
when "workspace/symbol"
|
62
|
+
query = request[:params][:query]
|
63
|
+
queue << WorkspaceSymbolJob.new(id: request[:id], query: query)
|
64
|
+
when "workspace/executeCommand"
|
65
|
+
case request[:params][:command]
|
66
|
+
when "steep/stats"
|
67
|
+
queue << StatsJob.new(id: request[:id])
|
68
|
+
end
|
69
|
+
when "$/typecheck/start"
|
70
|
+
params = request[:params]
|
71
|
+
enqueue_typecheck_jobs(params)
|
72
|
+
when "textDocument/definition"
|
73
|
+
queue << GotoJob.definition(id: request[:id], params: request[:params])
|
74
|
+
when "textDocument/implementation"
|
75
|
+
queue << GotoJob.implementation(id: request[:id], params: request[:params])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def enqueue_typecheck_jobs(params)
|
80
|
+
guid = params[:guid]
|
81
|
+
|
82
|
+
@current_type_check_guid = guid
|
83
|
+
|
84
|
+
pop_buffer() do |changes|
|
85
|
+
Steep.logger.info { "Enqueueing StartTypeCheckJob for guid=#{guid}" }
|
86
|
+
queue << StartTypeCheckJob.new(guid: guid, changes: changes)
|
87
|
+
end
|
88
|
+
|
89
|
+
priority_paths = Set.new(params[:priority_uris].map {|uri| Pathname(URI.parse(uri).path) })
|
90
|
+
library_paths = params[:library_uris].map {|uri| Pathname(URI.parse(uri).path) }
|
91
|
+
signature_paths = params[:signature_uris].map {|uri| Pathname(URI.parse(uri).path) }
|
92
|
+
code_paths = params[:code_uris].map {|uri| Pathname(URI.parse(uri).path) }
|
93
|
+
|
94
|
+
library_paths.each do |path|
|
95
|
+
if priority_paths.include?(path)
|
96
|
+
Steep.logger.info { "Enqueueing ValidateLibrarySignatureJob for guid=#{guid}, path=#{path}" }
|
97
|
+
queue << ValidateLibrarySignatureJob.new(guid: guid, path: path)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
code_paths.each do |path|
|
102
|
+
if priority_paths.include?(path)
|
103
|
+
Steep.logger.info { "Enqueueing TypeCheckCodeJob for guid=#{guid}, path=#{path}" }
|
104
|
+
queue << TypeCheckCodeJob.new(guid: guid, path: path)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
signature_paths.each do |path|
|
109
|
+
if priority_paths.include?(path)
|
110
|
+
Steep.logger.info { "Enqueueing ValidateAppSignatureJob for guid=#{guid}, path=#{path}" }
|
111
|
+
queue << ValidateAppSignatureJob.new(guid: guid, path: path)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
library_paths.each do |path|
|
116
|
+
unless priority_paths.include?(path)
|
117
|
+
Steep.logger.info { "Enqueueing ValidateLibrarySignatureJob for guid=#{guid}, path=#{path}" }
|
118
|
+
queue << ValidateLibrarySignatureJob.new(guid: guid, path: path)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
code_paths.each do |path|
|
123
|
+
unless priority_paths.include?(path)
|
124
|
+
Steep.logger.info { "Enqueueing TypeCheckCodeJob for guid=#{guid}, path=#{path}" }
|
125
|
+
queue << TypeCheckCodeJob.new(guid: guid, path: path)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
signature_paths.each do |path|
|
130
|
+
unless priority_paths.include?(path)
|
131
|
+
Steep.logger.info { "Enqueueing ValidateAppSignatureJob for guid=#{guid}, path=#{path}" }
|
132
|
+
queue << ValidateAppSignatureJob.new(guid: guid, path: path)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def handle_job(job)
|
138
|
+
case job
|
139
|
+
when StartTypeCheckJob
|
140
|
+
Steep.logger.info { "Processing StartTypeCheckJob for guid=#{job.guid}" }
|
141
|
+
service.update(changes: job.changes)
|
142
|
+
|
143
|
+
when ValidateAppSignatureJob
|
144
|
+
if job.guid == current_type_check_guid
|
145
|
+
Steep.logger.info { "Processing ValidateAppSignature for guid=#{job.guid}, path=#{job.path}" }
|
146
|
+
service.validate_signature(path: project.relative_path(job.path)) do |path, diagnostics|
|
147
|
+
formatter = Diagnostic::LSPFormatter.new()
|
148
|
+
|
149
|
+
writer.write(
|
150
|
+
method: :"textDocument/publishDiagnostics",
|
151
|
+
params: LSP::Interface::PublishDiagnosticsParams.new(
|
152
|
+
uri: URI.parse(job.path.to_s).tap {|uri| uri.scheme = "file"},
|
153
|
+
diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq
|
154
|
+
)
|
155
|
+
)
|
156
|
+
end
|
157
|
+
|
158
|
+
typecheck_progress(path: job.path, guid: job.guid)
|
159
|
+
end
|
160
|
+
|
161
|
+
when ValidateLibrarySignatureJob
|
162
|
+
if job.guid == current_type_check_guid
|
163
|
+
Steep.logger.info { "Processing ValidateLibrarySignature for guid=#{job.guid}, path=#{job.path}" }
|
164
|
+
service.validate_signature(path: job.path) do |path, diagnostics|
|
165
|
+
formatter = Diagnostic::LSPFormatter.new()
|
166
|
+
|
167
|
+
writer.write(
|
168
|
+
method: :"textDocument/publishDiagnostics",
|
169
|
+
params: LSP::Interface::PublishDiagnosticsParams.new(
|
170
|
+
uri: URI.parse(job.path.to_s).tap {|uri| uri.scheme = "file"},
|
171
|
+
diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq
|
172
|
+
)
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
typecheck_progress(path: job.path, guid: job.guid)
|
177
|
+
end
|
178
|
+
|
179
|
+
when TypeCheckCodeJob
|
180
|
+
if job.guid == current_type_check_guid
|
181
|
+
Steep.logger.info { "Processing TypeCheckCodeJob for guid=#{job.guid}, path=#{job.path}" }
|
182
|
+
service.typecheck_source(path: project.relative_path(job.path)) do |path, diagnostics|
|
183
|
+
if target = project.target_for_source_path(path)
|
184
|
+
diagnostics = diagnostics.select {|diagnostic| target.options.error_to_report?(diagnostic) }
|
185
|
+
end
|
186
|
+
|
187
|
+
formatter = Diagnostic::LSPFormatter.new()
|
188
|
+
|
189
|
+
writer.write(
|
190
|
+
method: :"textDocument/publishDiagnostics",
|
191
|
+
params: LSP::Interface::PublishDiagnosticsParams.new(
|
192
|
+
uri: URI.parse(job.path.to_s).tap {|uri| uri.scheme = "file"},
|
193
|
+
diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq
|
194
|
+
)
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
typecheck_progress(path: job.path, guid: job.guid)
|
199
|
+
end
|
200
|
+
|
201
|
+
when WorkspaceSymbolJob
|
202
|
+
writer.write(
|
203
|
+
id: job.id,
|
204
|
+
result: workspace_symbol_result(job.query)
|
205
|
+
)
|
206
|
+
when StatsJob
|
207
|
+
writer.write(
|
208
|
+
id: job.id,
|
209
|
+
result: stats_result().map(&:as_json)
|
210
|
+
)
|
211
|
+
when GotoJob
|
212
|
+
writer.write(
|
213
|
+
id: job.id,
|
214
|
+
result: goto(job)
|
215
|
+
)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def typecheck_progress(guid:, path:)
|
220
|
+
writer.write(
|
221
|
+
method: "$/typecheck/progress",
|
222
|
+
params: { guid: guid, path: path }
|
223
|
+
)
|
224
|
+
end
|
225
|
+
|
226
|
+
def workspace_symbol_result(query)
|
227
|
+
Steep.measure "Generating workspace symbol list for query=`#{query}`" do
|
228
|
+
indexes = project.targets.map {|target| service.signature_services[target.name].latest_rbs_index }
|
229
|
+
|
230
|
+
provider = Index::SignatureSymbolProvider.new(project: project, assignment: assignment)
|
231
|
+
provider.indexes.push(*indexes)
|
232
|
+
|
233
|
+
symbols = provider.query_symbol(query)
|
234
|
+
|
235
|
+
symbols.map do |symbol|
|
236
|
+
LSP::Interface::SymbolInformation.new(
|
237
|
+
name: symbol.name,
|
238
|
+
kind: symbol.kind,
|
239
|
+
location: symbol.location.yield_self do |location|
|
240
|
+
path = Pathname(location.buffer.name)
|
241
|
+
{
|
242
|
+
uri: URI.parse(project.absolute_path(path).to_s).tap {|uri| uri.scheme = "file" },
|
243
|
+
range: {
|
244
|
+
start: { line: location.start_line - 1, character: location.start_column },
|
245
|
+
end: { line: location.end_line - 1, character: location.end_column }
|
246
|
+
}
|
247
|
+
}
|
248
|
+
end,
|
249
|
+
container_name: symbol.container_name
|
250
|
+
)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def stats_result
|
256
|
+
calculator = Services::StatsCalculator.new(service: service)
|
257
|
+
|
258
|
+
project.targets.each.with_object([]) do |target, stats|
|
259
|
+
service.source_files.each_value do |file|
|
260
|
+
next unless target.possible_source_file?(file.path)
|
261
|
+
absolute_path = project.absolute_path(file.path)
|
262
|
+
next unless assignment =~ absolute_path
|
263
|
+
|
264
|
+
stats << calculator.calc_stats(target, file: file)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def goto(job)
|
270
|
+
path = Pathname(URI.parse(job.params[:textDocument][:uri]).path)
|
271
|
+
line = job.params[:position][:line] + 1
|
272
|
+
column = job.params[:position][:character]
|
273
|
+
|
274
|
+
goto_service = Services::GotoService.new(type_check: service)
|
275
|
+
locations =
|
276
|
+
case
|
277
|
+
when job.definition?
|
278
|
+
goto_service.definition(path: path, line: line, column: column)
|
279
|
+
when job.implementation?
|
280
|
+
goto_service.implementation(path: path, line: line, column: column)
|
281
|
+
else
|
282
|
+
raise
|
283
|
+
end
|
284
|
+
|
285
|
+
locations.map do |loc|
|
286
|
+
path =
|
287
|
+
case loc
|
288
|
+
when RBS::Location
|
289
|
+
Pathname(loc.buffer.name)
|
290
|
+
else
|
291
|
+
Pathname(loc.source_buffer.name)
|
292
|
+
end
|
293
|
+
|
294
|
+
path = project.absolute_path(path)
|
295
|
+
|
296
|
+
{
|
297
|
+
uri: URI.parse(path.to_s).tap {|uri| uri.scheme = "file" }.to_s,
|
298
|
+
range: loc.as_lsp_range
|
299
|
+
}
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
@@ -7,26 +7,26 @@ module Steep
|
|
7
7
|
|
8
8
|
attr_reader :name
|
9
9
|
attr_reader :wait_thread
|
10
|
+
attr_reader :index
|
10
11
|
|
11
|
-
def initialize(reader:, writer:, stderr:, wait_thread:, name:)
|
12
|
+
def initialize(reader:, writer:, stderr:, wait_thread:, name:, index: nil)
|
12
13
|
@reader = reader
|
13
14
|
@writer = writer
|
14
15
|
@stderr = stderr
|
15
16
|
@wait_thread = wait_thread
|
16
17
|
@name = name
|
18
|
+
@index = index
|
17
19
|
end
|
18
20
|
|
19
|
-
def self.spawn_worker(type, name:, steepfile:, delay_shutdown: false)
|
21
|
+
def self.spawn_worker(type, name:, steepfile:, options: [], delay_shutdown: false, index: nil)
|
20
22
|
log_level = %w(debug info warn error fatal unknown)[Steep.logger.level]
|
21
23
|
command = case type
|
22
|
-
when :code
|
23
|
-
["steep", "worker", "--code", "--name=#{name}", "--log-level=#{log_level}", "--steepfile=#{steepfile}"]
|
24
|
-
when :signature
|
25
|
-
["steep", "worker", "--signature", "--name=#{name}", "--log-level=#{log_level}", "--steepfile=#{steepfile}"]
|
26
24
|
when :interaction
|
27
|
-
["steep", "worker", "--interaction", "--name=#{name}", "--log-level=#{log_level}", "--steepfile=#{steepfile}"]
|
25
|
+
["steep", "worker", "--interaction", "--name=#{name}", "--log-level=#{log_level}", "--steepfile=#{steepfile}", *options]
|
26
|
+
when :typecheck
|
27
|
+
["steep", "worker", "--typecheck", "--name=#{name}", "--log-level=#{log_level}", "--steepfile=#{steepfile}", *options]
|
28
28
|
else
|
29
|
-
raise
|
29
|
+
raise "Unknown type: #{type}"
|
30
30
|
end
|
31
31
|
|
32
32
|
if delay_shutdown
|
@@ -39,12 +39,17 @@ module Steep
|
|
39
39
|
writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdin)
|
40
40
|
reader = LanguageServer::Protocol::Transport::Io::Reader.new(stdout)
|
41
41
|
|
42
|
-
new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread, name: name)
|
42
|
+
new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread, name: name, index: index)
|
43
43
|
end
|
44
44
|
|
45
|
-
def self.
|
45
|
+
def self.spawn_typecheck_workers(steepfile:, args:, count: [Etc.nprocessors - 1, 1].max, delay_shutdown: false)
|
46
46
|
count.times.map do |i|
|
47
|
-
spawn_worker(:
|
47
|
+
spawn_worker(:typecheck,
|
48
|
+
name: "typecheck@#{i}",
|
49
|
+
steepfile: steepfile,
|
50
|
+
options: ["--max-index=#{count}", "--index=#{i}", *args],
|
51
|
+
delay_shutdown: delay_shutdown,
|
52
|
+
index: i)
|
48
53
|
end
|
49
54
|
end
|
50
55
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Steep
|
2
|
-
|
2
|
+
module Services
|
3
3
|
class CompletionProvider
|
4
4
|
Position = Struct.new(:line, :column, keyword_init: true) do
|
5
5
|
def -(size)
|
@@ -51,13 +51,13 @@ module Steep
|
|
51
51
|
@modified_text = text
|
52
52
|
|
53
53
|
Steep.measure "parsing" do
|
54
|
-
@source =
|
54
|
+
@source = Source
|
55
55
|
.parse(text, path: path, factory: subtyping.factory)
|
56
56
|
.without_unrelated_defs(line: line, column: column)
|
57
57
|
end
|
58
58
|
|
59
59
|
Steep.measure "typechecking" do
|
60
|
-
@typing =
|
60
|
+
@typing = TypeCheckService.type_check(source: source, subtyping: subtyping)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -82,7 +82,7 @@ module Steep
|
|
82
82
|
end
|
83
83
|
|
84
84
|
rescue Parser::SyntaxError => exn
|
85
|
-
Steep.logger.
|
85
|
+
Steep.logger.info "recovering syntax error: #{exn.inspect}"
|
86
86
|
case possible_trigger
|
87
87
|
when "."
|
88
88
|
source_text[index-1] = " "
|
@@ -143,7 +143,7 @@ module Steep
|
|
143
143
|
|
144
144
|
when node.type == :lvar && at_end?(position, of: node.loc)
|
145
145
|
# foo ← (lvar)
|
146
|
-
local_variable_items_for_context(context, position: position, prefix: node.children[0].
|
146
|
+
local_variable_items_for_context(context, position: position, prefix: node.children[0].to_s, items: items)
|
147
147
|
|
148
148
|
when node.type == :send && node.children[0] && at_end?(position, of: node.loc.selector)
|
149
149
|
# foo.ba ←
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Steep
|
2
|
+
module Services
|
3
|
+
class ContentChange
|
4
|
+
class Position
|
5
|
+
attr_reader :line, :column
|
6
|
+
|
7
|
+
def initialize(line:, column:)
|
8
|
+
@line = line
|
9
|
+
@column = column
|
10
|
+
end
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
other.is_a?(Position) && other.line == line && other.column == column
|
14
|
+
end
|
15
|
+
|
16
|
+
alias eql? ==
|
17
|
+
|
18
|
+
def hash
|
19
|
+
self.class.hash ^ line ^ column
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :range, :text
|
24
|
+
|
25
|
+
def initialize(range: nil, text:)
|
26
|
+
@range = range
|
27
|
+
@text = text
|
28
|
+
end
|
29
|
+
|
30
|
+
def ==(other)
|
31
|
+
other.is_a?(ContentChange) && other.range == range && other.text == text
|
32
|
+
end
|
33
|
+
|
34
|
+
alias eql? ==
|
35
|
+
|
36
|
+
def hash
|
37
|
+
self.class.hash ^ range.hash ^ text.hash
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.string(string)
|
41
|
+
new(text: string)
|
42
|
+
end
|
43
|
+
|
44
|
+
def apply_to(text)
|
45
|
+
if range
|
46
|
+
text = text.dup
|
47
|
+
start_pos, end_pos = range
|
48
|
+
|
49
|
+
buf = RBS::Buffer.new(name: :_, content: text)
|
50
|
+
start_pos = buf.loc_to_pos([start_pos.line, start_pos.column])
|
51
|
+
end_pos = buf.loc_to_pos([end_pos.line, end_pos.column])
|
52
|
+
|
53
|
+
text[start_pos...end_pos] = self.text
|
54
|
+
text
|
55
|
+
else
|
56
|
+
self.text
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|