[PRISM] Fix PM_CALL_NODE
assignment
This PR fixes ruby/prism#1963. Array and variable assignment was broken for call nodes. The change checks if the `method_id` is related to assignment and if is adds a `putnil`, `setn` and a `pop`. The incorrect instructions meant that in some cases (demonstrated in tests) the wrong value would be returned. I verified that this fixes the test mentioned in the issue (run: `RUBY_ISEQ_DUMP_DEBUG=prism make test/-ext-/st/test_numhash.rb`) Incorrect instructions: ``` "********* Ruby *************" == disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(4,10)> 0000 putnil ( 4)[Li] 0001 putself 0002 send <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0005 putself 0006 send <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0009 putself 0010 send <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0013 setn 3 0015 send <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil 0018 pop 0019 leave "********* PRISM *************" == disasm: #<ISeq:<compiled>@<compiled>:3 (3,0)-(3,10)> 0000 putself ( 3)[Li] 0001 send <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0004 putself 0005 send <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0008 putself 0009 send <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0012 send <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil 0015 leave ``` Fixed instructions: ``` "********* Ruby *************" == disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(4,10)> 0000 putnil ( 4)[Li] 0001 putself 0002 send <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0005 putself 0006 send <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0009 putself 0010 send <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0013 setn 3 0015 send <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil 0018 pop 0019 leave "********* PRISM *************" == disasm: #<ISeq:<compiled>@<compiled>:3 (3,0)-(3,10)> 0000 putnil ( 3)[Li] 0001 putself 0002 send <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0005 putself 0006 send <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0009 putself 0010 send <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0013 setn 3 0015 send <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil 0018 pop 0019 leave ``` Fixes ruby/prism#1963
This commit is contained in:
parent
9e7ca2c3c9
commit
1cbe114d1c
@ -1465,7 +1465,7 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node);
|
||||
static void pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, ID method_id);
|
||||
|
||||
void
|
||||
pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, NODE dummy_line_node, int lineno, bool in_condition, LABEL **lfinish, bool explicit_receiver)
|
||||
@ -1637,7 +1637,8 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *co
|
||||
pm_compile_defined_expr0(iseq, call_node->receiver, ret, src, popped, scope_node, dummy_line_node, lineno, true, lfinish, true);
|
||||
if (PM_NODE_TYPE_P(call_node->receiver, PM_CALL_NODE)) {
|
||||
ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[2]);
|
||||
pm_compile_call(iseq, (const pm_call_node_t *)call_node->receiver, ret, src, popped, scope_node);
|
||||
ID method_id = pm_constant_id_lookup(scope_node, call_node->name);
|
||||
pm_compile_call(iseq, (const pm_call_node_t *)call_node->receiver, ret, src, popped, scope_node, method_id);
|
||||
}
|
||||
else {
|
||||
ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
|
||||
@ -1765,14 +1766,13 @@ pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *con
|
||||
}
|
||||
|
||||
static void
|
||||
pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
|
||||
pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, ID method_id)
|
||||
{
|
||||
pm_parser_t *parser = scope_node->parser;
|
||||
pm_newline_list_t newline_list = parser->newline_list;
|
||||
int lineno = (int)pm_newline_list_line_column(&newline_list, ((pm_node_t *)call_node)->location.start).line;
|
||||
NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
|
||||
|
||||
ID method_id = pm_constant_id_lookup(scope_node, call_node->name);
|
||||
int flags = 0;
|
||||
struct rb_callinfo_kwarg *kw_arg = NULL;
|
||||
|
||||
@ -1806,7 +1806,16 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
|
||||
flags |= VM_CALL_FCALL;
|
||||
}
|
||||
|
||||
if (rb_is_attrset_id(method_id)) {
|
||||
ADD_INSN1(ret, &dummy_line_node, setn, INT2FIX(orig_argc + 1));
|
||||
}
|
||||
|
||||
ADD_SEND_R(ret, &dummy_line_node, method_id, INT2FIX(orig_argc), block_iseq, INT2FIX(flags), kw_arg);
|
||||
|
||||
if (rb_is_attrset_id(method_id)) {
|
||||
PM_POP;
|
||||
}
|
||||
|
||||
PM_POP_IF_POPPED;
|
||||
}
|
||||
|
||||
@ -2149,13 +2158,18 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
|
||||
case PM_CALL_NODE: {
|
||||
pm_call_node_t *call_node = (pm_call_node_t *) node;
|
||||
|
||||
ID method_id = pm_constant_id_lookup(scope_node, call_node->name);
|
||||
if (rb_is_attrset_id(method_id)) {
|
||||
PM_PUTNIL;
|
||||
}
|
||||
|
||||
if (call_node->receiver == NULL) {
|
||||
PM_PUTSELF;
|
||||
} else {
|
||||
PM_COMPILE_NOT_POPPED(call_node->receiver);
|
||||
}
|
||||
|
||||
pm_compile_call(iseq, call_node, ret, src, popped, scope_node);
|
||||
pm_compile_call(iseq, call_node, ret, src, popped, scope_node, method_id);
|
||||
return;
|
||||
}
|
||||
case PM_CALL_AND_WRITE_NODE: {
|
||||
|
@ -1301,6 +1301,34 @@ module Prism
|
||||
CODE
|
||||
|
||||
assert_prism_eval("prism_test_call_node_splat(*[], 1, 2)")
|
||||
|
||||
assert_prism_eval(<<-CODE)
|
||||
class Foo
|
||||
def []=(a, b)
|
||||
1234
|
||||
end
|
||||
end
|
||||
|
||||
def self.foo(i, j)
|
||||
tbl = Foo.new
|
||||
tbl[i] = j
|
||||
end
|
||||
foo(1, 2)
|
||||
CODE
|
||||
|
||||
assert_prism_eval(<<-CODE)
|
||||
class Foo
|
||||
def i=(a)
|
||||
1234
|
||||
end
|
||||
end
|
||||
|
||||
def self.foo(j)
|
||||
tbl = Foo.new
|
||||
tbl.i = j
|
||||
end
|
||||
foo(1)
|
||||
CODE
|
||||
end
|
||||
|
||||
def test_CallAndWriteNode
|
||||
|
Loading…
x
Reference in New Issue
Block a user