steep 1.2.1 → 1.3.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -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/bin/steep-prof +1 -1
  8. data/lib/steep/annotation_parser.rb +34 -28
  9. data/lib/steep/ast/annotation.rb +16 -5
  10. data/lib/steep/ast/node/type_application.rb +74 -0
  11. data/lib/steep/ast/node/type_assertion.rb +56 -0
  12. data/lib/steep/ast/types/factory.rb +5 -1
  13. data/lib/steep/ast/types/helper.rb +4 -3
  14. data/lib/steep/ast/types/logic.rb +4 -0
  15. data/lib/steep/diagnostic/helper.rb +2 -1
  16. data/lib/steep/diagnostic/lsp_formatter.rb +3 -1
  17. data/lib/steep/diagnostic/ruby.rb +70 -5
  18. data/lib/steep/diagnostic/signature.rb +21 -8
  19. data/lib/steep/drivers/check.rb +2 -2
  20. data/lib/steep/drivers/checkfile.rb +2 -2
  21. data/lib/steep/drivers/langserver.rb +2 -2
  22. data/lib/steep/drivers/stats.rb +2 -2
  23. data/lib/steep/drivers/utils/jobs_option.rb +0 -4
  24. data/lib/steep/drivers/watch.rb +1 -1
  25. data/lib/steep/drivers/worker.rb +0 -1
  26. data/lib/steep/server/lsp_formatter.rb +13 -3
  27. data/lib/steep/server/master.rb +4 -1
  28. data/lib/steep/server/worker_process.rb +91 -14
  29. data/lib/steep/services/completion_provider.rb +2 -1
  30. data/lib/steep/services/goto_service.rb +2 -1
  31. data/lib/steep/services/hover_provider/rbs.rb +7 -7
  32. data/lib/steep/services/hover_provider/ruby.rb +21 -5
  33. data/lib/steep/services/signature_service.rb +23 -4
  34. data/lib/steep/services/type_check_service.rb +4 -4
  35. data/lib/steep/signature/validator.rb +36 -13
  36. data/lib/steep/source.rb +189 -71
  37. data/lib/steep/type_construction.rb +246 -135
  38. data/lib/steep/type_inference/logic_type_interpreter.rb +3 -1
  39. data/lib/steep/version.rb +1 -1
  40. data/lib/steep.rb +2 -0
  41. data/rbs_collection.steep.lock.yaml +27 -10
  42. data/rbs_collection.steep.yaml +0 -1
  43. data/sig/shims/exception.rbs +4 -0
  44. data/sig/shims/parser/comment.rbs +33 -0
  45. data/sig/shims/parser.rbs +30 -2
  46. data/sig/steep/annotation_parser.rbs +59 -0
  47. data/sig/steep/ast/annotation.rbs +21 -26
  48. data/sig/steep/ast/node/type_application.rbs +31 -0
  49. data/sig/steep/ast/node/type_assertion.rbs +26 -0
  50. data/sig/steep/ast/types/any.rbs +1 -1
  51. data/sig/steep/ast/types/boolean.rbs +1 -1
  52. data/sig/steep/ast/types/bot.rbs +1 -1
  53. data/sig/steep/ast/types/class.rbs +1 -1
  54. data/sig/steep/ast/types/factory.rbs +0 -2
  55. data/sig/steep/ast/types/helper.rbs +6 -3
  56. data/sig/steep/ast/types/instance.rbs +1 -1
  57. data/sig/steep/ast/types/intersection.rbs +1 -1
  58. data/sig/steep/ast/types/logic.rbs +2 -0
  59. data/sig/steep/ast/types/name.rbs +2 -2
  60. data/sig/steep/ast/types/nil.rbs +1 -1
  61. data/sig/steep/ast/types/record.rbs +1 -1
  62. data/sig/steep/ast/types/self.rbs +1 -1
  63. data/sig/steep/ast/types/top.rbs +2 -2
  64. data/sig/steep/ast/types/tuple.rbs +1 -1
  65. data/sig/steep/ast/types/union.rbs +1 -1
  66. data/sig/steep/ast/types/var.rbs +2 -2
  67. data/sig/steep/ast/types/void.rbs +1 -1
  68. data/sig/steep/diagnostic/helper.rbs +9 -3
  69. data/sig/steep/diagnostic/lsp_formatter.rbs +12 -8
  70. data/sig/steep/diagnostic/ruby.rbs +62 -8
  71. data/sig/steep/diagnostic/signature.rbs +118 -85
  72. data/sig/steep/drivers/utils/jobs_option.rbs +0 -2
  73. data/sig/steep/drivers/worker.rbs +11 -13
  74. data/sig/steep/range_extension.rbs +7 -0
  75. data/sig/steep/server/lsp_formatter.rbs +14 -7
  76. data/sig/steep/server/worker_process.rbs +74 -12
  77. data/sig/steep/services/hover_provider/rbs.rbs +27 -7
  78. data/sig/steep/services/hover_provider/ruby.rbs +18 -4
  79. data/sig/steep/services/hover_provider/singleton_methods.rbs +1 -1
  80. data/sig/steep/services/signature_service.rbs +14 -0
  81. data/sig/steep/services/type_check_service.rbs +2 -2
  82. data/sig/steep/signature/validator.rbs +76 -0
  83. data/sig/steep/source.rbs +54 -30
  84. data/sig/steep/type_construction.rbs +85 -27
  85. data/sig/steep/type_inference/method_call.rbs +1 -1
  86. data/sig/steep.rbs +2 -0
  87. data/smoke/diagnostics-rbs/inherit-module.rbs +2 -0
  88. data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
  89. data/steep.gemspec +1 -1
  90. metadata +16 -6
