This queue is for tickets about the Future-AsyncAwait CPAN distribution.

Report information
The Basics
Id:
134414
Status:
resolved
Priority:
Low/Low

People
Owner:
Nobody in particular
Requestors:
leonerd-cpan [...] leonerd.org.uk
Cc:
AdminCc:

BugTracker
Severity:
(no value)
Broken in:
(no value)
Fixed in:
0.49



Subject: Does not suspend/resume properly across 5.33.7's CXt_EVAL|CXt_TRY contexts
Perl 5.33.7 adds real try/catch syntax, and a new context type to represent it. As demonstrated via Feature::Compat::Try, these are not currently handled: $ perl5.33.7 Build.PL Using core's feature 'try' ... $ perl5.33.7 Build test ... t/80await+try.t ...... # Future::AsyncAwait 0.48, Feature::Compat::Try 0.02 t/80await+try.t ...... 1/? # Failed test '$fdone for successful await in try/catch' # at t/80await+try.t line 46. # got: 'oopsie' # expected: 'result' # Failed test '$fdone for successful await in try/catch with return' # at t/80await+try.t line 77. # got: 'fallthrough' # expected: 'result' # Failed test 'fallthrough after try{return} did not happen' # at t/80await+try.t line 78. # Looks like you failed 3 tests of 4. t/80await+try.t ...... Dubious, test returned 3 (wstat 768, 0x300) Failed 3/4 subtests (see also https://github.com/Perl/perl5/issues/18605 ) -- Paul Evans
Fixed by attached patch. -- Paul Evans
Subject: rt134414.patch
=== modified file 'lib/Future/AsyncAwait.xs' --- old/lib/Future/AsyncAwait.xs 2021-02-02 23:20:16 +0000 +++ new/lib/Future/AsyncAwait.xs 2021-02-24 11:55:57 +0000 @@ -25,6 +25,11 @@ # define HAVE_ITERVAR #endif +#if HAVE_PERL_VERSION(5, 33, 7) +/* perl 5.33.7 added CXp_TRY and the CxTRY macro for true try/catch semantics */ +# define HAVE_CX_TRY +#endif + #ifdef SAVEt_CLEARPADRANGE # include "save_clearpadrange.c.inc" #endif @@ -983,6 +988,11 @@ frame->type = CXt_EVAL; frame->gimme = cx->blk_gimme; +#ifdef HAVE_CX_TRY + if(CxTRY(cx)) + frame->type |= CXp_TRY; +#endif + frame->el.eval.retop = cx->blk_eval.retop; break; @@ -1319,6 +1329,19 @@ CLEAR_ERRSV(); break; +#ifdef HAVE_CX_TRY + case CXt_EVAL|CXp_TRY: + if(CATCH_GET) + panic("Too late to docatch()\n"); + + cx = cx_pushblock(CXt_EVAL|CXp_EVALBLOCK|CXp_TRY, frame->gimme, + PL_stack_sp, PL_savestack_ix); + cx_pushtry(cx, frame->el.eval.retop); + PL_in_eval = EVAL_INEVAL; + CLEAR_ERRSV(); + break; +#endif + default: panic("TODO: Unsure how to restore a %d frame\n", frame->type); } === renamed file 't/80await+try.t' => 't/80await+SKT.t' === added file 't/80await+feature-try.t' --- old/t/80await+feature-try.t 1970-01-01 00:00:00 +0000 +++ new/t/80await+feature-try.t 2021-02-24 11:55:57 +0000 @@ -0,0 +1,102 @@ +#!/usr/bin/perl + +use v5.14; +use warnings; + +use Test::More; + +BEGIN { + plan skip_all => "Future is not available" + unless eval { require Future }; + plan skip_all => "Future::AsyncAwait >= 0.10 is not available" + unless eval { require Future::AsyncAwait; + Future::AsyncAwait->VERSION( '0.10' ) }; + plan skip_all => "feature 'try' is not available" + unless $] >= 5.033007; + + Future::AsyncAwait->import; + + require feature; + feature->import( 'try' ); + warnings->unimport( 'experimental::try' ); + + diag( "Future::AsyncAwait $Future::AsyncAwait::VERSION, " . + "core perl version $^V" ); +} + +# await in try/catch +{ + async sub with_trycatch + { + my $f = shift; + + my $ret; + + try { + await $f; + $ret = "result"; + } + catch ($e) { + $ret = "oopsie"; + } + return $ret; + } + + my $f1 = Future->new; + my $fdone = with_trycatch( $f1 ); + + $f1->done; + is( scalar $fdone->get, "result", '$fdone for successful await in try/catch' ); + + my $f2 = Future->new; + my $ffail = with_trycatch( $f2 ); + + $f2->fail( "fail" ); + is( scalar $ffail->get, "oopsie", '$ffail for failed await in try/catch' ); +} + +# await in try/catch with return +{ + my $fellthrough; + + async sub with_trycatch_return + { + my $f = shift; + + try { + await $f; + return "result"; + } + catch ($e) {} + $fellthrough++; + return "fallthrough"; + } + + my $f1 = Future->new; + my $fdone = with_trycatch_return( $f1 ); + + $f1->done; + + is( scalar $fdone->get, "result", '$fdone for successful await in try/catch with return' ); + ok( !$fellthrough, 'fallthrough after try{return} did not happen' ); +} + +# await in toplevel try +{ + try { + is( await Future->done( "success" ), "success", + 'await in toplevel try' ); + } + catch ($e) { + fail( 'await in toplevel try' ); + } + + try { + await Future->fail( "failure\n" ); + } + catch ($e) { + is( $e, "failure\n", 'await in toplevel try/catch failure' ); + } +} + +done_testing;
Released in 0.49 -- Paul Evans


This service runs on Request Tracker, is sponsored by The Perl Foundation, and maintained by Best Practical Solutions.

Please report any issues with rt.cpan.org to rt-cpan-admin@bestpractical.com.