diff options
| author | Jemma Issroff <jemmaissroff@gmail.com> | 2023-12-12 11:08:40 -0500 |
|---|---|---|
| committer | Jemma Issroff <jemmaissroff@gmail.com> | 2023-12-12 13:45:21 -0500 |
| commit | b9dfe04a73b9b4b9a3d3e96a3418a8d105e5c63a (patch) | |
| tree | fe951447c5aeb6a14837d82afc0a87d01cfc701e | |
| parent | 68753e44083f7d4d171f66aa092b35ccb41a66f6 (diff) | |
[PRISM] Implementing forwarding of args for ForwardingSuperNode
ForwardingSuperNodes need to actually forward any applicable
arguments. This commit implements that logic, by using the data
stored on the local iseq about the parameters to forward the
appropriate arguments.
| -rw-r--r-- | prism_compile.c | 108 | ||||
| -rw-r--r-- | test/ruby/test_compile_prism.rb | 16 |
2 files changed, 119 insertions, 5 deletions
diff --git a/prism_compile.c b/prism_compile.c index e2045e3303..f1f70a9b63 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -1680,7 +1680,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *co ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_METHOD), rb_id2sym(method_id), PUSH_VAL(DEFINED_METHOD)); } else { - ADD_INSN(ret, &dummy_line_node, putself); + PM_PUTSELF; if (explicit_receiver) { PM_DUP; } @@ -1782,11 +1782,11 @@ pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *con if (lfinish[1]) { ELEM_INSERT_NEXT(last, &new_insn_body(iseq, &dummy_line_node, BIN(putnil), 0)->link); - ADD_INSN(ret, &dummy_line_node, swap); + PM_SWAP; if (lfinish[2]) { ADD_LABEL(ret, lfinish[2]); } - ADD_INSN(ret, &dummy_line_node, pop); + PM_POP; ADD_LABEL(ret, lfinish[1]); } @@ -2964,7 +2964,105 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block); } - ADD_INSN2(ret, &dummy_line_node, invokesuper, new_callinfo(iseq, 0, 0, flag, NULL, block != NULL), block); + DECL_ANCHOR(args); + INIT_ANCHOR(args); + + struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq); + + const rb_iseq_t *local_iseq = body->local_iseq; + const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(local_iseq); + + int argc = 0; + int depth = get_lvar_level(iseq); + + if (local_body->param.flags.has_lead) { + /* required arguments */ + for (int i = 0; i < local_body->param.lead_num; i++) { + int idx = local_body->local_table_size - i; + ADD_GETLOCAL(args, &dummy_line_node, idx, depth); + } + argc += local_body->param.lead_num; + } + + + if (local_body->param.flags.has_opt) { + /* optional arguments */ + for (int j = 0; j < local_body->param.opt_num; j++) { + int idx = local_body->local_table_size - (argc + j); + ADD_GETLOCAL(args, &dummy_line_node, idx, depth); + } + argc += local_body->param.opt_num; + } + + if (local_body->param.flags.has_rest) { + /* rest argument */ + int idx = local_body->local_table_size - local_body->param.rest_start; + ADD_GETLOCAL(args, &dummy_line_node, idx, depth); + ADD_INSN1(args, &dummy_line_node, splatarray, Qfalse); + + argc = local_body->param.rest_start + 1; + flag |= VM_CALL_ARGS_SPLAT; + } + + if (local_body->param.flags.has_post) { + /* post arguments */ + int post_len = local_body->param.post_num; + int post_start = local_body->param.post_start; + + int j = 0; + for (; j < post_len; j++) { + int idx = local_body->local_table_size - (post_start + j); + ADD_GETLOCAL(args, &dummy_line_node, idx, depth); + } + + if (local_body->param.flags.has_rest) { + // argc remains unchanged from rest branch + ADD_INSN1(args, &dummy_line_node, newarray, INT2FIX(j)); + ADD_INSN (args, &dummy_line_node, concatarray); + } + else { + argc = post_len + post_start; + } + } + + const struct rb_iseq_param_keyword *const local_keyword = local_body->param.keyword; + if (local_body->param.flags.has_kw) { + int local_size = local_body->local_table_size; + argc++; + + ADD_INSN1(args, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); + + if (local_body->param.flags.has_kwrest) { + int idx = local_body->local_table_size - local_keyword->rest_start; + ADD_GETLOCAL(args, &dummy_line_node, idx, depth); + if (local_keyword->num > 0) { + ADD_SEND(args, &dummy_line_node, rb_intern("dup"), INT2FIX(0)); + flag |= VM_CALL_KW_SPLAT_MUT; + } + } + else { + ADD_INSN1(args, &dummy_line_node, newhash, INT2FIX(0)); + flag |= VM_CALL_KW_SPLAT_MUT; + } + int i = 0; + for (; i < local_keyword->num; ++i) { + ID id = local_keyword->table[i]; + int idx = local_size - get_local_var_idx(local_iseq, id); + ADD_INSN1(args, &dummy_line_node, putobject, ID2SYM(id)); + ADD_GETLOCAL(args, &dummy_line_node, idx, depth); + } + ADD_SEND(args, &dummy_line_node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1)); + flag |= VM_CALL_KW_SPLAT; + } + else if (local_body->param.flags.has_kwrest) { + int idx = local_body->local_table_size - local_keyword->rest_start; + ADD_GETLOCAL(args, &dummy_line_node, idx, depth); + argc++; + flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT; + } + + ADD_SEQ(ret, args); + ADD_INSN2(ret, &dummy_line_node, invokesuper, new_callinfo(iseq, 0, argc, flag, NULL, block != NULL), block); PM_POP_IF_POPPED; return; } @@ -5031,7 +5129,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, INIT_ANCHOR(args); ISEQ_COMPILE_DATA(iseq)->current_block = NULL; - ADD_INSN(ret, &dummy_line_node, putself); + PM_PUTSELF; int argc = pm_setup_args(super_node->arguments, &flags, &keywords, iseq, ret, src, popped, scope_node, dummy_line_node, parser); diff --git a/test/ruby/test_compile_prism.rb b/test/ruby/test_compile_prism.rb index 2bc1821936..05db94227e 100644 --- a/test/ruby/test_compile_prism.rb +++ b/test/ruby/test_compile_prism.rb @@ -1543,6 +1543,22 @@ module Prism def test_ForwardingSuperNode 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(<<-CODE) + class A + def initialize(a, b) + end + end + + class B < A + attr_reader :res + def initialize(a, b, *) + super + @res = [a, b] + end + end + + B.new(1, 2).res + CODE end def test_KeywordHashNode |
