Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

`return`-ing out of a block and LEAVE phaser (“identity”‽) #2380

Open
AlexDaniel opened this Issue Oct 16, 2018 · 5 comments

Comments

Projects
None yet
4 participants
@AlexDaniel
Copy link
Member

commented Oct 16, 2018

Code:

sub bar(&some-code) {
    LEAVE { say left };
    some-code()
};
sub foo {
    bar { return 42 } # this is a block of code that `return`s from `foo` but is executed in `bar`
};

for ^2 { say foo }

Output on all releases:

¦«2016.01.1,2016.02,2016.03,2016.04,2016.05»:
left
42
left
42

¦«2016.06,2016.07.1,2016.08.1,2016.09,2016.10,2016.11,2016.12,2017.01,
  2017.02,2017.03,2017.04.3,2017.05,2017.06,2017.07,2017.08,2017.09,
  2017.10,2017.11»:
left
0
left
42

¦«2017.12,2018.01,2018.02.1,2018.03,2018.04.1,2018.05,2018.06»:
left
1
left
42

¦«2018.08,2018.09,HEAD(e1ebffe)»:
left
identity
left
42

I was expecting left 42 left 42 or possibly an error saying that I can't do that.

@AlexDaniel AlexDaniel added the BLOCKER label Oct 16, 2018

@AlexDaniel

This comment has been minimized.

Copy link
Member Author

commented Oct 16, 2018

I don't know if this should be a blocker or not, but I added a label to make sure I take a look again.

@AlexDaniel AlexDaniel removed the BLOCKER label Oct 16, 2018

@AlexDaniel

This comment has been minimized.

Copy link
Member Author

commented Oct 16, 2018

Removing the label because it seems like we had this issue for quite a while.

@AlexDaniel AlexDaniel added the severe label Oct 16, 2018

@AlexDaniel

This comment has been minimized.

Copy link
Member Author

commented Oct 27, 2018

# this is a block of code that returns from foo but is executed in bar

Is it actually what it should mean? Or should return always return from the outer sub? I'm confused reading my own ticket.

@jnthn

This comment has been minimized.

Copy link
Member

commented Oct 27, 2018

The return applies to the nearest lexical routine, so in this case its target is foo.

@vrurg

This comment has been minimized.

Copy link
Contributor

commented Dec 3, 2018

I think I got into the very same bug. Though in my case things are slightly more complicated and it gets triggered only as a result of combination of factors: exception, LEAVE with a loop, CATCH with return:

 sub bar ( $v ) {
     die "don't like it" if $v == 3;
     LEAVE {
         note "LEAVE";
         (1..2).map: { "ok" }
     };
     "[" ~ $v ~ "]"
 }

 sub foo ( $v ) {
     my $str = bar( $v );
     CATCH {
         note "CATCH";
         default {
             return "«oops»";
         }
     }
     $str
 }

 sub foobar {
     return [~] (1..10).map: {
         note "---";
         foo( $_ );
     };
 }

 say foobar;

In this form this script outputs:

[1][2]1[4][5][6][7][8][9][10]

instead of

[1][2]«oops»[4][5][6][7][8][9][10]

A couple of remarks which hopefully would help in smashing the bug:

  1. Replacing .map in LEAVE with a for loop fixes this script.

    Though I wasn't that lucky with my real code where I had to replace 'LEAVE' with more complex code involving 'CATCHand.rethrow`. Commenting out all looping works around the bug in the real code too.

  2. In the sample code LEAVE and CATCH report about themselves. This way I discovered an oddity about the order of execution because CATCH is run before LEAVE. To my view it's absolutely contra-intuitive as it goes against both stack- and lexical-wise relations between foo() and bar().

    I would cautiously assume that this order could be related to the cause of the bug: in some way LEAVE operates on a wrong stack frame, damaging the return value from another block belonging to that very frame.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.