parser 2.7.1.3 → 2.7.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1018,11 +1018,15 @@ rule
1018
1018
  result = @builder.block(val[0],
1019
1019
  begin_t, args, body, end_t)
1020
1020
  }
1021
- | tLAMBDA lambda
1021
+ | tLAMBDA
1022
+ {
1023
+ @context.push(:lambda)
1024
+ }
1025
+ lambda
1022
1026
  {
1023
1027
  lambda_call = @builder.call_lambda(val[0])
1024
1028
 
1025
- args, (begin_t, body, end_t) = val[1]
1029
+ args, (begin_t, body, end_t) = val[2]
1026
1030
  result = @builder.block(lambda_call,
1027
1031
  begin_t, args, body, end_t)
1028
1032
  }
@@ -1136,6 +1140,7 @@ rule
1136
1140
  {
1137
1141
  @static_env.extend_static
1138
1142
  @lexer.push_cmdarg
1143
+ @context.push(:module)
1139
1144
  }
1140
1145
  bodystmt kEND
1141
1146
  {
@@ -1148,6 +1153,7 @@ rule
1148
1153
 
1149
1154
  @lexer.pop_cmdarg
1150
1155
  @static_env.unextend
1156
+ @context.pop
1151
1157
  }
1152
1158
  | kDEF fname
