ruby-changes:34284
From: nobu <ko1@a...>
Date: Fri, 6 Jun 2014 17:07:33 +0900 (JST)
Subject: [ruby-changes:34284] nobu:r46365 (trunk): compile.c, parse.y: private op assign
nobu 2014-06-06 17:07:13 +0900 (Fri, 06 Jun 2014) New Revision: 46365 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=46365 Log: compile.c, parse.y: private op assign * compile.c (iseq_compile_each), parse.y (new_attr_op_assign_gen): allow op assign to a private attribute. [ruby-core:62949] [Bug #9907] Modified files: trunk/ChangeLog trunk/compile.c trunk/parse.y trunk/test/ruby/test_assignment.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 46364) +++ ChangeLog (revision 46365) @@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Jun 6 17:07:08 2014 Nobuyoshi Nakada <nobu@r...> + + * compile.c (iseq_compile_each), parse.y (new_attr_op_assign_gen): + allow op assign to a private attribute. + [ruby-core:62949] [Bug #9907] + Fri Jun 6 13:39:32 2014 Nobuyoshi Nakada <nobu@r...> * io.c (io_setstrbuf, io_read): should not shorten the given buffer until Index: compile.c =================================================================== --- compile.c (revision 46364) +++ compile.c (revision 46365) @@ -265,6 +265,11 @@ r_value(VALUE value) https://github.com/ruby/ruby/blob/trunk/compile.c#L265 (debug_compile("== " desc "\n", \ iseq_compile_each(iseq, (anchor), (node), (poped)))) +#define COMPILE_RECV(anchor, desc, node) \ + (private_recv_p(node) ? \ + (ADD_INSN(anchor, nd_line(node), putself), VM_CALL_FCALL) : \ + (COMPILE(anchor, desc, node->nd_recv), 0)) + #define OPERAND_AT(insn, idx) \ (((INSN*)(insn))->operands[(idx)]) @@ -3983,6 +3988,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L3988 DECL_ANCHOR(args); VALUE argc; VALUE flag = 0; + VALUE asgnflag = 0; ID id = node->nd_mid; int boff = 0; @@ -4012,7 +4018,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4018 if (!poped) { ADD_INSN(ret, line, putnil); } - COMPILE(ret, "NODE_OP_ASGN1 recv", node->nd_recv); + asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node); switch (nd_type(node->nd_args->nd_head)) { case NODE_ZARRAY: argc = INT2FIX(0); @@ -4026,6 +4032,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4032 } ADD_INSN1(ret, line, dupn, FIXNUM_INC(argc, 1 + boff)); ADD_SEND_R(ret, line, ID2SYM(idAREF), argc, Qfalse, LONG2FIX(flag)); + flag |= asgnflag; if (id == 0 || id == 1) { /* 0: or, 1: and @@ -4121,6 +4128,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4128 } case NODE_OP_ASGN2:{ ID atype = node->nd_next->nd_mid; + VALUE asgnflag; LABEL *lfin = NEW_LABEL(line); LABEL *lcfin = NEW_LABEL(line); /* @@ -4165,7 +4173,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4173 */ - COMPILE(ret, "NODE_OP_ASGN2#recv", node->nd_recv); + asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node); ADD_INSN(ret, line, dup); ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_vid), INT2FIX(0)); @@ -4182,8 +4190,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4190 COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value); ADD_INSN(ret, line, swap); ADD_INSN1(ret, line, topn, INT2FIX(1)); - ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_aid), - INT2FIX(1)); + ADD_SEND_R(ret, line, ID2SYM(node->nd_next->nd_aid), + INT2FIX(1), Qfalse, INT2FIX(asgnflag)); ADD_INSNL(ret, line, jump, lfin); ADD_LABEL(ret, lcfin); @@ -4204,8 +4212,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4212 ADD_INSN(ret, line, swap); ADD_INSN1(ret, line, topn, INT2FIX(1)); } - ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_aid), - INT2FIX(1)); + ADD_SEND_R(ret, line, ID2SYM(node->nd_next->nd_aid), + INT2FIX(1), Qfalse, INT2FIX(asgnflag)); ADD_INSN(ret, line, pop); } break; @@ -5347,13 +5355,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L5355 INIT_ANCHOR(args); argc = setup_args(iseq, args, node->nd_args, &flag); - if (private_recv_p(node)) { - flag |= VM_CALL_FCALL; - ADD_INSN(recv, line, putself); - } - else { - COMPILE(recv, "recv", node->nd_recv); - } + flag |= COMPILE_RECV(recv, "recv", node); debugp_param("argc", argc); debugp_param("nd_mid", ID2SYM(node->nd_mid)); Index: parse.y =================================================================== --- parse.y (revision 46364) +++ parse.y (revision 46365) @@ -1206,7 +1206,7 @@ stmt : keyword_alias fitem {lex_state = https://github.com/ruby/ruby/blob/trunk/parse.y#L1206 else if ($5 == tANDOP) { $5 = 1; } - $$ = NEW_OP_ASGN1($1, $5, args); + $$ = NEW_OP_ASGN1(attr_receiver($1), $5, args); fixpos($$, $1); /*% $$ = dispatch2(aref_field, $1, escape_Qundef($3)); @@ -1998,7 +1998,7 @@ arg : lhs '=' arg https://github.com/ruby/ruby/blob/trunk/parse.y#L1998 else if ($5 == tANDOP) { $5 = 1; } - $$ = NEW_OP_ASGN1($1, $5, args); + $$ = NEW_OP_ASGN1(attr_receiver($1), $5, args); fixpos($$, $1); /*% $1 = dispatch2(aref_field, $1, escape_Qundef($3)); @@ -9650,6 +9650,7 @@ new_attr_op_assign_gen(struct parser_par https://github.com/ruby/ruby/blob/trunk/parse.y#L9650 else if (op == tANDOP) { op = 1; } + lhs = attr_receiver(lhs); asgn = NEW_OP_ASGN2(lhs, attr, op, rhs); fixpos(asgn, lhs); return asgn; Index: test/ruby/test_assignment.rb =================================================================== --- test/ruby/test_assignment.rb (revision 46364) +++ test/ruby/test_assignment.rb (revision 46365) @@ -102,8 +102,12 @@ class TestAssignment < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_assignment.rb#L102 end def test_assign_private_self + bug9907 = '[ruby-core:62949] [Bug #9907]' + o = Object.new class << o + def foo; 42; end + def [](i); 42; end private def foo=(a); 42; end def []=(i, a); 42; end @@ -122,6 +126,20 @@ class TestAssignment < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_assignment.rb#L126 assert_nothing_raised(NoMethodError) { assert_equal(1, o.instance_eval {self[0] = 1}) } + + assert_nothing_raised(NoMethodError, bug9907) { + assert_equal(43, o.instance_eval {self.foo += 1}) + } + assert_nothing_raised(NoMethodError, bug9907) { + assert_equal(1, o.instance_eval {self.foo &&= 1}) + } + + assert_nothing_raised(NoMethodError, bug9907) { + assert_equal(43, o.instance_eval {self[0] += 1}) + } + assert_nothing_raised(NoMethodError, bug9907) { + assert_equal(1, o.instance_eval {self[0] &&= 1}) + } end def test_yield -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/