[Bug #22450] Preserve do-block binding in control-flow arguments

Inherited `CMDARG` state made `do` blocks in control-flow arguments
bind to the wrong call.
This commit is contained in:
Nobuyoshi Nakada committed 2026-10-18 00:33:30 +09:00
1 parent a430ab4e96
commit 31a3aa4e46
2 files changed
+42 -3
Notes: git 2026-10-17 16:48:39 +00:00

No files matched your search

+24 -3
View File
@@ -3656,20 +3656,23 @@ command : fcall command_args %prec tLOWEST
fixpos($$, $2);
/*% ripper: yield!($:2) %*/
}
| k_return call_args
| k_return_arg call_args
{
CMDARG_POP();
$$ = NEW_RETURN(ret_args(p, $2), &@$, &@1);
/*% ripper: return!($:2) %*/
}
| keyword_break call_args
| k_break_arg call_args
{
CMDARG_POP();
NODE *args = 0;
args = ret_args(p, $2);
$$ = add_block_exit(p, NEW_BREAK(args, &@$, &@1));
/*% ripper: break!($:2) %*/
}
| keyword_next call_args
| k_next_arg call_args
{
CMDARG_POP();
NODE *args = 0;
args = ret_args(p, $2);
$$ = add_block_exit(p, NEW_NEXT(args, &@$, &@1));
@@ -4897,6 +4900,24 @@ k_return : keyword_return
}
;
k_return_arg : k_return
{
CMDARG_PUSH(0);
}
;
k_break_arg : keyword_break
{
CMDARG_PUSH(0);
}
;
k_next_arg : keyword_next
{
CMDARG_PUSH(0);
}
;
k_yield : keyword_yield
{
if (!p->ctxt.in_defined && !p->ctxt.in_def && !compile_for_eval)
+18
View File
@@ -1517,6 +1517,24 @@ x = __ENCODING__
assert_valid_syntax('let () { m(a) do; end }')
end
def test_do_block_in_return_argument_inside_command_arguments
omit if ParserSupport.prism_enabled?
nodes = ->(node) do
return [] unless node.is_a?(RubyVM::AbstractSyntaxTree::Node)
[node] + node.children.flat_map {|child| nodes.call(child) }
end
{return: :RETURN, break: :BREAK, next: :NEXT}.each do |keyword, exit_type|
ast = RubyVM::AbstractSyntaxTree.parse("def f; 1.times { check 1, if true then #{keyword} foo + bar do end end }; end")
exit_node = nodes.call(ast).find {|node| node.type == exit_type }
exit_value = exit_node.children.find {|child| child.is_a?(RubyVM::AbstractSyntaxTree::Node) }
assert_equal(:OPCALL, exit_value.type, keyword)
block = nodes.call(exit_value).find {|node| node.type == :ITER }
assert_equal(:FCALL, block.children.first.type, keyword)
end
end
def test_void_value_in_rhs
w = "void value expression"
[