Lookup overloaded assignment operators when trying to swap the arguments
authorRafael Garcia-Suarez <rgs@consttype.org>
Tue, 20 Mar 2012 08:17:02 +0000 (09:17 +0100)
committerRafael Garcia-Suarez <rgs@consttype.org>
Tue, 22 May 2012 07:51:28 +0000 (09:51 +0200)
This is in the case where we search for an overloaded operator when
passing the AMGf_assign flag (we're executing an assignment operator
like +=).

At the very beginning of Perl_amagic_call, if the flag AMGf_noleft is
not passed, we first try to look up the overload method corresponding
to the assignment operator, then the normal one if fallback is
authorized. However, if this fails, when trying later to find
overload magic with the arguments swapped (if AMGf_noright is not
passed), this procedure was not used and we looked up directly the base
operation from which the assignment operator might be derived.
As a consequence of what an operator like += might have looked
autogenerated even when fallback=>0 was passed.

This change only necessitates a minor adjustment in lib/overload.t,
where an overloaded += method wasn't corresponding semantically to the
overloaded + method of the same class, which can be seen as a
pathological case.

gv.c
lib/overload.t

diff --git a/gv.c b/gv.c
index 89a672c..2befa71 100644 (file)
--- a/gv.c
+++ b/gv.c
@@ -2740,9 +2740,16 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
               && (cvp = (AMT_AMAGIC((AMT*)mg->mg_ptr)
                          ? (amtp = (AMT*)mg->mg_ptr)->table
                          : NULL))
-              && (cv = cvp[off=method])) { /* Method for right
-                                            * argument found */
-      lr=1;
+              && ((cv = cvp[off=method+assignshift])
+                  || (assign && amtp->fallback > AMGfallNEVER && /* fallback to
+                                                                  * usual method */
+                      (
+#ifdef DEBUGGING
+                       fl = 1,
+#endif
+                       cv = cvp[off=method])))) { /* Method for right
+                                                   * argument found */
+       lr=1;
     } else if (((cvp && amtp->fallback > AMGfallNEVER)
                 || (ocvp && oamtp->fallback > AMGfallNEVER))
               && !(flags & AMGf_unary)) {
index df3a9b8..0304714 100644 (file)
@@ -202,7 +202,7 @@ is($b, "89");
 is(ref $a, "Oscalar");
 is($copies, 1);
 
-eval q[package Oscalar; use overload ('+=' => sub {$ {$_[0]} += 3*$_[1];
+eval q[package Oscalar; use overload ('+=' => sub {$ {$_[0]} += 3*"$_[1]";
                                                   $_[0] } ) ];
 $c=new Oscalar;                        # Cause rehash