1153
1159
  {
@@ -1429,9 +1435,13 @@ rule
1429
1435
  lambda: {
1430
1436
  @static_env.extend_dynamic
1431
1437
  }
1432
- f_larglist lambda_body
1438
+ f_larglist
1439
+ {
1440
+ @context.pop
1441
+ }
1442
+ lambda_body
1433
1443
  {
1434
- result = [ val[1], val[2] ]
1444
+ result = [ val[1], val[3] ]
1435
1445
 
1436
1446
  @static_env.unextend
1437
1447
  }
@@ -37,7 +37,7 @@ module Parser
37
37
 
38
38
  private
39
39
 
40
- LEGACY_MODES = %i[lambda procarg0 encoding index arg_inside_procarg0].freeze
40
+ LEGACY_MODES = %i[lambda procarg0 encoding index arg_inside_procarg0 forward_arg].freeze
41
41
 
42
42
  def runner_name
43
43
  raise NotImplementedError, "implement #{self.class}##{__callee__}"
@@ -13,7 +13,7 @@ module Parser
13
13
  # ^^
14
14
  #
15
15
  # @!attribute [r] source_buffer
16
- # @return [Parser::Diagnostic::Engine]
16
+ # @return [Parser::Source::Buffer]
17
17
  #
18
18
  # @!attribute [r] begin_pos
19
19
  # @return [Integer] index of the first character in the range
@@ -129,6 +129,8 @@ module Parser
129
129
  ##
130
130
  # Merges the updates of argument with the receiver.
131
131
  # Policies of the receiver are used.
132
+ # This action is atomic in that it won't change the receiver
133
+ # unless it succeeds.
132
134
  #
133
135
  # @param [Rewriter] with
134
136
  # @return [Rewriter] self
@@ -154,6 +156,32 @@ module Parser
154
156
  dup.merge!(with)
155
157
  end
156
158
 
159
+ ##
160
+ # For special cases where one needs to merge a rewriter attached to a different source_buffer
161
+ # or that needs to be offset. Policies of the receiver are used.
162
+ #
163
+ # @param [TreeRewriter] rewriter from different source_buffer
164
+ # @param [Integer] offset
165
+ # @return [Rewriter] self
166
+ # @raise [IndexError] if action ranges (once offset) don't fit the current buffer
167
+ #
168
+ def import!(foreign_rewriter, offset: 0)
169
+ return self if foreign_rewriter.empty?
170
+
171
+ contracted = foreign_rewriter.action_root.contract
172
+ merge_effective_range = ::Parser::Source::Range.new(
173
+ @source_buffer,
174
+ contracted.range.begin_pos + offset,
175
+ contracted.range.end_pos + offset,
176
+ )
177
+ check_range_validity(merge_effective_range)
178
+
179
+ merge_with = contracted.moved(@source_buffer, offset)
180
+
181
+ @action_root = @action_root.combine(merge_with)
182
+ self
183
+ end
184
+
157
185
  ##
158
186
  # Replaces the code of the source range `range` with `content`.
159
187
  #
@@ -234,6 +262,44 @@ module Parser
234
262
  chunks.join
235
263
  end
236
264
 
265
+ ##
266
+ # Returns a representation of the rewriter as an ordered list of replacements.
267
+ #
268
+ # rewriter.as_replacements # => [ [1...1, '('],
269
+ # [2...4, 'foo'],
270
+ # [5...6, ''],
271
+ # [6...6, '!'],
272
+ # [10...10, ')'],
273
+ # ]
274
+ #
275
+ # This representation is sufficient to recreate the result of `process` but it is
276
+ # not sufficient to recreate completely the rewriter for further merging/actions.
277
+ # See `as_nested_actions`
278
+ #
279
+ # @return [Array<Range, String>] an ordered list of pairs of range & replacement
280
+ #
281
+ def as_replacements
282
+ @action_root.ordered_replacements
283
+ end
284
+
285
+ ##
286
+ # Returns a representation of the rewriter as nested insertions (:wrap) and replacements.
287
+ #
288
+ # rewriter.as_actions # =>[ [:wrap, 1...10, '(', ')'],
289
+ # [:wrap, 2...6, '', '!'], # aka "insert_after"
290
+ # [:replace, 2...4, 'foo'],
291
+ # [:replace, 5...6, ''], # aka "removal"
292
+ # ],
293
+ #
294
+ # Contrary to `as_replacements`, this representation is sufficient to recreate exactly
295
+ # the rewriter.
296
+ #
297
+ # @return [Array<(Symbol, Range, String{, String})>]
298
+ #
299
+ def as_nested_actions
300
+ @action_root.nested_actions
301
+ end
302
+
237
303
  ##
238
304
  # Provides a protected block where a sequence of multiple rewrite actions
239
305
  # are handled atomically. If any of the actions failed by clobbering,
@@ -310,7 +376,7 @@ module Parser
310
376
 
311
377
  def check_range_validity(range)
312
378
  if range.begin_pos < 0 || range.end_pos > @source_buffer.source.size
313
- raise IndexError, "The range #{range} is outside the bounds of the source"
379
+ raise IndexError, "The range #{range.to_range} is outside the bounds of the source"
314
380
  end
315
381
  range
316
382
  end
@@ -46,10 +46,49 @@ module Parser
46
46
  reps
47
47
  end
48
48
 
49
+ def nested_actions
50
+ actions = []
51
+ actions << [:wrap, @range, @insert_before, @insert_after] if !@insert_before.empty? ||
52
+ !@insert_after.empty?
53
+ actions << [:replace, @range, @replacement] if @replacement
54
+ actions.concat(@children.flat_map(&:nested_actions))
55
+ end
56
+
49
57
  def insertion?
50
58
  !insert_before.empty? || !insert_after.empty? || (replacement && !replacement.empty?)
51
59
  end
52
60
 
61
+ ##
62
+ # A root action has its range set to the whole source range, even
63
+ # though it typically do not act on that range.
64
+ # This method returns the action as if it was a child action with
65
+ # its range contracted.
66
+ # @return [Action]
67
+ def contract
68
+ raise 'Empty actions can not be contracted' if empty?
69
+ return self if insertion?
70
+ range = @range.with(
71
+ begin_pos: children.first.range.begin_pos,
72
+ end_pos: children.last.range.end_pos,
73
+ )
74
+ with(range: range)
75
+ end
76
+
77
+ ##
78
+ # @return [Action] that has been moved to the given source_buffer and with the given offset
79
+ # No check is done on validity of resulting range.
80
+ def moved(source_buffer, offset)
81
+ moved_range = ::Parser::Source::Range.new(
82
+ source_buffer,
83
+ @range.begin_pos + offset,
84
+ @range.end_pos + offset
85
+ )
86
+ with(
87
+ range: moved_range,
88
+ children: children.map { |child| child.moved(source_buffer, offset) }
89
+ )
90
+ end
91
+
53
92
  protected
54
93
 
55
94
  attr_reader :children
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parser
4
- VERSION = '2.7.1.3'
4
+ VERSION = '2.7.1.4'
5
5
  end
@@ -42,7 +42,7 @@ Gem::Specification.new do |spec|
42
42
 
43
43
  spec.required_ruby_version = '>= 2.0.0'
44
44
 
45
- spec.add_dependency 'ast', '~> 2.4.0'
45
+ spec.add_dependency 'ast', '~> 2.4.1'
46
46
 
47
47
  spec.add_development_dependency 'bundler', '>= 1.15', '< 3.0.0'
48
48
  spec.add_development_dependency 'rake', '~> 13.0.1'
@@ -77,3 +77,27 @@ class Parser::AST::Node
77
77
  super
78
78
  end
79
79
  end
80
+
81
+ # Special test extension that records a context of the parser
82
+ # for any node that is created
83
+ module NodeContextExt
84
+ module NodeExt
85
+ attr_reader :context
86
+
87
+ def assign_properties(properties)
88
+ super
89
+
90
+ if (context = properties[:context])
91
+ @context = context
92
+ end
93
+ end
94
+ end
95
+ Parser::AST::Node.prepend(NodeExt)
96
+
97
+ module BuilderExt
98
+ def n(type, children, source_map)
99
+ super.updated(nil, nil, context: @parser.context.stack.dup)
100
+ end
101
+ end
102
+ Parser::Builders::Default.prepend(BuilderExt)
103
+ end
@@ -241,13 +241,13 @@ module ParseHelper
241
241
  with_versions(versions) do |version, parser|
242
242
  source_file = Parser::Source::Buffer.new('(assert_context)', source: code)
243
243
 
244
- begin
245
- parser.parse(source_file)
246
- rescue Parser::SyntaxError
247
- # do nothing; the diagnostic was reported
248
- end
244
+ parsed_ast = parser.parse(source_file)
249
245
 
250
- assert_equal parser.context.stack, context, "(#{version}) parsing context"
246
+ nodes = find_matching_nodes(parsed_ast) { |node| node.type == :send && node.children[1] == :get_context }
247
+ assert_equal 1, nodes.count, "there must exactly 1 `get_context()` call"
248
+
249
+ node = nodes.first
250
+ assert_equal context, node.context, "(#{version}) expect parsing context to match"
251
251
  end
252
252
  end
253
253
 
@@ -310,4 +310,14 @@ module ParseHelper
310
310
  matching_children[index]
311
311
  end
312
312
  end
313
+
314
+ def find_matching_nodes(ast, &block)
315
+ return [] unless ast.is_a?(AST::Node)
316
+
317
+ result = []
318
+ result << ast if block.call(ast)
319
+ ast.children.each { |child| result += find_matching_nodes(child, &block) }
320
+
321
+ result
322
+ end
313
323
  end
@@ -6551,39 +6551,64 @@ class TestParser < Minitest::Test
6551
6551
 
6552
6552
  def test_context_class
6553
6553
  [
6554
- %q{class A;},
6555
- %q{class A < B;}
6554
+ %q{class A; get_context; end},
6555
+ %q{class A < B; get_context; end}
6556
6556
  ].each do |code|
6557
6557
  assert_context([:class], code, ALL_VERSIONS)
6558
6558
  end
6559
6559
  end
6560
6560
 
6561
+ def test_context_module
6562
+ assert_context(
6563
+ [:module],
6564
+ %q{module M; get_context; end},
6565
+ ALL_VERSIONS)
6566
+ end
6567
+
6561
6568
  def test_context_sclass
6562
6569
  assert_context(
6563
6570
  [:sclass],
6564
- %q{class << foo;},
6571
+ %q{class << foo; get_context; end},
6565
6572
  ALL_VERSIONS)
6566
6573
  end
6567
6574
 
6568
6575
  def test_context_def
6569
- assert_context(
6570
- [:def],
6571
- %q{def m;},
6572
- ALL_VERSIONS)
6576
+ [
6577
+ %q{def m; get_context; end},
6578
+ %q{def m(a = get_context); end}
6579
+ ].each do |code|
6580
+ assert_context([:def], code, ALL_VERSIONS)
6581
+ end
6582
+
6583
+ [
6584
+ %q{def m() = get_context},
6585
+ %q{def m(a = get_context) = 42}
6586
+ ].each do |code|
6587
+ assert_context([:def], code, SINCE_2_8)
6588
+ end
6573
6589
  end
6574
6590
 
6575
6591
  def test_context_defs
6576
- assert_context(
6577
- [:defs],
6578
- %q{def foo.m;},
6579
- ALL_VERSIONS)
6592
+ [
6593
+ %q{def foo.m; get_context; end},
6594
+ %q{def foo.m(a = get_context); end}
6595
+ ].each do |code|
6596
+ assert_context([:defs], code, ALL_VERSIONS)
6597
+ end
6598
+
6599
+ [
6600
+ %q{def foo.m() = get_context},
6601
+ %q{def foo.m(a = get_context) = 42}
6602
+ ].each do |code|
6603
+ assert_context([:defs], code, SINCE_2_8)
6604
+ end
6580
6605
  end
6581
6606
 
6582
6607
  def test_context_cmd_brace_block
6583
6608
  [
6584
- 'tap foo {',
6585
- 'foo.tap foo {',
6586
- 'foo::tap foo {'
6609
+ 'tap foo { get_context }',
6610
+ 'foo.tap foo { get_context }',
6611
+ 'foo::tap foo { get_context }'
6587
6612
  ].each do |code|
6588
6613
  assert_context([:block], code, ALL_VERSIONS)
6589
6614
  end
@@ -6591,12 +6616,12 @@ class TestParser < Minitest::Test
6591
6616
 
6592
6617
  def test_context_brace_block
6593
6618
  [
6594
- 'tap {',
6595
- 'foo.tap {',
6596
- 'foo::tap {',
6597
- 'tap do',
6598
- 'foo.tap do',
6599
- 'foo::tap do'
6619
+ 'tap { get_context }',
6620
+ 'foo.tap { get_context }',
6621
+ 'foo::tap { get_context }',
6622
+ 'tap do get_context end',
6623
+ 'foo.tap do get_context end',
6624
+ 'foo::tap do get_context end'
6600
6625
  ].each do |code|
6601
6626
  assert_context([:block], code, ALL_VERSIONS)
6602
6627
  end
@@ -6604,9 +6629,9 @@ class TestParser < Minitest::Test
6604
6629
 
6605
6630
  def test_context_do_block
6606
6631
  [
6607
- %q{tap 1 do},
6608
- %q{foo.tap do},
6609
- %q{foo::tap do}
6632
+ %q{tap 1 do get_context end},
6633
+ %q{foo.tap do get_context end},
6634
+ %q{foo::tap do get_context end}
6610
6635
  ].each do |code|
6611
6636
  assert_context([:block], code, ALL_VERSIONS)
6612
6637
  end
@@ -6614,8 +6639,12 @@ class TestParser < Minitest::Test
6614
6639
 
6615
6640
  def test_context_lambda
6616
6641
  [
6617
- '->() {',
6618
- '->() do'
6642
+ '->() { get_context }',
6643
+ '->() do get_context end',
6644
+ '-> { get_context }',
6645
+ '-> do get_context end',
6646
+ '->(a = get_context) {}',
6647
+ '->(a = get_context) do end'
6619
6648
  ].each do |code|
6620
6649
  assert_context([:lambda], code, SINCE_1_9)
6621
6650
  end
@@ -6623,28 +6652,61 @@ class TestParser < Minitest::Test
6623
6652
 
6624
6653
  def test_context_nested
6625
6654
  assert_context(
6626
- [:class, :sclass, :defs, :def, :block],
6627
- %q{class A; class << foo; def bar.m; def m; tap do},
6655
+ [:class, :module, :sclass, :defs, :def, :block],
6656
+ %q{
6657
+ class A
6658
+ module M
6659
+ class << foo
6660
+ def bar.m
6661
+ def m
6662
+ tap do
6663
+ get_context
6664
+ end
6665
+ end
6666
+ end
6667
+ end
6668
+ end
6669
+ end
6670
+ },
6628
6671
  ALL_VERSIONS)
6629
6672
 
6630
6673
  assert_context(
6631
- [:class, :sclass, :defs, :def, :lambda, :block],
6632
- %q{class A; class << foo; def bar.m; def m; -> do; tap do},
6674
+ [:class, :module, :sclass, :defs, :def, :lambda, :block],
6675
+ %q{
6676
+ class A
6677
+ module M
6678
+ class << foo
6679
+ def bar.m
6680
+ def m
6681
+ -> do
6682
+ tap do
6683
+ get_context
6684
+ end
6685
+ end
6686
+ end
6687
+ end
6688
+ end
6689
+ end
6690
+ end
6691
+ },
6633
6692
  SINCE_1_9)
6634
6693
 
6635
6694
  assert_context(
6636
6695
  [],
6637
6696
  %q{
6638
6697
  class A
6639
- class << foo
6640
- def bar.m
6641
- def m
6642
- tap do
6698
+ module M
6699
+ class << foo
6700
+ def bar.m
6701
+ def m
6702
+ tap do
6703
+ end
6643
6704
  end
6644
6705
  end
6645
6706
  end
6646
6707
  end
6647
6708
  end
6709
+ get_context
6648
6710
  },
6649
6711
  ALL_VERSIONS)
6650
6712
 
@@ -6652,17 +6714,20 @@ class TestParser < Minitest::Test
6652
6714
  [],
6653
6715
  %q{
6654
6716
  class A
6655
- class << foo
6656
- def bar.m
6657
- def m
6658
- -> do
6659
- tap do
6717
+ module M
6718
+ class << foo
6719
+ def bar.m
6720
+ def m
6721
+ -> do
6722
+ tap do
6723
+ end
6660
6724
  end
6661
6725
  end
6662
6726
  end
6663
6727
  end
6664
6728
  end
6665
6729
  end
6730
+ get_context
6666
6731
  },
6667
6732
  SINCE_1_9)
