steep 1.9.4 → 1.10.0.pre.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -3
  3. data/Steepfile +5 -2
  4. data/lib/steep/annotations_helper.rb +43 -0
  5. data/lib/steep/ast/ignore.rb +3 -4
  6. data/lib/steep/cli.rb +102 -23
  7. data/lib/steep/diagnostic/lsp_formatter.rb +17 -3
  8. data/lib/steep/diagnostic/ruby.rb +75 -0
  9. data/lib/steep/diagnostic/signature.rb +20 -0
  10. data/lib/steep/drivers/check.rb +3 -1
  11. data/lib/steep/drivers/diagnostic_printer/base_formatter.rb +19 -0
  12. data/lib/steep/drivers/diagnostic_printer/code_formatter.rb +95 -0
  13. data/lib/steep/drivers/diagnostic_printer/github_actions_formatter.rb +44 -0
  14. data/lib/steep/drivers/diagnostic_printer.rb +9 -86
  15. data/lib/steep/drivers/langserver.rb +4 -1
  16. data/lib/steep/drivers/worker.rb +2 -0
  17. data/lib/steep/interface/builder.rb +2 -2
  18. data/lib/steep/server/custom_methods.rb +12 -0
  19. data/lib/steep/server/interaction_worker.rb +33 -6
  20. data/lib/steep/server/master.rb +103 -7
  21. data/lib/steep/server/type_check_worker.rb +48 -2
  22. data/lib/steep/server/worker_process.rb +31 -20
  23. data/lib/steep/services/completion_provider.rb +12 -2
  24. data/lib/steep/services/signature_service.rb +2 -2
  25. data/lib/steep/services/type_check_service.rb +22 -7
  26. data/lib/steep/signature/validator.rb +56 -4
  27. data/lib/steep/source.rb +3 -1
  28. data/lib/steep/subtyping/check.rb +22 -16
  29. data/lib/steep/type_construction.rb +153 -34
  30. data/lib/steep/type_inference/case_when.rb +2 -0
  31. data/lib/steep/type_inference/logic_type_interpreter.rb +77 -15
  32. data/lib/steep/type_inference/method_call.rb +5 -3
  33. data/lib/steep/version.rb +1 -1
  34. data/lib/steep.rb +10 -0
  35. data/manual/ruby-diagnostics.md +114 -1
  36. data/sample/Steepfile +0 -2
  37. data/sample/lib/conference.rb +14 -0
  38. data/sample/lib/deprecated.rb +7 -0
  39. data/sample/sig/deprecated.rbs +16 -0
  40. data/steep.gemspec +4 -3
  41. metadata +28 -8
@@ -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
- begin
23
- unless steep_command
24
- fork_worker(
25
- type,
26
- name: name,
27
- steepfile: steepfile,
28
- index: index,
29
- delay_shutdown: delay_shutdown,
30
- patterns: patterns
31
- )
32
- else
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}(#{wait_thread.pid})") do
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, wait_thread.pid)
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,17 @@ module Steep
51
51
  raise
52
52
  end
53
53
  end
54
+
55
+ def deprecated?
56
+ if AnnotationsHelper.deprecated_type_name?(full_name, env)
57
+ true
58
+ else
59
+ false
60
+ end
61
+ end
54
62
  end
55
63
 
56
- SimpleMethodNameItem = _ = Struct.new(:identifier, :range, :receiver_type, :method_types, :method_member, :method_name, keyword_init: true) do
64
+ SimpleMethodNameItem = _ = Struct.new(:identifier, :range, :receiver_type, :method_types, :method_member, :method_name, :deprecated, keyword_init: true) do
57
65
  # @implements SimpleMethodNameItem
58
66
 
59
67
  def comment
@@ -640,13 +648,15 @@ module Steep
640
648
  all_members.each do |member|
641
649
  associated_decl = all_decls.find {|decl| decl.method_def.member == member } or next
642
650
  overloads = method_entry.overloads.select {|overload| overload.method_defs.any? {|defn| defn.member == member }}
651
+ annotations = associated_decl.method_def.member_annotations
643
652
  items << SimpleMethodNameItem.new(
644
653
  identifier: name,
645
654
  range: range,
646
655
  receiver_type: type,
647
656
  method_name: associated_decl.method_name,
648
657
  method_types: overloads.map {|overload| subtyping.factory.method_type_1(overload.method_type) },
649
- method_member: member
658
+ method_member: member,
659
+ deprecated: AnnotationsHelper.deprecated_annotation?(annotations) ? true : false
650
660
  )
651
661
  end
652
662
  else
@@ -294,8 +294,8 @@ module Steep
294
294
  end
295
295
 
296
296
  unless errors.empty?
