summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--compile.c28
-rw-r--r--parse.y5
-rw-r--r--test/ruby/test_assignment.rb18
4 files changed, 42 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index 9d1cea85dd..551dd1cfd5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Fri Jun 6 17:07:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * 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@ruby-lang.org>
* io.c (io_setstrbuf, io_read): should not shorten the given buffer until
diff --git a/compile.c b/compile.c
index aeebe2634e..e4d2998885 100644
--- a/compile.c
+++ b/compile.c
@@ -265,6 +265,11 @@ r_value(VALUE value)
(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_ANCHOR *ret, NODE * node, int poped)
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_ANCHOR *ret, NODE * node, int poped)
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_ANCHOR *ret, NODE * node, int poped)
}
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_ANCHOR *ret, NODE * node, int poped)
}
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_ANCHOR *ret, NODE * node, int poped)
*/
- 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_ANCHOR *ret, NODE * node, int poped)
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_ANCHOR *ret, NODE * node, int poped)
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_ANCHOR *ret, NODE * node, int poped)
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));
diff --git a/parse.y b/parse.y
index d2076a8d6d..a9f7d5db82 100644
--- a/parse.y
+++ b/parse.y
@@ -1206,7 +1206,7 @@ stmt : keyword_alias fitem {lex_state = EXPR_FNAME;} fitem
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
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_params *parser, NODE *lhs, ID attr, ID op,
else if (op == tANDOP) {
op = 1;
}
+ lhs = attr_receiver(lhs);
asgn = NEW_OP_ASGN2(lhs, attr, op, rhs);
fixpos(asgn, lhs);
return asgn;
diff --git a/test/ruby/test_assignment.rb b/test/ruby/test_assignment.rb
index 604464bbd3..c6f1cd1bc7 100644
--- a/test/ruby/test_assignment.rb
+++ b/test/ruby/test_assignment.rb
@@ -102,8 +102,12 @@ class TestAssignment < Test::Unit::TestCase
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::TestCase
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