6668
6733
  end
@@ -7746,7 +7811,8 @@ class TestParser < Minitest::Test
7746
7811
  end
7747
7812
  end
7748
7813
 
7749
- def test_forward_args
7814
+ def test_forward_args_legacy
7815
+ Parser::Builders::Default.emit_forward_arg = false
7750
7816
  assert_parses(
7751
7817
  s(:def, :foo,
7752
7818
  s(:forward_args),
@@ -7778,7 +7844,27 @@ class TestParser < Minitest::Test
7778
7844
  %q{def foo(...); end},
7779
7845
  %q{},
7780
7846
  SINCE_2_7)
7847
+ ensure
7848
+ Parser::Builders::Default.emit_forward_arg = true
7849
+ end
7850
+
7851
+ def test_forward_arg
7852
+ assert_parses(
7853
+ s(:def, :foo,
7854
+ s(:args,
7855
+ s(:forward_arg)),
7856
+ s(:send, nil, :bar,
7857
+ s(:forwarded_args))),
7858
+ %q{def foo(...); bar(...); end},
7859
+ %q{ ~ begin (args)
7860
+ | ~~~~~ expression (args)
7861
+ | ~ end (args)
7862
+ | ~~~ expression (args.forward_arg)
7863
+ | ~~~ expression (send.forwarded_args)},
7864
+ SINCE_2_7)
7865
+ end
7781
7866
 
7867
+ def test_forward_args_invalid
7782
7868
  assert_diagnoses(
7783
7869
  [:error, :block_and_blockarg],
7784
7870
  %q{def foo(...) bar(...) { }; end},
@@ -7804,6 +7890,12 @@ class TestParser < Minitest::Test
7804
7890
  %q{ ^^^ location},
7805
7891
  SINCE_2_7)
7806
7892
 
7893
+ assert_diagnoses(
7894
+ [:error, :unexpected_token, { :token => 'tBDOT3' }],
7895
+ %q{def foo(x,y,z); bar(x, y, z, ...); end},
7896
+ %q{ ^^^ location},
7897
+ SINCE_2_8)
7898
+
7807
7899
  assert_diagnoses(
7808
7900
  [:error, :unexpected_token, { :token => 'tBDOT3' }],
7809
7901
  %q{def foo(x,y,z); super(...); end},
@@ -7820,7 +7912,13 @@ class TestParser < Minitest::Test
7820
7912
  [:error, :unexpected_token, { :token => 'tBDOT3' }],
7821
7913
  %q{->(...) {}},
7822
7914
  %q{ ^^^ location},
7823
- SINCE_2_7)
7915
+ ['2.7'])
7916
+
7917
+ assert_diagnoses(
7918
+ [:error, :unexpected_token, { :token => 'tDOT3' }],
7919
+ %q{->(...) {}},
7920
+ %q{ ^^^ location},
7921
+ SINCE_2_8)
7824
7922
 
