Project

General

Profile

Actions

Bug #22314

open

parse.y does not check **rest bindings in patterns (duplicate / alternation)

Bug #22314: parse.y does not check **rest bindings in patterns (duplicate / alternation)

Added by yuki300 (y h) 6 days ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 4.0.4 (2026-05-12 revision b89eb1bcbf) +PRISM [arm64-darwin25]
[ruby-core:126699]

Description

p_kwrest is the only binding rule in patterns that does not go through
error_duplicate_pattern_variable. p_variable, p_rest and the {a:}
shorthand in p_kw all call it before assignable; for **rest the name is
handed straight to assignable in new_hash_pattern_tail. So **rest is
never registered in pvtbl, never checked against in_alt_pattern, and never
sets capture_in_pattern.

Duplicate binding

case { a: 1, b: 2 }
in { a: x, **x } then p x
end

$ ruby --parser=parse.y dup.rb
{b: 2}                          # accepted and runs; x is the rest hash
$ ruby --parser=prism dup.rb
dup.rb:2: duplicated variable name (SyntaxError)

in a, a and in a, {a:} are rejected by parse.y as expected; only **rest
slips through. This is not a 4.0 regression: parse.y in 3.4.9 also accepts it,
and Prism 3.4.9 already rejects it.

Binding inside an alternative pattern

case 1
in 1 | { a: 1, **rest }
end

$ ruby --parser=parse.y -c alt.rb
Syntax OK
$ ruby --parser=prism -c alt.rb
alt.rb:2: variable capture in alternative pattern (SyntaxError)

$ ruby --parser=parse.y alt.rb      # compile.c still catches it at run time
alt.rb:2: illegal variable in alternative pattern (rest)

*rest in the same position is rejected at parse time by both parsers. This
form only diverges since 4.0, where https://bugs.ruby-lang.org/issues/21572
moved the check to parse time; in 3.4.9 both parsers accept it under -c and
reject it at compile time.

Fix

Call error_duplicate_pattern_variable in p_kwrest, as p_rest does.
One line plus tests: https://github.com/ruby/ruby/pull/18831

It should land after the fix for https://bugs.ruby-lang.org/issues/22310
(https://github.com/ruby/ruby/pull/18830): on its own, making **rest set
capture_in_pattern would newly reject an unrelated sibling alternation such
as in [ { **rest }, 1 | 2 ] under the current p_alt check. With that fix
applied first, both parsers agree on every form I tried. Since this turns code
parse.y has accepted at least since 3.4 into a SyntaxError, I am not
requesting a backport.

Environment

ruby 4.0.4 (2026-05-12 revision b89eb1bcbf) +PRISM [arm64-darwin25]   # rejects with --parser=prism only
ruby 3.4.9 (2026-03-11 revision 76cca827ab) +PRISM [arm64-darwin25]   # duplicate case: same divergence

No data to display

Actions

Also available in: PDF Atom