mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
parent
014df99c94
commit
86320a5300
2 changed files with 64 additions and 4 deletions
|
@ -1762,9 +1762,14 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
orig_argc += 2;
|
if (has_splat) {
|
||||||
|
// If we already have a splat, we're concatenating to existing array
|
||||||
|
orig_argc += 1;
|
||||||
|
} else {
|
||||||
|
orig_argc += 2;
|
||||||
|
}
|
||||||
|
|
||||||
*flags |= VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_SPLAT_MUT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT;
|
*flags |= VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT;
|
||||||
|
|
||||||
// Forwarding arguments nodes are treated as foo(*, **, &)
|
// Forwarding arguments nodes are treated as foo(*, **, &)
|
||||||
// So foo(...) equals foo(*, **, &) and as such the local
|
// So foo(...) equals foo(*, **, &) and as such the local
|
||||||
|
@ -1773,7 +1778,13 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
|
||||||
// Push the *
|
// Push the *
|
||||||
pm_local_index_t mult_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_MULT, 0);
|
pm_local_index_t mult_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_MULT, 0);
|
||||||
PUSH_GETLOCAL(ret, location, mult_local.index, mult_local.level);
|
PUSH_GETLOCAL(ret, location, mult_local.index, mult_local.level);
|
||||||
PUSH_INSN1(ret, location, splatarray, Qtrue);
|
|
||||||
|
if (has_splat) {
|
||||||
|
// If we already have a splat, we need to concatenate arrays
|
||||||
|
PUSH_INSN(ret, location, concattoarray);
|
||||||
|
} else {
|
||||||
|
PUSH_INSN1(ret, location, splatarray, Qfalse);
|
||||||
|
}
|
||||||
|
|
||||||
// Push the **
|
// Push the **
|
||||||
pm_local_index_t pow_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_POW, 0);
|
pm_local_index_t pow_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_POW, 0);
|
||||||
|
@ -1782,7 +1793,6 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
|
||||||
// Push the &
|
// Push the &
|
||||||
pm_local_index_t and_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_AND, 0);
|
pm_local_index_t and_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_AND, 0);
|
||||||
PUSH_INSN2(ret, location, getblockparamproxy, INT2FIX(and_local.index + VM_ENV_DATA_SIZE - 1), INT2FIX(and_local.level));
|
PUSH_INSN2(ret, location, getblockparamproxy, INT2FIX(and_local.index + VM_ENV_DATA_SIZE - 1), INT2FIX(and_local.level));
|
||||||
PUSH_INSN(ret, location, splatkw);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2183,6 +2183,56 @@ end
|
||||||
RUBY
|
RUBY
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_ForwardingArgumentsNode_instruction_sequence_consistency
|
||||||
|
# Test that both parsers generate identical instruction sequences for forwarding arguments
|
||||||
|
# This prevents regressions like the one fixed in prism_compile.c for PM_FORWARDING_ARGUMENTS_NODE
|
||||||
|
|
||||||
|
# Test case from the bug report: def bar(buz, ...) = foo(buz, ...)
|
||||||
|
source = <<~RUBY
|
||||||
|
def foo(*, &block) = block
|
||||||
|
def bar(buz, ...) = foo(buz, ...)
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
compare_instruction_sequences(source)
|
||||||
|
|
||||||
|
# Test simple forwarding
|
||||||
|
source = <<~RUBY
|
||||||
|
def target(...) = nil
|
||||||
|
def forwarder(...) = target(...)
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
compare_instruction_sequences(source)
|
||||||
|
|
||||||
|
# Test mixed forwarding with regular arguments
|
||||||
|
source = <<~RUBY
|
||||||
|
def target(a, b, c) = [a, b, c]
|
||||||
|
def forwarder(x, ...) = target(x, ...)
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
compare_instruction_sequences(source)
|
||||||
|
|
||||||
|
# Test forwarding with splat
|
||||||
|
source = <<~RUBY
|
||||||
|
def target(a, b, c) = [a, b, c]
|
||||||
|
def forwarder(x, ...); target(*x, ...); end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
compare_instruction_sequences(source)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def compare_instruction_sequences(source)
|
||||||
|
# Get instruction sequences from both parsers
|
||||||
|
parsey_iseq = RubyVM::InstructionSequence.compile_parsey(source)
|
||||||
|
prism_iseq = RubyVM::InstructionSequence.compile_prism(source)
|
||||||
|
|
||||||
|
# Compare instruction sequences
|
||||||
|
assert_equal parsey_iseq.disasm, prism_iseq.disasm
|
||||||
|
end
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
def test_ForwardingSuperNode
|
def test_ForwardingSuperNode
|
||||||
assert_prism_eval("class Forwarding; def to_s; super; end; end")
|
assert_prism_eval("class Forwarding; def to_s; super; end; end")
|
||||||
assert_prism_eval("class Forwarding; def eval(code); super { code }; end; end")
|
assert_prism_eval("class Forwarding; def eval(code); super { code }; end; end")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue