/// <summary> /// Rewrite an async method into a state machine type. /// </summary> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, int methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics, out AsyncStateMachine stateMachineType) { if (!method.IsAsync) { stateMachineType = null; return(body); } CSharpCompilation compilation = method.DeclaringCompilation; bool isAsyncEnumerableOrEnumerator = method.IsIAsyncEnumerableReturningAsync(compilation) || method.IsIAsyncEnumeratorReturningAsync(compilation); if (isAsyncEnumerableOrEnumerator && !method.IsIterator) { bool containsAwait = AwaitDetector.ContainsAwait(body); diagnostics.Add(containsAwait ? ErrorCode.ERR_PossibleAsyncIteratorWithoutYield : ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, method.Locations[0], method.ReturnType); stateMachineType = null; return(body); } // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. // For async-iterators, we also need to generate a class. var typeKind = (compilationState.Compilation.Options.EnableEditAndContinue || method.IsIterator) ? TypeKind.Class : TypeKind.Struct; var bodyWithAwaitLifted = AwaitExpressionSpiller.Rewrite(body, method, compilationState, diagnostics); stateMachineType = new AsyncStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, typeKind); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); AsyncRewriter rewriter = isAsyncEnumerableOrEnumerator ? new AsyncIteratorRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) : new AsyncRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return(body); } try { return(rewriter.Rewrite()); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); return(new BoundBadStatement(body.Syntax, ImmutableArray.Create <BoundNode>(body), hasErrors: true)); } }
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(method.IteratorElementType != null); _isEnumerable = method.IsIAsyncEnumerableReturningAsync(method.DeclaringCompilation); }
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.IsIAsyncEnumerableReturningAsync(method.DeclaringCompilation); Debug.Assert(_isEnumerable != method.IsIAsyncEnumeratorReturningAsync(method.DeclaringCompilation)); }
internal readonly TypeSymbol IteratorElementType; // only for async-iterators public AsyncStateMachine(VariableSlotAllocator variableAllocatorOpt, TypeCompilationState compilationState, MethodSymbol asyncMethod, int asyncMethodOrdinal, TypeKind typeKind) : base(variableAllocatorOpt, compilationState, asyncMethod, asyncMethodOrdinal) { _typeKind = typeKind; CSharpCompilation compilation = asyncMethod.DeclaringCompilation; var interfaces = ArrayBuilder <NamedTypeSymbol> .GetInstance(); bool isIterator = asyncMethod.IsIterator; if (isIterator) { var elementType = TypeMap.SubstituteType(asyncMethod.IteratorElementType).TypeSymbol; this.IteratorElementType = elementType; bool isEnumerable = asyncMethod.IsIAsyncEnumerableReturningAsync(compilation); if (isEnumerable) { // IAsyncEnumerable<TResult> interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T).Construct(elementType)); } // IAsyncEnumerator<TResult> interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T).Construct(elementType)); // IValueTaskSource<bool> interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource_T).Construct(compilation.GetSpecialType(SpecialType.System_Boolean))); // IStrongBox<ManualResetValueTaskSourceLogic<bool>> interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IStrongBox_T).Construct( compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ManualResetValueTaskSourceLogic_T) .Construct(compilation.GetSpecialType(SpecialType.System_Boolean)))); // IAsyncDisposable interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable)); } interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IAsyncStateMachine)); _interfaces = interfaces.ToImmutableAndFree(); _constructor = isIterator ? (MethodSymbol) new IteratorConstructor(this) : new AsyncConstructor(this); }