// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp { internal partial class AsyncRewriter : StateMachineRewriter { /// /// This rewriter rewrites an async-iterator method. See async-streams.md for design overview. /// private sealed class AsyncIteratorRewriter : AsyncRewriter { private FieldSymbol _promiseOfValueOrEndField; // this struct implements the IValueTaskSource logic private FieldSymbol _currentField; // stores the current/yielded value private FieldSymbol _disposeModeField; // whether the state machine is in dispose mode (ie. skipping all logic except that in `catch` and `finally`, yielding no new elements) private FieldSymbol _combinedTokensField; // CancellationTokenSource for combining tokens // true if the iterator implements IAsyncEnumerable, // false if it implements IAsyncEnumerator private readonly bool _isEnumerable; internal AsyncIteratorRewriter( BoundStatement body, MethodSymbol method, int methodOrdinal, AsyncStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) { Debug.Assert(!TypeSymbol.Equals(method.IteratorElementTypeWithAnnotations.Type, null, TypeCompareKind.ConsiderEverything2)); _isEnumerable = method.IsAsyncReturningIAsyncEnumerable(method.DeclaringCompilation); Debug.Assert(_isEnumerable != method.IsAsyncReturningIAsyncEnumerator(method.DeclaringCompilation)); } protected override void VerifyPresenceOfRequiredAPIs(DiagnosticBag bag) { base.VerifyPresenceOfRequiredAPIs(bag); if (_isEnumerable) { EnsureWellKnownMember(WellKnownMember.System_Collections_Generic_IAsyncEnumerable_T__GetAsyncEnumerator, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_CancellationToken__Equals, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_CancellationTokenSource__CreateLinkedTokenSource, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_CancellationTokenSource__Token, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_CancellationTokenSource__Dispose, bag); } EnsureWellKnownMember(WellKnownMember.System_Collections_Generic_IAsyncEnumerator_T__MoveNextAsync, bag); EnsureWellKnownMember(WellKnownMember.System_Collections_Generic_IAsyncEnumerator_T__get_Current, bag); EnsureWellKnownMember(WellKnownMember.System_IAsyncDisposable__DisposeAsync, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_ValueTask_T__ctorSourceAndToken, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_ValueTask_T__ctorValue, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_ValueTask__ctor, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__GetResult, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__GetStatus, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__get_Version, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__OnCompleted, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__Reset, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__SetException, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__SetResult, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource_T__GetResult, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource_T__GetStatus, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource_T__OnCompleted, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource__GetResult, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource__GetStatus, bag); EnsureWellKnownMember(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource__OnCompleted, bag); } protected override void GenerateMethodImplementations() { // IAsyncStateMachine methods and constructor base.GenerateMethodImplementations(); if (_isEnumerable) { // IAsyncEnumerable GenerateIAsyncEnumerableImplementation_GetAsyncEnumerator(); } // IAsyncEnumerator GenerateIAsyncEnumeratorImplementation_MoveNextAsync(); GenerateIAsyncEnumeratorImplementation_Current(); // IValueTaskSource GenerateIValueTaskSourceBoolImplementation_GetResult(); GenerateIValueTaskSourceBoolImplementation_GetStatus(); GenerateIValueTaskSourceBoolImplementation_OnCompleted(); // IValueTaskSource GenerateIValueTaskSourceImplementation_GetResult(); GenerateIValueTaskSourceImplementation_GetStatus(); GenerateIValueTaskSourceImplementation_OnCompleted(); // IAsyncDisposable GenerateIAsyncDisposable_DisposeAsync(); } protected override bool PreserveInitialParameterValuesAndThreadId => _isEnumerable; protected override void GenerateControlFields() { // the fields are initialized from entry-point method (which replaces the async-iterator method), so they need to be public base.GenerateControlFields(); NamedTypeSymbol boolType = F.SpecialType(SpecialType.System_Boolean); // Add a field: ManualResetValueTaskSourceLogic promiseOfValueOrEnd _promiseOfValueOrEndField = F.StateMachineField( F.WellKnownType(WellKnownType.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T).Construct(boolType), GeneratedNames.MakeAsyncIteratorPromiseOfValueOrEndFieldName(), isPublic: true); // the element type may contain method type parameters, which are now alpha-renamed into type parameters of the generated class TypeSymbol elementType = ((AsyncStateMachine)stateMachineType).IteratorElementType; // Add a field: T current _currentField = F.StateMachineField(elementType, GeneratedNames.MakeIteratorCurrentFieldName()); // Add a field: bool disposeMode _disposeModeField = F.StateMachineField(boolType, GeneratedNames.MakeDisposeModeFieldName()); if (_isEnumerable && this.method.Parameters.Any(p => p is SourceComplexParameterSymbol { HasEnumeratorCancellationAttribute: true })) { // Add a field: CancellationTokenSource combinedTokens _combinedTokensField = F.StateMachineField( F.WellKnownType(WellKnownType.System_Threading_CancellationTokenSource), GeneratedNames.MakeAsyncIteratorCombinedTokensFieldName()); } } protected override void GenerateConstructor() { // Produces: // .ctor(int state) // { // this.state = state; // this.initialThreadId = {managedThreadId}; // this.builder = System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create(); // } Debug.Assert(stateMachineType.Constructor is IteratorConstructor); F.CurrentFunction = stateMachineType.Constructor; var bodyBuilder = ArrayBuilder.GetInstance(); bodyBuilder.Add(F.BaseInitialization()); bodyBuilder.Add(F.Assignment(F.InstanceField(stateField), F.Parameter(F.CurrentFunction.Parameters[0]))); // this.state = state; var managedThreadId = MakeCurrentThreadId(); if (managedThreadId != null && (object)initialThreadIdField != null) { // this.initialThreadId = {managedThreadId}; bodyBuilder.Add(F.Assignment(F.InstanceField(initialThreadIdField), managedThreadId)); } // this.builder = System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create(); bodyBuilder.Add(GenerateCreateAndAssignBuilder()); bodyBuilder.Add(F.Return()); F.CloseMethod(F.Block(bodyBuilder.ToImmutableAndFree())); bodyBuilder = null; } private BoundExpressionStatement GenerateCreateAndAssignBuilder() { // Produce: // this.builder = System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create(); return F.Assignment( F.InstanceField(_builderField), F.StaticCall( null, _asyncMethodBuilderMemberCollection.CreateBuilder)); } protected override void InitializeStateMachine(ArrayBuilder bodyBuilder, NamedTypeSymbol frameType, LocalSymbol stateMachineLocal) { // var stateMachineLocal = new {StateMachineType}({initialState}) int initialState = _isEnumerable ? StateMachineStates.FinishedStateMachine : StateMachineStates.InitialAsyncIteratorStateMachine; bodyBuilder.Add( F.Assignment( F.Local(stateMachineLocal), F.New(stateMachineType.Constructor.AsMember(frameType), F.Literal(initialState)))); } protected override BoundStatement InitializeParameterField(MethodSymbol getEnumeratorMethod, ParameterSymbol parameter, BoundExpression resultParameter, BoundExpression parameterProxy) { BoundStatement result; if (_combinedTokensField is object && parameter is SourceComplexParameterSymbol { HasEnumeratorCancellationAttribute: true } && parameter.Type.Equals(F.Compilation.GetWellKnownType(WellKnownType.System_Threading_CancellationToken), TypeCompareKind.ConsiderEverything)) { // For a parameter of type CancellationToken with [EnumeratorCancellation] // if (this.parameterProxy.Equals(default)) // { // result.parameter = token; // } // else if (token.Equals(this.parameterProxy) || token.Equals(default)) // { // result.parameter = this.parameterProxy; // } // else // { // result.combinedTokens = CancellationTokenSource.CreateLinkedTokenSource(this.parameterProxy, token); // result.parameter = combinedTokens.Token; // } BoundParameter tokenParameter = F.Parameter(getEnumeratorMethod.Parameters[0]); BoundFieldAccess combinedTokens = F.Field(F.This(), _combinedTokensField); result = F.If( // if (this.parameterProxy.Equals(default)) F.Call(parameterProxy, WellKnownMember.System_Threading_CancellationToken__Equals, F.Default(parameterProxy.Type)), // result.parameter = token; thenClause: F.Assignment(resultParameter, tokenParameter), elseClauseOpt: F.If( // else if (token.Equals(this.parameterProxy) || token.Equals(default)) F.LogicalOr( F.Call(tokenParameter, WellKnownMember.System_Threading_CancellationToken__Equals, parameterProxy), F.Call(tokenParameter, WellKnownMember.System_Threading_CancellationToken__Equals, F.Default(tokenParameter.Type))), // result.parameter = this.parameterProxy; thenClause: F.Assignment(resultParameter, parameterProxy), elseClauseOpt: F.Block( // result.combinedTokens = CancellationTokenSource.CreateLinkedTokenSource(this.parameterProxy, token); F.Assignment(combinedTokens, F.StaticCall(WellKnownMember.System_Threading_CancellationTokenSource__CreateLinkedTokenSource, parameterProxy, tokenParameter)), // result.parameter = result.combinedTokens.Token; F.Assignment(resultParameter, F.Property(combinedTokens, WellKnownMember.System_Threading_CancellationTokenSource__Token))))); } else { // For parameters that don't have [EnumeratorCancellation], initialize their parameter fields // result.parameter = this.parameterProxy; result = F.Assignment(resultParameter, parameterProxy); } return result; } protected override BoundStatement GenerateStateMachineCreation(LocalSymbol stateMachineVariable, NamedTypeSymbol frameType) { // return local; return F.Block(F.Return(F.Local(stateMachineVariable))); } /// /// Generates the `ValueTask<bool> MoveNextAsync()` method. /// [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "Standard naming convention for generating 'IAsyncEnumerator.MoveNextAsync'")] private void GenerateIAsyncEnumeratorImplementation_MoveNextAsync() { // Produce: // if (state == StateMachineStates.FinishedStateMachine) // { // return default; // } // _valueOrEndPromise.Reset(); // var inst = this; // _builder.Start(ref inst); // var version = _valueOrEndPromise.Version; // if (_valueOrEndPromise.GetStatus(version) == ValueTaskSourceStatus.Succeeded) // { // return new ValueTask(_valueOrEndPromise.GetResult(version)); // } // return new ValueTask(this, version); NamedTypeSymbol IAsyncEnumeratorOfElementType = F.WellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T) .Construct(_currentField.Type); MethodSymbol IAsyncEnumerableOfElementType_MoveNextAsync = F.WellKnownMethod(WellKnownMember.System_Collections_Generic_IAsyncEnumerator_T__MoveNextAsync) .AsMember(IAsyncEnumeratorOfElementType); var promiseType = (NamedTypeSymbol)_promiseOfValueOrEndField.Type; MethodSymbol promise_GetStatus = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__GetStatus) .AsMember(promiseType); MethodSymbol promise_GetResult = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__GetResult) .AsMember(promiseType); var moveNextAsyncReturnType = (NamedTypeSymbol)IAsyncEnumerableOfElementType_MoveNextAsync.ReturnType; MethodSymbol valueTaskT_ctorValue = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_ValueTask_T__ctorValue) .AsMember(moveNextAsyncReturnType); MethodSymbol valueTaskT_ctor = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_ValueTask_T__ctorSourceAndToken) .AsMember(moveNextAsyncReturnType); // The implementation doesn't depend on the method body of the iterator method. OpenMethodImplementation(IAsyncEnumerableOfElementType_MoveNextAsync, hasMethodBodyDependency: false); GetPartsForStartingMachine(out BoundExpressionStatement callReset, out LocalSymbol instSymbol, out BoundStatement instAssignment, out BoundExpressionStatement startCall, out MethodSymbol promise_get_Version); BoundStatement ifFinished = F.If( // if (state == StateMachineStates.FinishedStateMachine) F.IntEqual(F.InstanceField(stateField), F.Literal(StateMachineStates.FinishedStateMachine)), // return default; thenClause: F.Return(F.Default(moveNextAsyncReturnType))); // var version = _valueOrEndPromise.Version; var versionSymbol = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int16)); var versionLocal = F.Local(versionSymbol); var versionInit = F.Assignment(versionLocal, F.Call(F.Field(F.This(), _promiseOfValueOrEndField), promise_get_Version)); var ifPromiseReady = F.If( // if (_valueOrEndPromise.GetStatus(version) == ValueTaskSourceStatus.Succeeded) F.IntEqual( F.Call(F.Field(F.This(), _promiseOfValueOrEndField), promise_GetStatus, versionLocal), F.Literal(1)), // return new ValueTask(_valueOrEndPromise.GetResult(version)); thenClause: F.Return(F.New(valueTaskT_ctorValue, F.Call(F.Field(F.This(), _promiseOfValueOrEndField), promise_GetResult, versionLocal)))); // return new ValueTask(this, version); // Note: we fall back to this slower method of returning when the promise doesn't yet have a value. // This method of returning relies on two interface calls (`IValueTaskSource.GetStatus(version)` and `IValueTaskSource.GetResult(version)`). var returnStatement = F.Return(F.New(valueTaskT_ctor, F.This(), versionLocal)); F.CloseMethod(F.Block( ImmutableArray.Create(instSymbol, versionSymbol), ifFinished, callReset, // _promiseOfValueOrEnd.Reset(); instAssignment, // var inst = this; startCall, // _builder.Start(ref inst); versionInit, ifPromiseReady, returnStatement)); } /// /// Prepares most of the parts for MoveNextAsync() and DisposeAsync() methods. /// private void GetPartsForStartingMachine(out BoundExpressionStatement callReset, out LocalSymbol instSymbol, out BoundStatement instAssignment, out BoundExpressionStatement startCall, out MethodSymbol promise_get_Version) { // Produce the following parts: // - _promiseOfValueOrEnd.Reset(); // - var inst = this; // - _builder.Start(ref inst); // - _valueOrEndPromise.Version // _promiseOfValueOrEnd.Reset(); BoundFieldAccess promiseField = F.InstanceField(_promiseOfValueOrEndField); var resetMethod = (MethodSymbol)F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__Reset, isOptional: true) .SymbolAsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type); callReset = F.ExpressionStatement(F.Call(promiseField, resetMethod)); // _builder.Start(ref inst); Debug.Assert(!_asyncMethodBuilderMemberCollection.CheckGenericMethodConstraints); MethodSymbol startMethod = _asyncMethodBuilderMemberCollection.Start.Construct(this.stateMachineType); instSymbol = F.SynthesizedLocal(this.stateMachineType); // var inst = this; var instLocal = F.Local(instSymbol); instAssignment = F.Assignment(instLocal, F.This()); // _builder.Start(ref inst); startCall = F.ExpressionStatement( F.Call( F.InstanceField(_builderField), startMethod, ImmutableArray.Create(instLocal))); // _valueOrEndPromise.Version promise_get_Version = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__get_Version) .AsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type); } /// /// Generates the `ValueTask IAsyncDisposable.DisposeAsync()` method. /// The DisposeAsync method should not be called from states -1 (running) or 0-and-up (awaits). /// [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "Standard naming convention for generating 'IAsyncDisposable.DisposeAsync'")] private void GenerateIAsyncDisposable_DisposeAsync() { // Produce: // if (state >= StateMachineStates.NotStartedStateMachine /* -3 */) // { // throw new NotSupportedException(); // } // if (state == StateMachineStates.FinishedStateMachine /* -2 */) // { // return default; // } // disposeMode = true; // _valueOrEndPromise.Reset(); // var inst = this; // _builder.Start(ref inst); // return new ValueTask(this, _valueOrEndPromise.Version); MethodSymbol IAsyncDisposable_DisposeAsync = F.WellKnownMethod(WellKnownMember.System_IAsyncDisposable__DisposeAsync); // The implementation doesn't depend on the method body of the iterator method. OpenMethodImplementation(IAsyncDisposable_DisposeAsync, hasMethodBodyDependency: false); TypeSymbol returnType = IAsyncDisposable_DisposeAsync.ReturnType; GetPartsForStartingMachine(out BoundExpressionStatement callReset, out LocalSymbol instSymbol, out BoundStatement instAssignment, out BoundExpressionStatement startCall, out MethodSymbol promise_get_Version); BoundStatement ifInvalidState = F.If( // if (state >= StateMachineStates.NotStartedStateMachine /* -1 */) F.IntGreaterThanOrEqual(F.InstanceField(stateField), F.Literal(StateMachineStates.NotStartedStateMachine)), // throw new NotSupportedException(); thenClause: F.Throw(F.New(F.WellKnownType(WellKnownType.System_NotSupportedException)))); BoundStatement ifFinished = F.If( // if (state == StateMachineStates.FinishedStateMachine) F.IntEqual(F.InstanceField(stateField), F.Literal(StateMachineStates.FinishedStateMachine)), // return default; thenClause: F.Return(F.Default(returnType))); MethodSymbol valueTask_ctor = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_ValueTask__ctor) .AsMember((NamedTypeSymbol)IAsyncDisposable_DisposeAsync.ReturnType); // return new ValueTask(this, _valueOrEndPromise.Version); var returnStatement = F.Return(F.New(valueTask_ctor, F.This(), F.Call(F.InstanceField(_promiseOfValueOrEndField), promise_get_Version))); F.CloseMethod(F.Block( ImmutableArray.Create(instSymbol), ifInvalidState, ifFinished, F.Assignment(F.InstanceField(_disposeModeField), F.Literal(true)), // disposeMode = true; callReset, // _promiseOfValueOrEnd.Reset(); instAssignment, // var inst = this; startCall, // _builder.Start(ref inst); returnStatement)); } /// /// Generates the Current property. /// private void GenerateIAsyncEnumeratorImplementation_Current() { // Produce the implementation for `T Current { get; }`: // return _current; NamedTypeSymbol IAsyncEnumeratorOfElementType = F.WellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T) .Construct(_currentField.Type); MethodSymbol IAsyncEnumerableOfElementType_get_Current = F.WellKnownMethod(WellKnownMember.System_Collections_Generic_IAsyncEnumerator_T__get_Current) .AsMember(IAsyncEnumeratorOfElementType); OpenPropertyImplementation(IAsyncEnumerableOfElementType_get_Current); F.CloseMethod(F.Block(F.Return(F.InstanceField(_currentField)))); } private void GenerateIValueTaskSourceBoolImplementation_GetResult() { // Produce the implementation for `bool IValueTaskSource.GetResult(short token)`: // return _valueOrEndPromise.GetResult(token); NamedTypeSymbol IValueTaskSourceOfBool = F.WellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource_T) .Construct(F.SpecialType(SpecialType.System_Boolean)); MethodSymbol IValueTaskSourceOfBool_GetResult = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource_T__GetResult) .AsMember(IValueTaskSourceOfBool); MethodSymbol promise_GetResult = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__GetResult) .AsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type); // The implementation doesn't depend on the method body of the iterator method. OpenMethodImplementation(IValueTaskSourceOfBool_GetResult, hasMethodBodyDependency: false); // return this._valueOrEndPromise.GetResult(token); F.CloseMethod(F.Return( F.Call(F.InstanceField(_promiseOfValueOrEndField), promise_GetResult, F.Parameter(IValueTaskSourceOfBool_GetResult.Parameters[0])))); } private void GenerateIValueTaskSourceBoolImplementation_GetStatus() { // Produce the implementation for `ValueTaskSourceStatus IValueTaskSource.GetStatus(short token)`: // return this._valueOrEndPromise.GetStatus(token); NamedTypeSymbol IValueTaskSourceOfBool = F.WellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource_T) .Construct(F.SpecialType(SpecialType.System_Boolean)); MethodSymbol IValueTaskSourceOfBool_GetStatus = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource_T__GetStatus) .AsMember(IValueTaskSourceOfBool); MethodSymbol promise_GetStatus = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__GetStatus) .AsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type); // The implementation doesn't depend on the method body of the iterator method. OpenMethodImplementation(IValueTaskSourceOfBool_GetStatus, hasMethodBodyDependency: false); // return this._valueOrEndPromise.GetStatus(token); F.CloseMethod(F.Return( F.Call(F.InstanceField(_promiseOfValueOrEndField), promise_GetStatus, F.Parameter(IValueTaskSourceOfBool_GetStatus.Parameters[0])))); } private void GenerateIValueTaskSourceBoolImplementation_OnCompleted() { // Produce the implementation for `void IValueTaskSource.OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)`: // this._valueOrEndPromise.OnCompleted(continuation, state, token, flags); // return; NamedTypeSymbol IValueTaskSourceOfBool = F.WellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource_T) .Construct(F.SpecialType(SpecialType.System_Boolean)); MethodSymbol IValueTaskSourceOfBool_OnCompleted = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource_T__OnCompleted) .AsMember(IValueTaskSourceOfBool); MethodSymbol promise_OnCompleted = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__OnCompleted) .AsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type); // The implementation doesn't depend on the method body of the iterator method. OpenMethodImplementation(IValueTaskSourceOfBool_OnCompleted, hasMethodBodyDependency: false); F.CloseMethod(F.Block( // this._valueOrEndPromise.OnCompleted(continuation, state, token, flags); F.ExpressionStatement( F.Call(F.InstanceField(_promiseOfValueOrEndField), promise_OnCompleted, F.Parameter(IValueTaskSourceOfBool_OnCompleted.Parameters[0]), F.Parameter(IValueTaskSourceOfBool_OnCompleted.Parameters[1]), F.Parameter(IValueTaskSourceOfBool_OnCompleted.Parameters[2]), F.Parameter(IValueTaskSourceOfBool_OnCompleted.Parameters[3]))), F.Return())); // return; } private void GenerateIValueTaskSourceImplementation_GetResult() { // Produce an implementation for `void IValueTaskSource.GetResult(short token)`: // this._valueOrEndPromise.GetResult(token); // return; MethodSymbol IValueTaskSource_GetResult = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource__GetResult); MethodSymbol promise_GetResult = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__GetResult) .AsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type); // The implementation doesn't depend on the method body of the iterator method. OpenMethodImplementation(IValueTaskSource_GetResult, hasMethodBodyDependency: false); F.CloseMethod(F.Block( // this._valueOrEndPromise.GetResult(token); F.ExpressionStatement(F.Call(F.InstanceField(_promiseOfValueOrEndField), promise_GetResult, F.Parameter(IValueTaskSource_GetResult.Parameters[0]))), // return; F.Return())); } // Consider factoring with IValueTaskSource implementation // See https://github.com/dotnet/roslyn/issues/31517 private void GenerateIValueTaskSourceImplementation_GetStatus() { // Produce the implementation for `ValueTaskSourceStatus IValueTaskSource.GetStatus(short token)`: // return this._valueOrEndPromise.GetStatus(token); MethodSymbol IValueTaskSource_GetStatus = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource__GetStatus); MethodSymbol promise_GetStatus = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__GetStatus) .AsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type); // The implementation doesn't depend on the method body of the iterator method. OpenMethodImplementation(IValueTaskSource_GetStatus, hasMethodBodyDependency: false); // return this._valueOrEndPromise.GetStatus(token); F.CloseMethod(F.Return( F.Call(F.InstanceField(_promiseOfValueOrEndField), promise_GetStatus, F.Parameter(IValueTaskSource_GetStatus.Parameters[0])))); } // Consider factoring with IValueTaskSource implementation // See https://github.com/dotnet/roslyn/issues/31517 private void GenerateIValueTaskSourceImplementation_OnCompleted() { // Produce the implementation for `void IValueTaskSource.OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)`: // this._valueOrEndPromise.OnCompleted(continuation, state, token, flags); // return; MethodSymbol IValueTaskSource_OnCompleted = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_IValueTaskSource__OnCompleted); MethodSymbol promise_OnCompleted = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__OnCompleted) .AsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type); // The implementation doesn't depend on the method body of the iterator method. OpenMethodImplementation(IValueTaskSource_OnCompleted, hasMethodBodyDependency: false); F.CloseMethod(F.Block( // this._valueOrEndPromise.OnCompleted(continuation, state, token, flags); F.ExpressionStatement( F.Call(F.InstanceField(_promiseOfValueOrEndField), promise_OnCompleted, F.Parameter(IValueTaskSource_OnCompleted.Parameters[0]), F.Parameter(IValueTaskSource_OnCompleted.Parameters[1]), F.Parameter(IValueTaskSource_OnCompleted.Parameters[2]), F.Parameter(IValueTaskSource_OnCompleted.Parameters[3]))), F.Return())); // return; } /// /// Generates the GetAsyncEnumerator method. /// private void GenerateIAsyncEnumerableImplementation_GetAsyncEnumerator() { NamedTypeSymbol IAsyncEnumerableOfElementType = F.WellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T) .Construct(_currentField.Type); MethodSymbol IAsyncEnumerableOfElementType_GetEnumerator = F.WellKnownMethod(WellKnownMember.System_Collections_Generic_IAsyncEnumerable_T__GetAsyncEnumerator) .AsMember(IAsyncEnumerableOfElementType); BoundExpression managedThreadId = null; GenerateIteratorGetEnumerator(IAsyncEnumerableOfElementType_GetEnumerator, ref managedThreadId, initialState: StateMachineStates.InitialAsyncIteratorStateMachine); } protected override void GenerateResetInstance(ArrayBuilder builder, int initialState) { // this.state = {initialState}; // this.builder = System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create(); // this.disposeMode = false; builder.Add( // this.state = {initialState}; F.Assignment(F.Field(F.This(), stateField), F.Literal(initialState))); builder.Add( // this.builder = System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create(); GenerateCreateAndAssignBuilder()); builder.Add( // disposeMode = false; F.Assignment(F.InstanceField(_disposeModeField), F.Literal(false))); } protected override void GenerateMoveNext(SynthesizedImplementationMethod moveNextMethod) { MethodSymbol setResultMethod = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__SetResult, isOptional: true); if ((object)setResultMethod != null) { setResultMethod = (MethodSymbol)setResultMethod.SymbolAsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type); } MethodSymbol setExceptionMethod = F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T__SetException, isOptional: true); if ((object)setExceptionMethod != null) { setExceptionMethod = (MethodSymbol)setExceptionMethod.SymbolAsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type); } var rewriter = new AsyncIteratorMethodToStateMachineRewriter( method: method, methodOrdinal: _methodOrdinal, asyncMethodBuilderMemberCollection: _asyncMethodBuilderMemberCollection, asyncIteratorInfo: new AsyncIteratorInfo(_promiseOfValueOrEndField, _combinedTokensField, _currentField, _disposeModeField, setResultMethod, setExceptionMethod), F: F, state: stateField, builder: _builderField, hoistedVariables: hoistedVariables, nonReusableLocalProxies: nonReusableLocalProxies, synthesizedLocalOrdinals: synthesizedLocalOrdinals, slotAllocatorOpt: slotAllocatorOpt, nextFreeHoistedLocalSlot: nextFreeHoistedLocalSlot, diagnostics: diagnostics); rewriter.GenerateMoveNext(body, moveNextMethod); } } } }