7825
7923
  # Here and below the parser asssumes that
7826
7924
  # it can be a beginningless range, so the error comes after reducing right paren
@@ -7873,6 +7971,26 @@ class TestParser < Minitest::Test
7873
7971
  SINCE_2_7)
7874
7972
  end
7875
7973
 
7974
+ def test_trailing_forward_arg
7975
+ assert_parses(
7976
+ s(:def, :foo,
7977
+ s(:args,
7978
+ s(:arg, :a),
7979
+ s(:arg, :b),
7980
+ s(:forward_arg)),
7981
+ s(:send, nil, :bar,
7982
+ s(:lvar, :a),
7983
+ s(:int, 42),
7984
+ s(:forwarded_args))),
7985
+ %q{def foo(a, b, ...); bar(a, 42, ...); end},
7986
+ %q{ ~ begin (args)
7987
+ | ~~~~~~~~~~~ expression (args)
7988
+ | ~ end (args)
7989
+ | ~~~ expression (args.forward_arg)},
7990
+ SINCE_2_8)
7991
+ end
7992
+
7993
+
7876
7994
  def test_erange_without_parentheses_at_eol
7877
7995
  assert_diagnoses(
7878
7996
  [:warning, :triple_dot_at_eol],
@@ -8342,7 +8460,7 @@ class TestParser < Minitest::Test
8342
8460
  nil),