@@ -20,7 +20,7 @@ module Steep
20
20
  end
21
21
 
22
22
  def each_error(&block)
23
- if block_given?
23
+ if block
24
24
  @errors.each(&block)
25
25
  else
26
26
  enum_for :each_error
@@ -64,6 +64,8 @@ module Steep
64
64
  )
65
65
 
66
66
  type_params.zip(type_args).each do |param, arg|
67
+ arg or raise
68
+
67
69
  if param.upper_bound
68
70
  upper_bound_type = factory.type(param.upper_bound).subst(subst)
69
71
  arg_type = factory.type(arg)
@@ -121,7 +123,7 @@ module Steep
121
123
 
122
124
  if name && type_params && type_args
123
125
  if !type_params.empty? && !type_args.empty?
124
- validate_type_application_constraints(type.name, type_params, type_args, location: type.location)
126
+ validate_type_application_constraints(name, type_params, type_args, location: type.location)
125
127
  end
126
128
  end
127
129
 
@@ -156,19 +158,21 @@ module Steep
156
158
  end
157
159
 
158
160
  def mixin_constraints(definition, mixin_ancestors, immediate_self_types:)
161
+ # @type var relations: Array[[Subtyping::Relation[AST::Types::t], RBS::Definition::Ancestor::Instance]]
159
162
  relations = []
160
163
 
161
164
  self_type = checker.factory.type(definition.self_type)
162
165
  if immediate_self_types && !immediate_self_types.empty?
163
- self_type = AST::Types::Intersection.build(
164
- types: immediate_self_types.map {|st| ancestor_to_type(st) }.push(self_type),
165
- location: nil
166
- )
166
+ # @type var sts: Array[AST::Types::t]
167
+ sts = immediate_self_types.map {|st| ancestor_to_type(st) }
168
+ self_type = AST::Types::Intersection.build(types: sts.push(self_type), location: nil)
167
169
  end
168
170
 
169
171
  mixin_ancestors.each do |ancestor|
170
172
  args = ancestor.args.map {|type| checker.factory.type(type) }
171
173
  ancestor_ancestors = builder.ancestor_builder.one_instance_ancestors(ancestor.name)
174
+ ancestor_ancestors.self_types or raise
175
+ ancestor_ancestors.params or raise
172
176
  self_constraints = ancestor_ancestors.self_types.map do |self_ancestor|
173
177
  s = Interface::Substitution.build(ancestor_ancestors.params, args)
174
178
  ancestor_to_type(self_ancestor).subst(s)
@@ -263,7 +267,7 @@ module Steep
263
267
  end
264
268
 
265
269
  ancestors = builder.ancestor_builder.one_instance_ancestors(name)
