88using System . Runtime . CompilerServices ;
99using System . Text ;
1010using System . Threading ;
11+ using System . Threading . Tasks ;
1112
1213using IronPython . Runtime ;
1314using IronPython . Runtime . Operations ;
@@ -118,24 +119,21 @@ internal override int KwOnlyArgCount {
118119 public Expression ReturnAnnotation { get ; internal set ; }
119120
120121#if FEATURE_NET_ASYNC
121- // Under runtime-async, async functions are compiled directly to a
122- // Task<object?> via the DLR's AsyncExpression rather than reused
123- // through the generator state machine, so IsAsync no longer implies
124- // generator-shaped emission.
122+ // Under .NET-async, async functions are compiled directly to a Task<object?> via the DLR's AsyncExpression
123+ // rather than reused through the generator state machine, so IsAsync does not imply generator-shaped emission.
125124 internal override bool IsGeneratorMethod => IsGenerator ;
126125
127- // Async-generator (PEP 525) channels, one StrongBox per async-generator instance (per stack frame
128- // at runtime — not static). Created when lowering the async generator; declared/assigned in the
129- // function body, captured by the generator (the body's yields read them through Parent), and handed
130- // to the PythonAsyncGenerator wrapper, which writes them before each resume:
126+ // Async-generator (PEP 525) channels. The StrongBox *values* are per- async-generator instance,
127+ // allocated per stack frame at runtime in the function body.
128+ // Declared/assigned in the body, captured by the generator (its yields read them through Parent),
129+ // and handed to the PythonAsyncGenerator wrapper, which writes them before each resume:
131130 // AsyncSendSlot — the value of `x = yield z` (asend(v); None for __anext__/async for).
132131 // AsyncThrowSlot — an exception to rethrow at the yield resume point (athrow/aclose).
133- private MSAst . ParameterExpression _asyncSendSlot ;
134- private MSAst . ParameterExpression _asyncThrowSlot ;
135- internal MSAst . ParameterExpression AsyncSendSlot
136- => _asyncSendSlot ??= MSAst . Expression . Variable ( typeof ( System . Runtime . CompilerServices . StrongBox < object > ) , "$asyncSend" ) ;
137- internal MSAst . ParameterExpression AsyncThrowSlot
138- => _asyncThrowSlot ??= MSAst . Expression . Variable ( typeof ( System . Runtime . CompilerServices . StrongBox < Exception > ) , "$asyncThrow" ) ;
132+ private readonly MSAst . ParameterExpression _asyncSendSlot = MSAst . Expression . Variable ( typeof ( StrongBox < object > ) , "$asyncSend" ) ;
133+ private readonly MSAst . ParameterExpression _asyncThrowSlot = MSAst . Expression . Variable ( typeof ( StrongBox < Exception > ) , "$asyncThrow" ) ;
134+
135+ internal MSAst . ParameterExpression AsyncSendSlot => _asyncSendSlot ;
136+ internal MSAst . ParameterExpression AsyncThrowSlot => _asyncThrowSlot ;
139137#else
140138 internal override bool IsGeneratorMethod => IsGenerator || IsAsync ;
141139#endif
@@ -385,16 +383,14 @@ internal MSAst.Expression MakeFunctionExpression() {
385383 )
386384 ) ,
387385#if FEATURE_NET_ASYNC
388- // Async generators are lowered via AsyncEnumerableExpression in the body, so they must not
389- // be wrapped as a PythonGenerator here — only plain (non-async) generators are.
386+ // Async generators are lowered via AsyncEnumerableExpression in the body,
387+ // so they must not be wrapped as a PythonGenerator here — only plain (non-async) generators are.
390388 ( IsGenerator && ! IsAsync ) ?
391- ( MSAst . Expression ) new PythonGeneratorExpression ( code , GlobalParent . PyContext . Options . CompilationThreshold , IsAsync ) :
392- ( MSAst . Expression ) code
393389#else
394390 ( IsGenerator || IsAsync ) ?
391+ #endif
395392 ( MSAst . Expression ) new PythonGeneratorExpression ( code , GlobalParent . PyContext . Options . CompilationThreshold , IsAsync ) :
396393 ( MSAst . Expression ) code
397- #endif
398394 ) ;
399395 } else {
400396 ret = Ast . Call (
@@ -695,18 +691,15 @@ private LightLambdaExpression CreateFunctionLambda() {
695691 // The exception traceback needs to come from the generator's method body, and so we must do the check and throw
696692 // from inside the generator.
697693#if FEATURE_NET_ASYNC
698- // Async generators have no backing PythonGenerator (they lower to IAsyncEnumerable via
699- // AsyncEnumerableExpression), so skip the $generator.CheckThrowable() prologue for them.
694+ // Async generators have no backing PythonGenerator (they lower to IAsyncEnumerable via AsyncEnumerableExpression),
695+ // so skip the $generator.CheckThrowable() prologue for them.
700696 if ( IsGenerator && ! IsAsync ) {
701- MSAst . Expression s1 = YieldExpression . CreateCheckThrowExpression ( SourceSpan . None ) ;
702- statements . Add ( s1 ) ;
703- }
704697#else
705698 if ( IsGenerator || IsAsync ) {
699+ #endif
706700 MSAst . Expression s1 = YieldExpression . CreateCheckThrowExpression ( SourceSpan . None ) ;
707701 statements . Add ( s1 ) ;
708702 }
709- #endif
710703
711704 if ( Body . CanThrow && ! ( Body is SuiteStatement ) && Body . StartIndex != - 1 ) {
712705 statements . Add ( UpdateLineNumber ( GlobalParent . IndexToLocation ( Body . StartIndex ) . Line) ) ;
@@ -726,16 +719,15 @@ private LightLambdaExpression CreateFunctionLambda() {
726719 body = AddReturnTarget ( body ) ;
727720
728721#if FEATURE_NET_ASYNC
729- // Under runtime-async, an `async def` body returns a PythonCoroutine wrapping a
730- // Task<object?>. We pre-allocate a CancellationTokenSource and a StrongBox<Exception?>
731- // here so the same instances are shared with both AsyncExpression (which threads them into
732- // AsyncHelpers.DriveAsync) and PythonCoroutine (which uses them to implement
733- // coro.throw(exc) on a running coroutine: write the exception to the box, cancel the CTS,
734- // and DriveAsync surfaces that exception in place of OperationCanceledException).
722+ // Under .NET-async, an `async def` body returns a PythonCoroutine wrapping a Task<object?>.
723+ // We pre-allocate a CancellationTokenSource and a StrongBox<Exception?> here
724+ // so the same instances are shared with both AsyncExpression, which threads them into AsyncHelpers.DriveAsync
725+ // and PythonCoroutine, which uses them to implement coro.throw(exc) on a running coroutine:
726+ // write the exception to the box, cancel the CTS, and DriveAsync surfaces that exception in place of OperationCanceledException.
735727 if ( IsAsync ) {
736- var cts = MSAst . Expression . Variable ( typeof ( System . Threading . CancellationTokenSource ) , "$cts" ) ;
737- var excBox = MSAst . Expression . Variable ( typeof ( System . Runtime . CompilerServices . StrongBox < Exception > ) , "$cancelExc" ) ;
738- var ctToken = MSAst . Expression . Property ( cts , nameof ( System . Threading . CancellationTokenSource . Token ) ) ;
728+ var cts = MSAst. Expression. Variable( typeof ( CancellationTokenSource ) , "$cts") ;
729+ var excBox = MSAst. Expression. Variable( typeof ( StrongBox < Exception > ) , "$cancelExc" ) ;
730+ var ctToken = MSAst. Expression. Property( cts , nameof ( CancellationTokenSource . Token ) ) ;
739731 if ( IsGenerator) {
740732 // Async generator: the body has both `await` and `yield`. Lower it to an
741733 // IAsyncEnumerable<object?> via AsyncEnumerableExpression, sharing the generator label so
@@ -746,11 +738,11 @@ private LightLambdaExpression CreateFunctionLambda() {
746738 var sendSlot = AsyncSendSlot;
747739 var throwSlot = AsyncThrowSlot ;
748740 body = MSAst . Expression . Block (
749- new [ ] { cts , excBox , sendSlot , throwSlot } ,
750- MSAst . Expression . Assign ( cts , MSAst . Expression . New ( typeof ( System . Threading . CancellationTokenSource ) ) ) ,
751- MSAst . Expression . Assign ( excBox , MSAst . Expression . New ( typeof ( System . Runtime . CompilerServices . StrongBox < Exception > ) ) ) ,
752- MSAst . Expression . Assign ( sendSlot , MSAst . Expression . New ( typeof ( System . Runtime . CompilerServices . StrongBox < object > ) ) ) ,
753- MSAst . Expression . Assign ( throwSlot , MSAst . Expression . New ( typeof ( System . Runtime . CompilerServices . StrongBox < Exception > ) ) ) ,
741+ [ cts , excBox , sendSlot , throwSlot ] ,
742+ MSAst . Expression . Assign ( cts , MSAst . Expression . New ( typeof ( CancellationTokenSource ) ) ) ,
743+ MSAst . Expression . Assign ( excBox , MSAst . Expression . New ( typeof ( StrongBox < Exception > ) ) ) ,
744+ MSAst . Expression . Assign ( sendSlot , MSAst . Expression . New ( typeof ( StrongBox < object > ) ) ) ,
745+ MSAst . Expression . Assign ( throwSlot , MSAst . Expression . New ( typeof ( StrongBox < Exception > ) ) ) ,
754746 Ast . Call (
755747 AstMethods . MakeAsyncGenerator ,
756748 _functionParam ,
@@ -760,19 +752,18 @@ private LightLambdaExpression CreateFunctionLambda() {
760752 cts ) ) ;
761753 } else {
762754 // Plain async def: the body returns a PythonCoroutine wrapping a Task<object?>.
763- // Lazy start: hand MakeAsyncCoroutine a thunk (Func<Task<object?>>) instead of an
764- // already-running Task, so the body doesn't execute until the coroutine is first driven
765- // (send/AsTask). This makes calling an async def side-effect-free (PEP 492) and lets the
766- // body's first await capture the driver's SynchronizationContext rather than whatever
767- // context happened to be current at construction.
755+ // Lazy start: hand MakeAsyncCoroutine a thunk (Func<Task<object?>>) instead of an already-running Task,
756+ // so the body doesn't execute until the coroutine is first driven (send/AsTask).
757+ // This makes calling an async def side-effect-free (PEP 492) and lets the body's first await capture the driver's SynchronizationContext
758+ // rather than whatever context happened to be current at construction.
768759 body = MSAst. Expression . Block (
769- new [ ] { cts , excBox } ,
770- MSAst . Expression . Assign ( cts , MSAst . Expression . New ( typeof ( System . Threading . CancellationTokenSource ) ) ) ,
771- MSAst . Expression . Assign ( excBox , MSAst . Expression . New ( typeof ( System . Runtime . CompilerServices . StrongBox < Exception > ) ) ) ,
760+ [ cts , excBox ] ,
761+ MSAst . Expression . Assign ( cts , MSAst . Expression . New ( typeof ( CancellationTokenSource ) ) ) ,
762+ MSAst . Expression . Assign ( excBox , MSAst . Expression . New ( typeof ( StrongBox < Exception > ) ) ) ,
772763 Ast . Call (
773764 AstMethods . MakeAsyncCoroutine ,
774765 _functionParam ,
775- MSAst . Expression . Lambda < Func < System . Threading . Tasks . Task < object > > > (
766+ MSAst . Expression . Lambda < Func < Task < object > > > (
776767 AstUtils . Async ( Name , body , ctToken , excBox ) ) ,
777768 cts ,
778769 excBox ) ) ;
0 commit comments