297
- # Builder won't be used.
298
- factory = AST::Types::Factory.new(builder: _ = nil)
297
+ errors.uniq! { |e| [e.class, e.message] }
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
- definition = subtyping.factory.definition_builder.build_instance(AST::Builtin::Object.module_name)
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: AST::Builtin::Object.instance_type,
325
- module_type: AST::Builtin::Object.module_type,
339
+ instance_type: instance_type,
340
+ module_type: module_type,
326
341
  implement_name: nil,
327
342
  nesting: nil,
328
- class_name: AST::Builtin::Object.module_name,
329
- instance_definition: subtyping.factory.definition_builder.build_instance(AST::Builtin::Object.module_name),
330
- module_definition: subtyping.factory.definition_builder.build_singleton(AST::Builtin::Object.module_name)
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: AST::Builtin::Object.instance_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
@@ -144,17 +144,39 @@ module Steep
144
144
  validate_type_application_constraints(name, type_params, type_args, location: type.location)
145
145
  end
146
146
  end
147
-
148
- type.each_type do |child|
149
- validate_type_application(child)
150
- end
151
147
  end
152
148
 
153
149
  def validate_type(type)
154
150
  Steep.logger.debug { "#{Location.to_string type.location}: Validating #{type}..." }
155
151
 
156
152
  validator.validate_type(type, context: nil)
153
+ validate_type_0(type)
154
+ end
155
+
156
+ def validate_type_0(type)
157
157
  validate_type_application(type)
158
+
159
+ case type
160
+ when RBS::Types::ClassInstance, RBS::Types::Interface, RBS::Types::ClassSingleton, RBS::Types::Alias
161
+ type_name = type.name
162
+ if type.location
163
+ location = type.location[:name]
164
+ end
165
+ end
166
+
167
+ if type_name && location
168
+ validate_type_name_deprecation(type_name, location)
169
+ end
170
+
171
+ type.each_type do |child|
172
+ validate_type_0(child)
173
+ end
174
+ end
175
+
176
+ def validate_type_name_deprecation(type_name, location)
177
+ if (_, message = AnnotationsHelper.deprecated_type_name?(type_name, env))
178
+ @errors << Diagnostic::Signature::DeprecatedTypeName.new(type_name, message, location: location)
179
+ end
158
180
  end
159
181
 
160
182
  def ancestor_to_type(ancestor)
@@ -269,6 +291,9 @@ module Steep
269
291
  type_params.each do |type_param|
270
292
  param = checker.factory.type_param(type_param)
271
293
 
294
+ validate_type(type_param.upper_bound_type) if type_param.upper_bound_type
295
+ validate_type(type_param.default_type) if type_param.default_type
296
+
272
297
  default_type = param.default_type or next
273
298
  upper_bound = param.upper_bound or next
274
299
 
@@ -296,6 +321,16 @@ module Steep
296
321
  args: entry.type_params.map { AST::Types::Any.instance() }
297
322
  )
298
323
 
324
+ entry.decls.each do |decl|
325
+ ast = decl.decl
326
+
327
+ unless AnnotationsHelper.deprecated_annotation?(ast.annotations)
328
+ if location = ast.location
329
+ validate_type_name_deprecation(name, location[:name])
330
+ end
331
+ end
332
+ end
333
+
299
334
  Steep.logger.tagged "#{name}" do
300
335
  builder.build_instance(name).tap do |definition|
301
336
  upper_bounds = definition.type_params_decl.each.with_object({}) do |param, bounds| #$ Hash[Symbol, AST::Types::t?]
@@ -353,6 +388,20 @@ module Steep
353
388
  case ancestor
354
389
  when RBS::Definition::Ancestor::Instance
355
390
  validate_ancestor_application(name, ancestor)
391
+ location =
392
+ case ancestor.source
393
+ when :super
394
+ if (primary_decl = entry.primary.decl).is_a?(RBS::AST::Declarations::Class)
395
+ primary_decl.super_class&.location
396
+ end
397
+ when nil
398
+ # skip
399
+ else
400
+ ancestor.source.location
401
+ end
402
+ if location
403
+ validate_type_name_deprecation(ancestor.name, location)
404
+ end
356
405
  end
357
406
  end
358
407
 
@@ -632,6 +681,9 @@ module Steep
632
681
  rescue_validation_errors(name) do
633
682
  Steep.logger.debug "Validating class/module alias `#{name}`..."
634
683
  validator.validate_class_alias(entry: entry)
684
+ if location = entry.decl.location
685
+ validate_type_name_deprecation(entry.decl.old_name, location[:old_name])
686
+ end
635
687
  end
636
688
  end
637
689
 
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 >= relation.super_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[key]
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.sub_type.elements.key?(key)
548
- sub_element_type = relation.sub_type.elements[key]
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
- if relation.super_type.required?(key)
551
- sub_element_type = AST::Builtin.nil_type
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
- 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) }
558
- end
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