This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Perl_list() tail-call optimise
authorDavid Mitchell <davem@iabyn.com>
Tue, 18 Jun 2019 14:11:12 +0000 (15:11 +0100)
committerDavid Mitchell <davem@iabyn.com>
Mon, 24 Jun 2019 10:40:06 +0000 (11:40 +0100)
The part of this function that scans the children of e.g.

    @a = do { void; void; list }

applying list context only to the last child, tail call optimise that
call to list().

(See also a few commits later entitled "Perl_scalar() tail-call
optimise" for a discourse on setting PL_curcop (in)correctly.)

op.c

diff --git a/op.c b/op.c
index 77dc177..a30740f 100644 (file)
--- a/op.c
+++ b/op.c
@@ -2396,15 +2396,18 @@ Perl_list(pTHX_ OP *o)
                     *                 ...
                     *                }}
                     */
-                if (!sib)
-                    list(kid);
+                if (!sib) {
+                    /* tail call optimise calling list() on the last kid */
+                    next_kid = kid;
+                    goto do_next;
+                }
                 else if (kid->op_type == OP_LEAVEWHEN)
                     list(kid);
                 else
                     scalarvoid(kid);
                 kid = sib;
             }
-            PL_curcop = &PL_compiling;
+            NOT_REACHED; /* NOTREACHED */
             break;
 
         }
@@ -2418,8 +2421,20 @@ Perl_list(pTHX_ OP *o)
                 return top_op; /* at top; no parents/siblings to try */
             if (OpHAS_SIBLING(o))
                 next_kid = o->op_sibparent;
-            else
+            else {
                 o = o->op_sibparent; /*try parent's next sibling */
+                switch (o->op_type) {
+                case OP_SCOPE:
+                case OP_LINESEQ:
+                case OP_LIST:
+                case OP_LEAVE:
+                case OP_LEAVETRY:
+                    /* should really restore PL_curcop to its old value, but
+                     * setting it to PL_compiling is better than do nothing */
+                    PL_curcop = &PL_compiling;
+                }
+            }
+
 
         }
         o = next_kid;