mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
[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:
2 files changed
+42
-3
Notes:
git
2026-10-17 16:48:39 +00:00
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
[
|
||||
|
||||
Reference in new issue
Block a user