266
- mixin_constraints(definition, ancestors.included_modules, immediate_self_types: ancestors.self_types).each do |relation, ancestor|
270
+ mixin_constraints(definition, ancestors.included_modules || raise, immediate_self_types: ancestors.self_types).each do |relation, ancestor|
267
271
  checker.check(
268
272
  relation,
269
273
  self_type: AST::Types::Self.new,
@@ -271,6 +275,8 @@ module Steep
271
275
  class_type: AST::Types::Class.new,
272
276
  constraints: Subtyping::Constraints.empty
273
277
  ).else do
278
+ raise if ancestor.source.is_a?(Symbol)
279
+
274
280
  @errors << Diagnostic::Signature::ModuleSelfTypeError.new(
275
281
  name: name,
276
282
  location: ancestor.source&.location || raise,
@@ -292,6 +298,14 @@ module Steep
292
298
  end
293
299
 
294
300
  builder.build_singleton(name).tap do |definition|
301
+ entry =
302
+ case definition.entry
303
+ when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
304
+ definition.entry
305
+ else
306
+ raise
307
+ end
308
+
295
309
  definition.instance_variables.each do |name, var|
296
310
  if parent = var.parent_variable
297
311
  var_type = checker.factory.type(var.type)
@@ -327,7 +341,7 @@ module Steep
327
341
  definition.class_variables.each do |name, var|
328
342
  if var.declared_in == definition.type_name
329
343
  if (parent = var.parent_variable) && var.declared_in != parent.declared_in
330
- class_var = definition.entry.decls.flat_map {|decl| decl.decl.members }.find do |member|
344
+ class_var = entry.decls.flat_map {|decl| decl.decl.members }.find do |member|
331
345
  member.is_a?(RBS::AST::Members::ClassVariable) && member.name == name
332
346
  end
333
347
 
@@ -336,7 +350,7 @@ module Steep
336
350
  class_name: definition.type_name,
337
351
  other_class_name: parent.declared_in,
338
352
  variable_name: name,
339
- location: class_var.location[:name]
353
+ location: class_var.location&.[](:name)
340
354
  )
341
355
  end
342
356
  end
@@ -344,6 +358,7 @@ module Steep
344
358
  end
345
359
 
346
360
  ancestors = builder.ancestor_builder.one_singleton_ancestors(name)
361
+ ancestors.extended_modules or raise
347
362
  mixin_constraints(definition, ancestors.extended_modules, immediate_self_types: ancestors.self_types).each do |relation, ancestor|
348
363
  checker.check(
349
364
  relation,
@@ -352,6 +367,8 @@ module Steep
352
367
  class_type: AST::Types::Class.new,
353
368
  constraints: Subtyping::Constraints.empty
354
369
  ).else do
370
+ raise if ancestor.source.is_a?(Symbol)
371
+
355
372
  @errors << Diagnostic::Signature::ModuleSelfTypeError.new(
356
373
  name: name,
357
374
  location: ancestor.source&.location || raise,
@@ -381,19 +398,23 @@ module Steep
381
398
  builder.build_instance(ancestor.name)
382
399
  when ancestor.name.interface?
383
400
  builder.build_interface(ancestor.name)
401
+ else
402
+ raise
384
403
  end
385
404
 
386
405
  location =
387
- if ancestor.source == :super
406
+ case ancestor.source
407
+ when :super
388
408
  primary_decl = env.class_decls[name].primary.decl
409
+ primary_decl.is_a?(RBS::AST::Declarations::Class) or raise
389
410
  if super_class = primary_decl.super_class
390
411
  super_class.location
391
412
  else
392
413
  # Implicit super class (Object): this can be skipped in fact...
393
- primary_decl.location[:name]
414
+ primary_decl.location&.aref(:name)
394
415
  end
395
416
  else
396
- ancestor.source.location
417
+ ancestor.source&.location
397
418
  end
398
419
 
399
420
  validate_type_application_constraints(
@@ -423,12 +444,14 @@ module Steep
423
444
  case ancestor
424
445
  when RBS::Definition::Ancestor::Instance
425
446
  # Interface ancestor cannot be other than Interface
447
+ ancestor.source.is_a?(Symbol) and raise
448
+
426
449
  defn = builder.build_interface(ancestor.name)
427
450
  validate_type_application_constraints(
428
451
  ancestor.name,
429
452
  defn.type_params_decl,
430
453
  ancestor.args,
431
- location: ancestor.source.location || raise
454
+ location: ancestor.source&.location || raise
432
455
  )
433
456
  end
434
457
  end
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