8343
8461
  "#{case_pre}#{code}; end",
8344
8462
  source_maps,
8345
- SINCE_2_7
8463
+ versions
8346
8464
  )
8347
8465
  end
8348
8466
 
@@ -9491,7 +9609,10 @@ class TestParser < Minitest::Test
9491
9609
  | ^ assignment
9492
9610
  |~~~~~~~~~~~~~~~~~~~~~~ expression},
9493
9611
  SINCE_2_8)
9612
+ end
9494
9613
 
9614
+ def test_endless_method_forwarded_args_legacy
9615
+ Parser::Builders::Default.emit_forward_arg = false
9495
9616
  assert_parses(
9496
9617
  s(:def_e, :foo,
9497
9618
  s(:forward_args),
@@ -9503,6 +9624,7 @@ class TestParser < Minitest::Test
9503
9624
  | ^ assignment
9504
9625
  |~~~~~~~~~~~~~~~~~~~~~~~ expression},
9505
9626
  SINCE_2_8)
9627
+ Parser::Builders::Default.emit_forward_arg = true
9506
9628
  end
9507
9629
 
9508
9630
  def test_endless_method_without_brackets
@@ -9593,4 +9715,66 @@ class TestParser < Minitest::Test
9593
9715
  %{ ^^ location},
9594
9716
  SINCE_2_8)
