fix issue git #47, incorrect welding of anonymous subs
authorSteve Hancock <perltidy@users.sourceforge.net>
Sun, 6 Dec 2020 16:07:15 +0000 (08:07 -0800)
committerSteve Hancock <perltidy@users.sourceforge.net>
Sun, 6 Dec 2020 16:07:15 +0000 (08:07 -0800)
lib/Perl/Tidy/Formatter.pm
local-docs/BugLog.pod

index 916df977c807212a06f705bcdca4a8476fe5fccc..8160adf5747ef6daf2344fb242ba6dd8cb57d623 100644 (file)
@@ -6330,11 +6330,68 @@ sub find_nested_pairs {
         my $token_outer_closing = $rLL->[$K_outer_closing]->[_TOKEN_];
         next unless ( $is_closing_token{$token_outer_closing} );
 
-        # Yes .. this is a possible nesting pair.  Now we have to check the
-        # opening tokens.  The can be separated by a small amount.
+        # Now we have to check the opening tokens.
         my $K_outer_opening = $K_opening_container->{$outer_seqno};
         my $K_inner_opening = $K_opening_container->{$inner_seqno};
         next unless defined($K_outer_opening) && defined($K_inner_opening);
+
+        # Verify that the inner opening token is the next container after the
+        # outer opening token.
+        my $K_io_check = $rLL->[$K_outer_opening]->[_KNEXT_SEQ_ITEM_];
+        next unless defined($K_io_check);
+        if ( $K_io_check != $K_inner_opening ) {
+
+            # The inner opening container does not immediately follow the outer
+            # opening container, but we may still allow a weld if they are
+            # separated by a sub signature.  For example, we may have something
+            # like this, where $K_io_check may be at the first 'x' instead of
+            # 'io'.  So we need to hop over the signature and see if we arrive
+            # at 'io'.
+
+            #            oo               io
+            #             |     x       x |
+            #   $obj->then( sub ( $code ) {
+            #       ...
+            #       return $c->render(text => '', status => $code);
+            #   } );
+            #   | |
+            #  ic oc
+
+            next if $rLL->[$K_inner_opening]->[_BLOCK_TYPE_] ne 'sub';
+            next if $rLL->[$K_io_check]->[_TOKEN_] ne '(';
+            my $seqno_signature = $rLL->[$K_io_check]->[_TYPE_SEQUENCE_];
+            next unless defined($seqno_signature);
+            my $K_signature_closing = $K_closing_container->{$seqno_signature};
+            next unless defined($K_signature_closing);
+            my $K_test = $rLL->[$K_signature_closing]->[_KNEXT_SEQ_ITEM_];
+            next
+              unless ( defined($K_test) && $K_test == $K_inner_opening );
+
+            # OK, we have arrived at 'io' in the above diagram.  We should put
+            # a limit on the length or complexity of the signature here.  There
+            # is no perfect way to do this, one way is to put a limit on token
+            # count.  For consistency with older versions, we should allow a
+            # signature with a single variable to weld, but not with
+            # multiple variables.  A single variable as in 'sub ($code) {' can
+            # have a $Kdiff of 2 to 4, depending on spacing.
+
+            # But two variables like 'sub ($v1,$v2) {' can have a diff of 4 to
+            # 7, depending on spacing. So to keep formatting consistent with
+            # previous versions, we will also avoid welding if there is a comma
+            # in the signature.
+
+            my $Kdiff = $K_signature_closing - $K_io_check;
+            next if ( $Kdiff > 4 );
+
+            my $saw_comma;
+            foreach my $KK ( $K_io_check + 1 .. $K_signature_closing - 1 ) {
+                if ( $rLL->[$KK]->[_TYPE_] eq ',' ) { $saw_comma = 1; last }
+            }
+            next if ($saw_comma);
+        }
+
+        # Yes .. this is a possible nesting pair.
+        # They can be separated by a small amount.
         my $K_diff = $K_inner_opening - $K_outer_opening;
 
         # Count nonblank characters separating them.
index 44c5f5c1b55d8368eac94382b9eb3e168c679331..a7df26489e13ec4c9a238cdefbed09a04d3dac04 100644 (file)
@@ -1,3 +1,40 @@
+=head1 Issues fixed after release 20201202
+
+=over 4
+
+=item B<Fix for issue git #47>
+
+This issue has to do with the --weld-nested-containers option in the specific
+case of formatting a function which returns a list of anonymous subs.  For
+example
+
+    $promises[$i]->then(
+        sub { $all->resolve(@_); () },
+        sub {
+            $results->[$i] = [@_];
+            $all->reject(@$results) if --$remaining <= 0;
+            return ();
+        }
+    );
+
+A bug introduced in v20201202 caused an incorrect welding to occur
+when the -wn flag was set
+
+    $promises[$i]->then( sub { $all->resolve(@_); () },
+        sub {
+        $results->[$i] = [@_];
+        $all->reject(@$results) if --$remaining <= 0;
+        return ();
+        } );
+
+This bug has been fixed, and code which has been incorrectly formatted will be
+correctly formatted with the next release.  The bug was a result of a new
+coding introduced in v20201202 for fixing some issues with parsing sub
+signatures.  Previously they were sometimes parsed the same as prototypes and
+sometimes as lists, now they are always parsed as lists.
+
+=back
+
 =head1 Issues fixed after release 20201001
 
 =over 4