steep 1.2.1 → 1.3.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/Gemfile.lock +4 -4
  4. data/Gemfile.steep +1 -1
  5. data/Gemfile.steep.lock +13 -3
  6. data/Steepfile +0 -1
  7. data/lib/steep/annotation_parser.rb +34 -28
  8. data/lib/steep/ast/annotation.rb +16 -5
  9. data/lib/steep/ast/node/type_application.rb +74 -0
  10. data/lib/steep/ast/node/type_assertion.rb +56 -0
  11. data/lib/steep/ast/types/factory.rb +5 -1
  12. data/lib/steep/diagnostic/helper.rb +2 -1
  13. data/lib/steep/diagnostic/lsp_formatter.rb +3 -1
  14. data/lib/steep/diagnostic/ruby.rb +70 -5
  15. data/lib/steep/diagnostic/signature.rb +21 -8
  16. data/lib/steep/drivers/check.rb +1 -1
  17. data/lib/steep/drivers/checkfile.rb +1 -1
  18. data/lib/steep/drivers/langserver.rb +2 -2
  19. data/lib/steep/drivers/stats.rb +1 -1
  20. data/lib/steep/drivers/watch.rb +1 -1
  21. data/lib/steep/drivers/worker.rb +0 -1
  22. data/lib/steep/server/lsp_formatter.rb +13 -3
  23. data/lib/steep/server/master.rb +4 -1
  24. data/lib/steep/server/worker_process.rb +86 -14
  25. data/lib/steep/services/hover_provider/rbs.rb +7 -7
  26. data/lib/steep/services/hover_provider/ruby.rb +19 -4
  27. data/lib/steep/services/signature_service.rb +7 -4
  28. data/lib/steep/signature/validator.rb +36 -13
  29. data/lib/steep/source.rb +189 -71
  30. data/lib/steep/type_construction.rb +232 -126
  31. data/lib/steep/type_inference/logic_type_interpreter.rb +3 -1
  32. data/lib/steep/version.rb +1 -1
  33. data/lib/steep.rb +2 -0
  34. data/rbs_collection.steep.lock.yaml +27 -10
  35. data/rbs_collection.steep.yaml +0 -1
  36. data/sig/shims/exception.rbs +4 -0
  37. data/sig/shims/parser/comment.rbs +33 -0
  38. data/sig/shims/parser.rbs +30 -2
  39. data/sig/steep/annotation_parser.rbs +59 -0
  40. data/sig/steep/ast/annotation.rbs +21 -26
  41. data/sig/steep/ast/node/type_application.rbs +31 -0
  42. data/sig/steep/ast/node/type_assertion.rbs +26 -0
  43. data/sig/steep/ast/types/factory.rbs +0 -2
  44. data/sig/steep/diagnostic/helper.rbs +9 -3
  45. data/sig/steep/diagnostic/lsp_formatter.rbs +12 -8
  46. data/sig/steep/diagnostic/ruby.rbs +62 -8
  47. data/sig/steep/diagnostic/signature.rbs +118 -85
  48. data/sig/steep/drivers/worker.rbs +11 -13
  49. data/sig/steep/range_extension.rbs +7 -0
  50. data/sig/steep/server/lsp_formatter.rbs +14 -7
  51. data/sig/steep/server/worker_process.rbs +74 -12
  52. data/sig/steep/services/hover_provider/rbs.rbs +27 -7
  53. data/sig/steep/services/hover_provider/ruby.rbs +18 -4
  54. data/sig/steep/services/hover_provider/singleton_methods.rbs +1 -1
  55. data/sig/steep/signature/validator.rbs +76 -0
  56. data/sig/steep/source.rbs +54 -30
  57. data/sig/steep/type_construction.rbs +85 -27
  58. data/sig/steep/type_inference/method_call.rbs +1 -1
  59. data/smoke/diagnostics-rbs/inherit-module.rbs +2 -0
  60. data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
  61. data/steep.gemspec +1 -1
  62. metadata +16 -6
data/lib/steep/source.rb CHANGED
@@ -1,27 +1,11 @@
1
1
  module Steep
2
2
  class Source
3
- class LocatedAnnotation
4
- attr_reader :line
5
- attr_reader :annotation
6
- attr_reader :source
7
-
8
- def initialize(line:, source:, annotation:)
9
- @line = line
10
- @source = source
11
- @annotation = annotation
12
- end
13
-
14
- def ==(other)
15
- other.is_a?(LocatedAnnotation) &&
16
- other.line == line &&
17
- other.annotation == annotation
18
- end
19
- end
20
-
21
3
  attr_reader :path