9595
9717
  end
9718
+
9719
+ def test_find_pattern
9720
+ assert_parses_pattern_match(
9721
+ s(:in_pattern,
9722
+ s(:find_pattern,
9723
+ s(:match_rest,
9724
+ s(:match_var, :x)),
9725
+ s(:match_as,
9726
+ s(:int, 1),
9727
+ s(:match_var, :a)),
9728
+ s(:match_rest,
9729
+ s(:match_var, :y))),
9730
+ nil,
9731
+ s(:true)),
9732
+ %q{in [*x, 1 => a, *y] then true},
9733
+ %q{ ~~~~~~~~~~~~~~~~ expression (in_pattern.find_pattern)
9734
+ | ~ begin (in_pattern.find_pattern)
9735
+ | ~ end (in_pattern.find_pattern)
9736
+ | ~~ expression (in_pattern.find_pattern.match_rest/1)
9737
+ | ~~ expression (in_pattern.find_pattern.match_rest/2)},
9738
+ SINCE_2_8)
9739
+
9740
+ assert_parses_pattern_match(
9741
+ s(:in_pattern,
9742
+ s(:const_pattern,
9743
+ s(:const, nil, :String),
9744
+ s(:find_pattern,
9745
+ s(:match_rest),
9746
+ s(:int, 1),
9747
+ s(:match_rest))),
9748
+ nil,
9749
+ s(:true)),
9750
+ %q{in String(*, 1, *) then true},
9751
+ %q{ ~~~~~~~ expression (in_pattern.const_pattern.find_pattern)},
9752
+ SINCE_2_8)
9753
+
9754
+ assert_parses_pattern_match(
9755
+ s(:in_pattern,
9756
+ s(:const_pattern,
9757
+ s(:const, nil, :Array),
9758
+ s(:find_pattern,
9759
+ s(:match_rest),
9760
+ s(:int, 1),
9761
+ s(:match_rest))),
9762
+ nil,
9763
+ s(:true)),
9764
+ %q{in Array[*, 1, *] then true},
9765
+ %q{ ~~~~~~~ expression (in_pattern.const_pattern.find_pattern)},
9766
+ SINCE_2_8)
9767
+
9768
+ assert_parses_pattern_match(
9769
+ s(:in_pattern,
9770
+ s(:find_pattern,
9771
+ s(:match_rest),
9772
+ s(:int, 42),
9773
+ s(:match_rest)),
9774
+ nil,
9775
+ s(:true)),
9776
+ %q{in *, 42, * then true},
9777
+ %q{ ~~~~~~~~ expression (in_pattern.find_pattern)},
9778
+ SINCE_2_8)
9779
+ end
9596
9780
  end