steep 1.9.3 → 1.10.0.dev.1
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/Steepfile +5 -2
- data/lib/steep/annotations_helper.rb +18 -0
- data/lib/steep/ast/ignore.rb +3 -4
- data/lib/steep/cli.rb +98 -23
- data/lib/steep/diagnostic/lsp_formatter.rb +14 -3
- data/lib/steep/diagnostic/ruby.rb +75 -0
- data/lib/steep/drivers/langserver.rb +4 -1
- data/lib/steep/drivers/worker.rb +2 -0
- data/lib/steep/interface/builder.rb +2 -2
- data/lib/steep/server/custom_methods.rb +12 -0
- data/lib/steep/server/interaction_worker.rb +14 -2
- data/lib/steep/server/master.rb +158 -52
- data/lib/steep/server/type_check_worker.rb +48 -2
- data/lib/steep/server/worker_process.rb +31 -20
- data/lib/steep/services/completion_provider.rb +24 -2
- data/lib/steep/services/signature_service.rb +1 -1
- data/lib/steep/services/type_check_service.rb +22 -7
- data/lib/steep/source.rb +3 -1
- data/lib/steep/subtyping/check.rb +22 -16
- data/lib/steep/type_construction.rb +102 -8
- data/lib/steep/type_inference/case_when.rb +2 -0
- data/lib/steep/type_inference/logic_type_interpreter.rb +50 -0
- data/lib/steep/type_inference/method_call.rb +5 -3
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +7 -0
- data/manual/ruby-diagnostics.md +114 -1
- data/sample/Steepfile +0 -2
- data/sample/lib/conference.rb +14 -0
- data/sample/lib/deprecated.rb +4 -0
- data/sample/sig/deprecated.rbs +11 -0
- data/steep.gemspec +4 -3
- metadata +25 -8
data/lib/steep/server/master.rb
CHANGED
@@ -178,6 +178,7 @@ module Steep
|
|
178
178
|
attr_reader :job_queue, :write_queue
|
179
179
|
|
180
180
|
attr_reader :current_type_check_request
|
181
|
+
attr_reader :refork_mutex
|
181
182
|
attr_reader :controller
|
182
183
|
attr_reader :result_controller
|
183
184
|
|
@@ -185,7 +186,7 @@ module Steep
|
|
185
186
|
attr_accessor :typecheck_automatically
|
186
187
|
attr_reader :start_type_checking_queue
|
187
188
|
|
188
|
-
def initialize(project:, reader:, writer:, interaction_worker:, typecheck_workers:, queue: Queue.new)
|
189
|
+
def initialize(project:, reader:, writer:, interaction_worker:, typecheck_workers:, queue: Queue.new, refork: false)
|
189
190
|
@project = project
|
190
191
|
@reader = reader
|
191
192
|
@writer = writer
|
@@ -196,6 +197,8 @@ module Steep
|
|
196
197
|
@commandline_args = []
|
197
198
|
@job_queue = queue
|
198
199
|
@write_queue = SizedQueue.new(100)
|
200
|
+
@refork_mutex = Mutex.new
|
201
|
+
@need_to_refork = refork
|
199
202
|
|
200
203
|
@controller = TypeCheckController.new(project: project)
|
201
204
|
@result_controller = ResultController.new()
|
@@ -244,8 +247,10 @@ module Steep
|
|
244
247
|
Steep.logger.info { "Processing SendMessageJob: dest=client, method=#{job.message[:method] || "-"}, id=#{job.message[:id] || "-"}" }
|
245
248
|
writer.write job.message
|
246
249
|
when WorkerProcess
|
247
|
-
|
248
|
-
|
250
|
+
refork_mutex.synchronize do
|
251
|
+
Steep.logger.info { "Processing SendMessageJob: dest=#{job.dest.name}, method=#{job.message[:method] || "-"}, id=#{job.message[:id] || "-"}" }
|
252
|
+
job.dest << job.message
|
253
|
+
end
|
249
254
|
end
|
250
255
|
end
|
251
256
|
end
|
@@ -287,11 +292,13 @@ module Steep
|
|
287
292
|
end
|
288
293
|
end
|
289
294
|
|
290
|
-
waiter = ThreadWaiter.new
|
291
|
-
|
292
|
-
|
295
|
+
waiter = ThreadWaiter.new(each_worker.to_a) {|worker| worker.wait_thread }
|
296
|
+
# @type var th: Thread & WorkerProcess::_ProcessWaitThread
|
297
|
+
while th = _ = waiter.wait_one()
|
298
|
+
if each_worker.any? { |worker| worker.pid == th.pid }
|
299
|
+
break # The worker unexpectedly exited
|
300
|
+
end
|
293
301
|
end
|
294
|
-
waiter.wait_one()
|
295
302
|
|
296
303
|
unless job_queue.closed?
|
297
304
|
# Exit by error
|
@@ -413,49 +420,7 @@ module Steep
|
|
413
420
|
end
|
414
421
|
|
415
422
|
if file_system_watcher_supported?
|
416
|
-
|
417
|
-
project.targets.each do |target|
|
418
|
-
target.source_pattern.patterns.each do |pat|
|
419
|
-
path = project.base_dir + pat
|
420
|
-
patterns << path.to_s unless path.directory?
|
421
|
-
end
|
422
|
-
target.source_pattern.prefixes.each do |pat|
|
423
|
-
path = project.base_dir + pat
|
424
|
-
patterns << (path + "**/*.rb").to_s unless path.file?
|
425
|
-
end
|
426
|
-
target.signature_pattern.patterns.each do |pat|
|
427
|
-
path = project.base_dir + pat
|
428
|
-
patterns << path.to_s unless path.directory?
|
429
|
-
end
|
430
|
-
target.signature_pattern.prefixes.each do |pat|
|
431
|
-
path = project.base_dir + pat
|
432
|
-
patterns << (path + "**/*.rbs").to_s unless path.file?
|
433
|
-
end
|
434
|
-
end
|
435
|
-
patterns.sort!
|
436
|
-
patterns.uniq!
|
437
|
-
|
438
|
-
Steep.logger.info { "Setting up didChangeWatchedFiles with pattern: #{patterns.inspect}" }
|
439
|
-
|
440
|
-
enqueue_write_job SendMessageJob.to_client(
|
441
|
-
message: {
|
442
|
-
id: SecureRandom.uuid,
|
443
|
-
method: "client/registerCapability",
|
444
|
-
params: {
|
445
|
-
registrations: [
|
446
|
-
{
|
447
|
-
id: SecureRandom.uuid,
|
448
|
-
method: "workspace/didChangeWatchedFiles",
|
449
|
-
registerOptions: {
|
450
|
-
watchers: patterns.map do |pattern|
|
451
|
-
{ globPattern: pattern }
|
452
|
-
end
|
453
|
-
}
|
454
|
-
}
|
455
|
-
]
|
456
|
-
}
|
457
|
-
}
|
458
|
-
)
|
423
|
+
setup_file_system_watcher()
|
459
424
|
end
|
460
425
|
|
461
426
|
controller.changed_paths.clear()
|
@@ -635,7 +600,7 @@ module Steep
|
|
635
600
|
enqueue_write_job SendMessageJob.to_client(
|
636
601
|
message: {
|
637
602
|
id: message[:id],
|
638
|
-
result: []
|
603
|
+
result: [] #: Array[untyped]
|
639
604
|
}
|
640
605
|
)
|
641
606
|
end
|
@@ -800,7 +765,7 @@ module Steep
|
|
800
765
|
Steep.logger.info "Starting new progress..."
|
801
766
|
|
802
767
|
@current_type_check_request = request
|
803
|
-
|
768
|
+
|
804
769
|
if progress
|
805
770
|
# If `request:` keyword arg is not given
|
806
771
|
request.work_done_progress.begin("Type checking", request_id: fresh_request_id)
|
@@ -836,6 +801,76 @@ module Steep
|
|
836
801
|
if current.finished?
|
837
802
|
finish_type_check(current)
|
838
803
|
@current_type_check_request = nil
|
804
|
+
refork_workers
|
805
|
+
end
|
806
|
+
end
|
807
|
+
end
|
808
|
+
end
|
809
|
+
|
810
|
+
def refork_workers
|
811
|
+
return unless @need_to_refork
|
812
|
+
@need_to_refork = false
|
813
|
+
|
814
|
+
Thread.new do
|
815
|
+
Thread.current.abort_on_exception = true
|
816
|
+
|
817
|
+
primary, *others = typecheck_workers
|
818
|
+
primary or raise
|
819
|
+
others.each do |worker|
|
820
|
+
worker.index or raise
|
821
|
+
|
822
|
+
refork_mutex.synchronize do
|
823
|
+
refork_finished = Thread::Queue.new
|
824
|
+
stdin_in, stdin_out = IO.pipe
|
825
|
+
stdout_in, stdout_out = IO.pipe
|
826
|
+
|
827
|
+
result_controller << send_refork_request(params: { index: worker.index, max_index: typecheck_workers.size }, worker: primary) do |handler|
|
828
|
+
handler.on_completion do |response|
|
829
|
+
writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdin_out)
|
830
|
+
reader = LanguageServer::Protocol::Transport::Io::Reader.new(stdout_in)
|
831
|
+
|
832
|
+
pid = response[:result][:pid]
|
833
|
+
# It does not need to wait worker process
|
834
|
+
# because the primary worker monitors it instead.
|
835
|
+
#
|
836
|
+
# @type var wait_thread: Thread & WorkerProcess::_ProcessWaitThread
|
837
|
+
wait_thread = _ = Thread.new { sleep }
|
838
|
+
wait_thread.define_singleton_method(:pid) { pid }
|
839
|
+
|
840
|
+
new_worker = WorkerProcess.new(reader:, writer:, stderr: nil, wait_thread:, name: "#{worker.name}-2", index: worker.index)
|
841
|
+
old_worker = typecheck_workers[worker.index] or raise
|
842
|
+
|
843
|
+
typecheck_workers[(new_worker.index or raise)] = new_worker
|
844
|
+
|
845
|
+
original_old_worker = old_worker.dup
|
846
|
+
old_worker.redirect_to new_worker
|
847
|
+
|
848
|
+
refork_finished << true
|
849
|
+
|
850
|
+
result_controller << send_request(method: 'shutdown', worker: original_old_worker) do |handler|
|
851
|
+
handler.on_completion do
|
852
|
+
send_request(method: 'exit', worker: original_old_worker)
|
853
|
+
end
|
854
|
+
end
|
855
|
+
|
856
|
+
Thread.new do
|
857
|
+
tags = Steep.logger.formatter.current_tags.dup
|
858
|
+
Steep.logger.formatter.push_tags(*tags, "from-worker@#{new_worker.name}")
|
859
|
+
new_worker.reader.read do |message|
|
860
|
+
job_queue << ReceiveMessageJob.new(source: new_worker, message: message)
|
861
|
+
end
|
862
|
+
end
|
863
|
+
end
|
864
|
+
end
|
865
|
+
|
866
|
+
# The primary worker starts forking when it receives the IOs.
|
867
|
+
primary.io_socket or raise
|
868
|
+
primary.io_socket.send_io(stdin_in)
|
869
|
+
primary.io_socket.send_io(stdout_out)
|
870
|
+
stdin_in.close
|
871
|
+
stdout_out.close
|
872
|
+
|
873
|
+
refork_finished.pop
|
839
874
|
end
|
840
875
|
end
|
841
876
|
end
|
@@ -868,6 +903,25 @@ module Steep
|
|
868
903
|
end
|
869
904
|
end
|
870
905
|
|
906
|
+
def send_refork_request(id: fresh_request_id(), params:, worker:, &block)
|
907
|
+
method = CustomMethods::Refork::METHOD
|
908
|
+
Steep.logger.info "Sending request #{method}(#{id}) to #{worker.name}"
|
909
|
+
|
910
|
+
# @type var message: lsp_request
|
911
|
+
message = { method: method, id: id, params: params }
|
912
|
+
ResultHandler.new(request: message).tap do |handler|
|
913
|
+
yield handler if block
|
914
|
+
|
915
|
+
job = SendMessageJob.to_worker(worker, message: message)
|
916
|
+
case job.dest
|
917
|
+
when WorkerProcess
|
918
|
+
job.dest << job.message
|
919
|
+
else
|
920
|
+
raise "Unexpected destination: #{job.dest}"
|
921
|
+
end
|
922
|
+
end
|
923
|
+
end
|
924
|
+
|
871
925
|
def group_request()
|
872
926
|
GroupHandler.new().tap do |group|
|
873
927
|
yield group
|
@@ -907,6 +961,58 @@ module Steep
|
|
907
961
|
)
|
908
962
|
end
|
909
963
|
end
|
964
|
+
|
965
|
+
def setup_file_system_watcher()
|
966
|
+
patterns = [] #: Array[String]
|
967
|
+
|
968
|
+
project.targets.each do |target|
|
969
|
+
patterns.concat(paths_to_watch(target.source_pattern, extname: ".rb"))
|
970
|
+
patterns.concat(paths_to_watch(target.signature_pattern, extname: ".rbs"))
|
971
|
+
target.groups.each do |group|
|
972
|
+
patterns.concat(paths_to_watch(group.source_pattern, extname: ".rb"))
|
973
|
+
patterns.concat(paths_to_watch(group.signature_pattern, extname: ".rbs"))
|
974
|
+
end
|
975
|
+
end
|
976
|
+
patterns.sort!
|
977
|
+
patterns.uniq!
|
978
|
+
|
979
|
+
Steep.logger.info { "Setting up didChangeWatchedFiles with pattern: #{patterns.inspect}" }
|
980
|
+
|
981
|
+
enqueue_write_job SendMessageJob.to_client(
|
982
|
+
message: {
|
983
|
+
id: SecureRandom.uuid,
|
984
|
+
method: "client/registerCapability",
|
985
|
+
params: {
|
986
|
+
registrations: [
|
987
|
+
{
|
988
|
+
id: SecureRandom.uuid,
|
989
|
+
method: "workspace/didChangeWatchedFiles",
|
990
|
+
registerOptions: {
|
991
|
+
watchers: patterns.map do |pattern|
|
992
|
+
{ globPattern: pattern }
|
993
|
+
end
|
994
|
+
}
|
995
|
+
}
|
996
|
+
]
|
997
|
+
}
|
998
|
+
}
|
999
|
+
)
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
def paths_to_watch(pattern, extname:)
|
1003
|
+
result = [] #: Array[String]
|
1004
|
+
|
1005
|
+
pattern.patterns.each do |pat|
|
1006
|
+
path = project.base_dir + pat
|
1007
|
+
result << path.to_s unless path.directory?
|
1008
|
+
end
|
1009
|
+
pattern.prefixes.each do |pat|
|
1010
|
+
path = project.base_dir + pat
|
1011
|
+
result << (path + "**/*#{extname}").to_s unless path.file?
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
result
|
1015
|
+
end
|
910
1016
|
end
|
911
1017
|
end
|
912
1018
|
end
|
@@ -51,15 +51,28 @@ module Steep
|
|
51
51
|
|
52
52
|
include ChangeBuffer
|
53
53
|
|
54
|
-
|
54
|
+
attr_reader :io_socket
|
55
|
+
|
56
|
+
def initialize(project:, reader:, writer:, assignment:, commandline_args:, io_socket: nil, buffered_changes: nil, service: nil)
|
55
57
|
super(project: project, reader: reader, writer: writer)
|
56
58
|
|
57
59
|
@assignment = assignment
|
58
|
-
@buffered_changes = {}
|
60
|
+
@buffered_changes = buffered_changes || {}
|
59
61
|
@mutex = Mutex.new()
|
60
62
|
@queue = Queue.new
|
61
63
|
@commandline_args = commandline_args
|
62
64
|
@current_type_check_guid = nil
|
65
|
+
@io_socket = io_socket
|
66
|
+
@service = service if service
|
67
|
+
@child_pids = []
|
68
|
+
|
69
|
+
if io_socket
|
70
|
+
Signal.trap "SIGCHLD" do
|
71
|
+
while pid = Process.wait(-1, Process::WNOHANG)
|
72
|
+
raise "Unexpected worker process exit: #{pid}" if @child_pids.include?(pid)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
63
76
|
end
|
64
77
|
|
65
78
|
def service
|
@@ -98,6 +111,39 @@ module Steep
|
|
98
111
|
queue << GotoJob.implementation(id: request[:id], params: request[:params])
|
99
112
|
when "textDocument/typeDefinition"
|
100
113
|
queue << GotoJob.type_definition(id: request[:id], params: request[:params])
|
114
|
+
when CustomMethods::Refork::METHOD
|
115
|
+
io_socket or raise
|
116
|
+
|
117
|
+
# Receive IOs before fork to avoid receiving them from multiple processes
|
118
|
+
stdin = io_socket.recv_io
|
119
|
+
stdout = io_socket.recv_io
|
120
|
+
|
121
|
+
if pid = fork
|
122
|
+
stdin.close
|
123
|
+
stdout.close
|
124
|
+
@child_pids << pid
|
125
|
+
writer.write(CustomMethods::Refork.response(request[:id], { pid: }))
|
126
|
+
else
|
127
|
+
io_socket.close
|
128
|
+
|
129
|
+
reader.close
|
130
|
+
writer.close
|
131
|
+
|
132
|
+
reader = LanguageServer::Protocol::Transport::Io::Reader.new(stdin)
|
133
|
+
writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdout)
|
134
|
+
Steep.logger.info("Reforked worker: #{Process.pid}, params: #{request[:params]}")
|
135
|
+
index = request[:params][:index]
|
136
|
+
assignment = Services::PathAssignment.new(max_index: request[:params][:max_index], index: index)
|
137
|
+
|
138
|
+
worker = self.class.new(project: project, reader: reader, writer: writer, assignment: assignment, commandline_args: commandline_args, io_socket: nil, buffered_changes: buffered_changes, service: service)
|
139
|
+
|
140
|
+
tags = Steep.logger.formatter.current_tags.dup
|
141
|
+
tags[tags.find_index("typecheck:typecheck@0")] = "typecheck:typecheck@#{index}-reforked"
|
142
|
+
Steep.logger.formatter.push_tags(tags)
|
143
|
+
worker.run()
|
144
|
+
|
145
|
+
raise "unreachable"
|
146
|
+
end
|
101
147
|
end
|
102
148
|
end
|
103
149
|
|
@@ -8,32 +8,30 @@ module Steep
|
|
8
8
|
attr_reader :name
|
9
9
|
attr_reader :wait_thread
|
10
10
|
attr_reader :index
|
11
|
+
attr_reader :io_socket
|
11
12
|
|
12
|
-
def initialize(reader:, writer:, stderr:, wait_thread:, name:, index: nil)
|
13
|
+
def initialize(reader:, writer:, io_socket: nil, stderr:, wait_thread:, name:, index: nil)
|
13
14
|
@reader = reader
|
14
15
|
@writer = writer
|
15
16
|
@stderr = stderr
|
17
|
+
@io_socket = io_socket
|
16
18
|
@wait_thread = wait_thread
|
17
19
|
@name = name
|
18
20
|
@index = index
|
19
21
|
end
|
20
22
|
|
21
23
|
def self.start_worker(type, name:, steepfile:, steep_command:, index: nil, delay_shutdown: false, patterns: [])
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
# Use `#spawn_worker`
|
34
|
-
raise NotImplementedError
|
35
|
-
end
|
36
|
-
rescue NotImplementedError
|
24
|
+
if Steep.can_fork? && !steep_command
|
25
|
+
fork_worker(
|
26
|
+
type,
|
27
|
+
name: name,
|
28
|
+
steepfile: steepfile,
|
29
|
+
index: index,
|
30
|
+
is_primary: index && (index[1] == 0 && index[0] >= 2),
|
31
|
+
delay_shutdown: delay_shutdown,
|
32
|
+
patterns: patterns
|
33
|
+
)
|
34
|
+
else
|
37
35
|
spawn_worker(
|
38
36
|
type,
|
39
37
|
name: name,
|
@@ -46,9 +44,10 @@ module Steep
|
|
46
44
|
end
|
47
45
|
end
|
48
46
|
|
49
|
-
def self.fork_worker(type, name:, steepfile:, index:, delay_shutdown:, patterns:)
|
47
|
+
def self.fork_worker(type, name:, steepfile:, index:, delay_shutdown:, patterns:, is_primary:)
|
50
48
|
stdin_in, stdin_out = IO.pipe
|
51
49
|
stdout_in, stdout_out = IO.pipe
|
50
|
+
sock_master, sock_worker = UNIXSocket.socketpair if is_primary
|
52
51
|
|
53
52
|
worker = Drivers::Worker.new(stdout: stdout_out, stdin: stdin_in, stderr: STDERR)
|
54
53
|
|
@@ -61,12 +60,14 @@ module Steep
|
|
61
60
|
worker.index = this
|
62
61
|
end
|
63
62
|
worker.commandline_args = patterns
|
63
|
+
worker.io_socket = sock_worker
|
64
64
|
|
65
65
|
pid = fork do
|
66
66
|
Process.setpgid(0, 0)
|
67
67
|
Steep.ui_logger.level = :fatal
|
68
68
|
stdin_out.close
|
69
69
|
stdout_in.close
|
70
|
+
sock_master&.close
|
70
71
|
worker.run()
|
71
72
|
end
|
72
73
|
|
@@ -81,6 +82,7 @@ module Steep
|
|
81
82
|
|
82
83
|
stdin_in.close
|
83
84
|
stdout_out.close
|
85
|
+
sock_worker&.close
|
84
86
|
|
85
87
|
new(
|
86
88
|
reader: reader,
|
@@ -88,7 +90,8 @@ module Steep
|
|
88
90
|
stderr: STDERR,
|
89
91
|
wait_thread: wait_thread,
|
90
92
|
name: name,
|
91
|
-
index: index&.[](1)
|
93
|
+
index: index&.[](1),
|
94
|
+
io_socket: sock_master,
|
92
95
|
)
|
93
96
|
end
|
94
97
|
|
@@ -146,6 +149,10 @@ module Steep
|
|
146
149
|
end
|
147
150
|
end
|
148
151
|
|
152
|
+
def redirect_to(worker)
|
153
|
+
@writer = worker.writer
|
154
|
+
end
|
155
|
+
|
149
156
|
def <<(message)
|
150
157
|
writer.write(message)
|
151
158
|
end
|
@@ -155,11 +162,11 @@ module Steep
|
|
155
162
|
end
|
156
163
|
|
157
164
|
def kill(force: false)
|
158
|
-
Steep.logger.tagged("WorkerProcess#kill@#{name}(#{
|
165
|
+
Steep.logger.tagged("WorkerProcess#kill@#{name}(#{pid})") do
|
159
166
|
begin
|
160
167
|
signal = force ? :KILL : :TERM
|
161
168
|
Steep.logger.debug("Sending signal SIG#{signal}...")
|
162
|
-
Process.kill(signal,
|
169
|
+
Process.kill(signal, pid)
|
163
170
|
Steep.logger.debug("Successfully sent the signal.")
|
164
171
|
rescue Errno::ESRCH => error
|
165
172
|
Steep.logger.debug("Failed #{error.inspect}")
|
@@ -171,6 +178,10 @@ module Steep
|
|
171
178
|
end
|
172
179
|
end
|
173
180
|
end
|
181
|
+
|
182
|
+
def pid
|
183
|
+
wait_thread.pid
|
184
|
+
end
|
174
185
|
end
|
175
186
|
end
|
176
187
|
end
|
@@ -51,9 +51,29 @@ module Steep
|
|
51
51
|
raise
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
def deprecated?
|
56
|
+
annotations =
|
57
|
+
case entry = env.constant_entry(full_name)
|
58
|
+
when RBS::Environment::ConstantEntry
|
59
|
+
entry.decl.annotations
|
60
|
+
when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
|
61
|
+
entry.decls.flat_map { _1.decl.annotations }
|
62
|
+
when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
|
63
|
+
entry.decl.annotations
|
64
|
+
else
|
65
|
+
raise
|
66
|
+
end
|
67
|
+
|
68
|
+
if AnnotationsHelper.deprecated_annotation?(annotations)
|
69
|
+
true
|
70
|
+
else
|
71
|
+
false
|
72
|
+
end
|
73
|
+
end
|
54
74
|
end
|
55
75
|
|
56
|
-
SimpleMethodNameItem = _ = Struct.new(:identifier, :range, :receiver_type, :method_types, :method_member, :method_name, keyword_init: true) do
|
76
|
+
SimpleMethodNameItem = _ = Struct.new(:identifier, :range, :receiver_type, :method_types, :method_member, :method_name, :deprecated, keyword_init: true) do
|
57
77
|
# @implements SimpleMethodNameItem
|
58
78
|
|
59
79
|
def comment
|
@@ -640,13 +660,15 @@ module Steep
|
|
640
660
|
all_members.each do |member|
|
641
661
|
associated_decl = all_decls.find {|decl| decl.method_def.member == member } or next
|
642
662
|
overloads = method_entry.overloads.select {|overload| overload.method_defs.any? {|defn| defn.member == member }}
|
663
|
+
annotations = associated_decl.method_def.member_annotations
|
643
664
|
items << SimpleMethodNameItem.new(
|
644
665
|
identifier: name,
|
645
666
|
range: range,
|
646
667
|
receiver_type: type,
|
647
668
|
method_name: associated_decl.method_name,
|
648
669
|
method_types: overloads.map {|overload| subtyping.factory.method_type_1(overload.method_type) },
|
649
|
-
method_member: member
|
670
|
+
method_member: member,
|
671
|
+
deprecated: AnnotationsHelper.deprecated_annotation?(annotations) ? true : false
|
650
672
|
)
|
651
673
|
end
|
652
674
|
else
|
@@ -295,7 +295,7 @@ module Steep
|
|
295
295
|
|
296
296
|
unless errors.empty?
|
297
297
|
# Builder won't be used.
|
298
|
-
factory = AST::Types::Factory.new(builder:
|
298
|
+
factory = AST::Types::Factory.new(builder: RBS::DefinitionBuilder.new(env: env, ancestor_builder: builder))
|
299
299
|
return errors.map {|error| Diagnostic::Signature.from_rbs_error(error, factory: factory) }
|
300
300
|
end
|
301
301
|
|
@@ -302,7 +302,22 @@ module Steep
|
|
302
302
|
def self.type_check(source:, subtyping:, constant_resolver:, cursor:)
|
303
303
|
annotations = source.annotations(block: source.node, factory: subtyping.factory, context: nil)
|
304
304
|
|
305
|
-
|
305
|
+
case annotations.self_type
|
306
|
+
when AST::Types::Name::Instance
|
307
|
+
module_name = annotations.self_type.name
|
308
|
+
module_type = AST::Types::Name::Singleton.new(name: module_name)
|
309
|
+
instance_type = annotations.self_type
|
310
|
+
when AST::Types::Name::Singleton
|
311
|
+
module_name = annotations.self_type.name
|
312
|
+
module_type = annotations.self_type
|
313
|
+
instance_type = annotations.self_type
|
314
|
+
else
|
315
|
+
module_name = AST::Builtin::Object.module_name
|
316
|
+
module_type = AST::Builtin::Object.module_type
|
317
|
+
instance_type = AST::Builtin::Object.instance_type
|
318
|
+
end
|
319
|
+
|
320
|
+
definition = subtyping.factory.definition_builder.build_instance(module_name)
|
306
321
|
|
307
322
|
const_env = TypeInference::ConstantEnv.new(
|
308
323
|
factory: subtyping.factory,
|
@@ -321,17 +336,17 @@ module Steep
|
|
321
336
|
context = TypeInference::Context.new(
|
322
337
|
block_context: nil,
|
323
338
|
module_context: TypeInference::Context::ModuleContext.new(
|
324
|
-
instance_type:
|
325
|
-
module_type:
|
339
|
+
instance_type: instance_type,
|
340
|
+
module_type: module_type,
|
326
341
|
implement_name: nil,
|
327
342
|
nesting: nil,
|
328
|
-
class_name:
|
329
|
-
instance_definition: subtyping.factory.definition_builder.build_instance(
|
330
|
-
module_definition: subtyping.factory.definition_builder.build_singleton(
|
343
|
+
class_name: module_name,
|
344
|
+
instance_definition: subtyping.factory.definition_builder.build_instance(module_name),
|
345
|
+
module_definition: subtyping.factory.definition_builder.build_singleton(module_name)
|
331
346
|
),
|
332
347
|
method_context: nil,
|
333
348
|
break_context: nil,
|
334
|
-
self_type:
|
349
|
+
self_type: instance_type,
|
335
350
|
type_env: type_env,
|
336
351
|
call_context: TypeInference::MethodCall::TopLevelContext.new,
|
337
352
|
variable_context: TypeInference::Context::TypeVariableContext.empty
|
data/lib/steep/source.rb
CHANGED
@@ -498,6 +498,8 @@ module Steep
|
|
498
498
|
# Skip
|
499
499
|
when :kwargs
|
500
500
|
# skip
|
501
|
+
when :when
|
502
|
+
# skip
|
501
503
|
when :pair
|
502
504
|
key, value = node.children
|
503
505
|
key = insert_type_node(key, comments.except(last_line))
|
@@ -644,7 +646,7 @@ module Steep
|
|
644
646
|
receiver_node, name, _, location = deconstruct_send_node!(send_node)
|
645
647
|
|
646
648
|
if receiver_node
|
647
|
-
if location.dot
|
649
|
+
if location.dot && location.selector
|
648
650
|
location.selector.line
|
649
651
|
end
|
650
652
|
else
|
@@ -285,11 +285,6 @@ module Steep
|
|
285
285
|
)
|
286
286
|
end
|
287
287
|
|
288
|
-
when relation.sub_type.is_a?(AST::Types::Self) && !self_type.is_a?(AST::Types::Self)
|
289
|
-
Expand(relation) do
|
290
|
-
check_type(Relation.new(sub_type: self_type, super_type: relation.super_type))
|
291
|
-
end
|
292
|
-
|
293
288
|
when relation.sub_type.is_a?(AST::Types::Instance) && !instance_type.is_a?(AST::Types::Instance)
|
294
289
|
Expand(relation) do
|
295
290
|
check_type(Relation.new(sub_type: instance_type, super_type: relation.super_type))
|
@@ -419,6 +414,11 @@ module Steep
|
|
419
414
|
end
|
420
415
|
end
|
421
416
|
|
417
|
+
when relation.sub_type.is_a?(AST::Types::Self) && !self_type.is_a?(AST::Types::Self)
|
418
|
+
Expand(relation) do
|
419
|
+
check_type(Relation.new(sub_type: self_type, super_type: relation.super_type))
|
420
|
+
end
|
421
|
+
|
422
422
|
when relation.super_type.is_a?(AST::Types::Name::Interface)
|
423
423
|
Expand(relation) do
|
424
424
|
check_interface(
|
@@ -493,7 +493,7 @@ module Steep
|
|
493
493
|
end
|
494
494
|
|
495
495
|
when relation.sub_type.is_a?(AST::Types::Tuple) && relation.super_type.is_a?(AST::Types::Tuple)
|
496
|
-
if relation.sub_type.types.size
|
496
|
+
if relation.sub_type.types.size == relation.super_type.types.size
|
497
497
|
pairs = relation.sub_type.types.take(relation.super_type.types.size).zip(relation.super_type.types)
|
498
498
|
|
499
499
|
All(relation) do |result|
|
@@ -541,21 +541,28 @@ module Steep
|
|
541
541
|
|
542
542
|
when relation.sub_type.is_a?(AST::Types::Record) && relation.super_type.is_a?(AST::Types::Record)
|
543
543
|
All(relation) do |result|
|
544
|
+
unchecked_keys = Set.new(relation.sub_type.elements.each_key)
|
545
|
+
|
544
546
|
relation.super_type.elements.each_key do |key|
|
545
|
-
super_element_type = relation.super_type.elements
|
547
|
+
super_element_type = relation.super_type.elements.fetch(key) #: AST::Types::t
|
548
|
+
sub_element_type = relation.sub_type.elements.fetch(key, nil) #: AST::Types::t?
|
546
549
|
|
547
|
-
if relation.
|
548
|
-
|
550
|
+
if relation.super_type.required?(key)
|
551
|
+
rel = Relation.new(sub_type: sub_element_type || AST::Builtin.nil_type, super_type: super_element_type)
|
552
|
+
result.add(rel) { check_type(rel) }
|
549
553
|
else
|
550
|
-
|
551
|
-
|
554
|
+
# If the key is optional, it's okay to not have the key
|
555
|
+
if sub_element_type
|
556
|
+
rel = Relation.new(sub_type: sub_element_type, super_type: super_element_type)
|
557
|
+
result.add(rel) { check_type(rel) }
|
552
558
|
end
|
553
559
|
end
|
554
560
|
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
561
|
+
unchecked_keys.delete(key)
|
562
|
+
end
|
563
|
+
|
564
|
+
unless unchecked_keys.empty?
|
565
|
+
return Failure(relation, Result::Failure::UnknownPairError.new(relation: relation))
|
559
566
|
end
|
560
567
|
end
|
561
568
|
|
@@ -601,7 +608,6 @@ module Steep
|
|
601
608
|
Expand(relation) do
|
602
609
|
check_type(Relation.new(sub_type: relation.sub_type.back_type, super_type: relation.super_type))
|
603
610
|
end
|
604
|
-
|
605
611
|
else
|
606
612
|
Failure(relation, Result::Failure::UnknownPairError.new(relation: relation))
|
607
613
|
end
|