22
4
  attr_reader :node
23
5
  attr_reader :mapping
24
6
 
7
+ extend NodeHelper
8
+
25
9
  def initialize(path:, node:, mapping:)
26
10
  @path = path
27
11
  @node = node
@@ -47,46 +31,61 @@ module Steep
47
31
 
48
32
  def self.parse(source_code, path:, factory:)
49
33
  buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code)
50
- node = new_parser().parse(buffer)
34
+ node, comments = new_parser().parse_with_comments(buffer)
51
35
 
36
+ # @type var annotations: Array[AST::Annotation::t]
52
37
  annotations = []
53
-
54
- _, comments, _ = yield_self do
55
- buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code)
56
- new_parser().tokenize(buffer)
57
- end
38
+ # @type var type_comments: Hash[Integer, type_comment]
39
+ type_comments = {}
58
40
 
59
41
  buffer = RBS::Buffer.new(name: path, content: source_code)
42
+ annotation_parser = AnnotationParser.new(factory: factory)
60
43
 
61
44
  comments.each do |comment|
62
- src = comment.text.gsub(/\A#\s*/, '')
63
- location = RBS::Location.new(buffer: buffer,
64
- start_pos: comment.location.expression.begin_pos + 1,
65
- end_pos: comment.location.expression.end_pos)
66
- annotation = AnnotationParser.new(factory: factory).parse(src, location: location)
67
- if annotation
68
- annotations << LocatedAnnotation.new(line: comment.location.line, source: src, annotation: annotation)
45
+ if comment.inline?
46
+ content = comment.text.delete_prefix('#')
47
+ content.lstrip!
48
+ prefix = comment.text.size - content.size
49
+ content.rstrip!
50
+ suffix = comment.text.size - content.size - prefix
51
+
52
+ location = RBS::Location.new(
53
+ buffer: buffer,
54
+ start_pos: comment.location.expression.begin_pos + prefix,
55
+ end_pos: comment.location.expression.end_pos - suffix
56
+ )
57
+
58
+ case
59
+ when annotation = annotation_parser.parse(content, location: location)
60
+ annotations << annotation
61
+ when assertion = AST::Node::TypeAssertion.parse(location)
62
+ type_comments[assertion.line] = assertion
63
+ when tapp = AST::Node::TypeApplication.parse(location)
64
+ type_comments[tapp.line] = tapp
65
+ end
69
66
  end
70
67
  end
71
68
 
72
- mapping = {}.compare_by_identity
69
+ map = {}
70
+ map.compare_by_identity
73
71
 
74
72
  if node
75
- construct_mapping(node: node, annotations: annotations, mapping: mapping)
73
+ node = insert_type_node(node, type_comments)
74
+ construct_mapping(node: node, annotations: annotations, mapping: map)
76
75
  end
77
76
 
78
77
  annotations.each do |annot|
79
- mapping[node] ||= []
80
- mapping[node] << annot
78
+ map[node] ||= []
79
+ map[node] << annot
81
80
  end
82
81
 
83
- new(path: path, node: node, mapping: mapping)
82
+ new(path: path, node: node, mapping: map)
84
83
  end
85
84
 
86
85
  def self.construct_mapping(node:, annotations:, mapping:, line_range: nil)
87
86
  case node.type
88
87
  when :if
89
- if node.loc.is_a?(::Parser::Source::Map::Ternary)
88
+ if node.loc.respond_to?(:question)
90
89
  # Skip ternary operator
91
90
  each_child_node node do |child|
92
91
  construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
@@ -200,7 +199,7 @@ module Steep
200
199
  last_cond = node.children[-2]
201
200
  body = node.children.last
202
201
 
203
- node.children.take(node.children.size-1) do |child|
202
+ node.children.take(node.children.size-1).each do |child|
204
203
  construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
205
204
  end
206
205
 
@@ -235,7 +234,7 @@ module Steep
235
234
  end
236
235
  end
237
236
 
238
- associated_annotations = annotations.select do |annot|
237
+ associated_annotations, other_annotations = annotations.partition do |annot|
239
238
  case node.type
240
239
  when :def, :module, :class, :block, :ensure, :defs
241
240
  loc = node.loc
@@ -257,33 +256,34 @@ module Steep
257
256
  associated_annotations.each do |annot|
258
257
  mapping[node] ||= []
259
258
  mapping[node] << annot
260
- annotations.delete annot
261
259
  end
262
- end
263
260
 
264
- def self.each_child_node(node)
265
- node.children.each do |child|
266
- if child.is_a?(::AST::Node)
267
- yield child
268
- end
269
- end
261
+ annotations.replace(other_annotations)
270
262
  end
271
263
 
272
- def self.map_child_nodes(node)
264
+ def self.map_child_node(node, type = nil, skip: nil)
273
265
  children = node.children.map do |child|
274
- if child.is_a?(::AST::Node)
275
- yield child
266
+ if child.is_a?(Parser::AST::Node)
267
+ if skip
268
+ if skip.member?(child)
269
+ child
270
+ else
271
+ yield child
272
+ end
273
+ else
274
+ yield child
275
+ end
276
276
  else
277
277
  child
278
278
  end
279
279
  end
280
280
 
281
- node.updated(nil, children)
281
+ node.updated(type, children)
282
282
  end
283
283
 
284
284
  def annotations(block:, factory:, context:)
285
285
  AST::Annotation::Collection.new(
286
- annotations: (mapping[block] || []).map(&:annotation),
286
+ annotations: (mapping[block] || []),
287
287
  factory: factory,
288
288
  context: context
289
289
  )
@@ -292,7 +292,7 @@ module Steep
292
292
  def each_annotation(&block)
293
293
  if block_given?
294
294
  mapping.each do |node, annots|
295
- yield node, annots.map(&:annotation)
295
+ yield [node, annots]
296
296
  end
297
297
  else
298
298
  enum_for :each_annotation
@@ -301,9 +301,11 @@ module Steep
301
301
 
302
302
  def each_heredoc_node(node = self.node, parents = [], &block)
303
303
  if block
304
+ return unless node
305
+
304
306
  case node.type
305
307
  when :dstr, :str
306
- if node.location.is_a?(Parser::Source::Map::Heredoc)
308
+ if node.location.respond_to?(:heredoc_body)
307
309
  yield [node, *parents]
308
310
  end
309
311
  end
@@ -344,7 +346,9 @@ module Steep
344
346
  parents.unshift node
345
347
 
346
348
  Source.each_child_node(node) do |child|
347
- ns = find_nodes_loc(child, position, parents) and return ns
349
+ if ns = find_nodes_loc(child, position, parents)
350
+ return ns
351
+ end
348
352
  end
349
353
 
350
354
  parents
@@ -359,12 +363,14 @@ module Steep
359
363
  node.location.expression.source_buffer.source_line(i+1).size + 1
360
364
  end + column
361
365
 
362
- if nodes = find_heredoc_nodes(line, column, position)
363
- Source.each_child_node(nodes[0]) do |child|
364
- find_nodes_loc(child, position, nodes) and break
366
+ if heredoc_nodes = find_heredoc_nodes(line, column, position)
367
+ Source.each_child_node(heredoc_nodes[0]) do |child|
368
+ if nodes = find_nodes_loc(child, position, heredoc_nodes)
369
+ return nodes
370
+ end
365
371
  end
366
372
 
367
- nodes
373
+ return heredoc_nodes
368
374
  else
369
375
  find_nodes_loc(node, position, [])
370
376
  end
@@ -385,7 +391,7 @@ module Steep
385
391
  delete_defs(node.children[0], allow_list)
386
392
  end
387
393
  else
388
- map_child_nodes(node) do |child|
394
+ map_child_node(node) do |child|
389
395
  delete_defs(child, allow_list)
390
396
  end
391
397
  end
@@ -398,7 +404,9 @@ module Steep
398
404
 
399
405
  node_ = Source.delete_defs(node, defs)
400
406
 
401
- mapping = {}.compare_by_identity
407
+ # @type var mapping: Hash[Parser::AST::Node, Array[AST::Annotation::t]]
408
+ mapping = {}
409
+ mapping.compare_by_identity
402
410
 
403
411
  annotations = self.mapping.values.flatten
404
412
  Source.construct_mapping(node: node_, annotations: annotations, mapping: mapping)
@@ -414,19 +422,129 @@ module Steep
414
422
  end
415
423
  end
416
424
 
417
- def compact_siblings(node)
418
- case node
419
- when :def
420
- node.updated(:nil, [])
421
- when :defs
422
- node.children[0]
423
- when :class
424
- node.updated(:class, [node.children[0], node.children[1], nil])
425
- when :module
426
- node.updated(:module, [node.children[0], nil])
425
+ def self.insert_type_node(node, comments)
426
+ if node.location.expression
427
+ first_line = node.location.expression.first_line
428
+ last_line = node.location.expression.last_line
429
+ last_comment = comments[last_line]
430
+
431
+ if (first_line..last_line).none? {|l| comments.key?(l) }
432
+ return node
433
+ end
434
+
435
+ case
436
+ when last_comment.is_a?(AST::Node::TypeAssertion)
437
+ case node.type
438
+ when :lvasgn, :ivasgn, :gvasgn, :cvasgn, :casgn
439
+ # Skip
440
+ when :masgn
441
+ lhs, rhs = node.children
442
+ node = node.updated(nil, [lhs, insert_type_node(rhs, comments)])
443
+ return adjust_location(node)
444
+ when :return, :break, :next
445
+ # Skip
446
+ when :begin
447
+ if node.loc.begin
448
+ # paren
449
+ child_assertions = comments.except(last_line)
450
+ node = map_child_node(node) {|child| insert_type_node(child, child_assertions) }
451
+ node = adjust_location(node)
452
+ return assertion_node(node, last_comment)
453
+ end
454
+ else
455
+ child_assertions = comments.except(last_line)
456
+ node = map_child_node(node) {|child| insert_type_node(child, child_assertions) }
457
+ node = adjust_location(node)
458
+ return assertion_node(node, last_comment)
459
+ end
460
+ when selector_line = sendish_node?(node)
461
+ if (comment = comments[selector_line]).is_a?(AST::Node::TypeApplication)
462
+ child_assertions = comments.except(selector_line)
463
+ case node.type
464
+ when :block
465
+ send, *children = node.children
466
+ node = node.updated(
467
+ nil,
468
+ [
469
+ map_child_node(send) {|child| insert_type_node(child, child_assertions) },
470
+ *children.map {|child| insert_type_node(child, child_assertions) }
471
+ ]
472
+ )
473
+ when :numblock
474
+ send, size, body = node.children
475
+ node = node.updated(
476
+ nil,
477
+ [
478
+ map_child_node(send) {|child| insert_type_node(child, child_assertions) },
479
+ size,
480
+ insert_type_node(body, child_assertions)
481
+ ]
482
+ )
483
+ else
484
+ node = map_child_node(node) {|child| insert_type_node(child, child_assertions) }
485
+ end
486
+ node = adjust_location(node)
487
+ return type_application_node(node, comment)
488
+ end
489
+ end
490
+ end
491
+
492
+ adjust_location(
493
+ map_child_node(node, nil) {|child| insert_type_node(child, comments) }
494
+ )
495
+ end
496
+
497
+ def self.sendish_node?(node)
498
+ send_node =
499
+ case node.type
500
+ when :send, :csend
501
+ node
502
+ when :block, :numblock
503
+ send = node.children[0]
504
+ case send.type
505
+ when :send, :csend
506
+ send
507
+ end
508
+ end
509
+
510
+ if send_node
511
+ if send_node.location.dot
512
+ send_node.location.selector.line
513
+ end
514
+ end
515
+ end
516
+
517
+ def self.adjust_location(node)
518
+ if end_pos = node.location.expression&.end_pos
519
+ if last_pos = each_child_node(node).map {|node| node.location.expression&.end_pos }.compact.max
520
+ if last_pos > end_pos
521
+ props = { location: node.location.with_expression(node.location.expression.with(end_pos: last_pos)) }
522
+ end
523
+ end
524
+ end
525
+
526
+ if props
527
+ node.updated(nil, nil, props)
427
528
  else
428
529
  node
429
530
  end
430
531
  end
532
+
533
+ def self.assertion_node(node, type)
534
+ map = Parser::Source::Map.new(node.location.expression.with(end_pos: type.location.end_pos))
535
+ Parser::AST::Node.new(:assertion, [node, type], { location: map })
536
+ end
537
+
538
+ def self.type_application_node(node, tapp)
539
+ if node.location.expression.end_pos > tapp.location.end_pos
540
+ map = Parser::Source::Map.new(node.location.expression)
541
+ else
542
+ map = Parser::Source::Map.new(node.location.expression.with(end_pos: tapp.location.end_pos))
543
+ end
544
+
545
+ node = Parser::AST::Node.new(:tapp, [node, tapp], { location: map })
546
+ tapp.set_node(node)
547
+ node
548
+ end
431
549
  end
432
550
  end