diff --git a/standard/classes.md b/standard/classes.md index b4b75ec21..fee46b164 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -5886,6 +5886,78 @@ When a function is implemented using an iterator block, it is a compile-time err An asynchronous iterator shall support cancellation of the asynchronous operation. This is described in [§23.5.8](attributes.md#2358-the-enumeratorcancellation-attribute). +Rather than using a task builder type based on the *return_type* of an async method, the attribute `AsyncMethodBuilder` can be applied to that method to indicate a different task builder type. + +It is an error to apply this attribute to a lambda with an implicit return type. + +The ability to provide an alternate builder type shall not be used when the synthesized entry-point for top-level statements is async ([§7.1.3](basic-concepts.md#713-using-top-level-statements)). For that, an explicit entry-point is needed. + +When an async method is compiled, the builder type is determined by: + +1. Using the builder type from the `AsyncMethodBuilder` attribute, if one is present; +1. Otherwise, falling back to the builder type determined by the method’s *return_type*. + +If an `AsyncMethodBuilder` attribute is present, the builder type specified by that attribute is constructed, if necessary. + +If the override type is an open generic type, take the single type argument of the async method's return type and substitute it into the override type. + +If the override type is a bound generic type, then an error results. + +If the async method's return type does not have a single type argument, an error results. + +To verify that the builder type is compatible with *return_type* of the async method: + +1. Look for the public `Create` method with no type parameters and no parameters on the constructed builder type. It is an error if the method is not found, or if the method returns a type other than the constructed builder type. +1. Look for the public `Task` property. It is an error if the property is not found. +1. Consider the type of that `Task` property (a task-like type). It is an error if the task-like type does not match the *return_type* of the async method. (It is not necessary for *return_type* to be a task-like type.) + +Consider the following code fragment: + +```csharp +public async ValueTask ExampleAsync() { … } +``` + +This will be compiled to something like the following: + +```csharp +[AsyncStateMachine(typeof(d__29))] +[CompilerGenerated] +static ValueTask ExampleAsync() +{ + d__29 stateMachine; + stateMachine.<>t__builder + = AsyncValueTaskMethodBuilder.Create(); + stateMachine.<>1__state = -1; + stateMachine.<>t__builder.Start(ref stateMachine); + return stateMachine.<>t__builder.Task; +} +``` + +However, the following code fragment: + +```csharp +[AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] +static async ValueTask ExampleAsync() { … } +``` + +in which the attribute `AsyncMethodBuilder` is applied to that method, would instead be compiled to something like: + +```csharp +[AsyncStateMachine(typeof(d__29))] +[CompilerGenerated] +[AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] +static ValueTask ExampleAsync() +{ + d__29 stateMachine; + stateMachine.<>t__builder + = PoolingAsyncValueTaskMethodBuilder.Create(); + // <>t__builder now a different type + stateMachine.<>1__state = -1; + stateMachine.<>t__builder.Start(ref stateMachine); + return stateMachine.<>t__builder.Task; +} +``` + ### 15.15.2 Enumerator interfaces The ***enumerator interface***s are the non-generic interface `System.Collections.IEnumerator` and the generic interface `System.Collections.Generic.IEnumerator`. diff --git a/standard/standard-library.md b/standard/standard-library.md index 5c46468f3..fa74a9a04 100644 --- a/standard/standard-library.md +++ b/standard/standard-library.md @@ -785,7 +785,7 @@ namespace System.Linq.Expressions namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | - AttributeTargets.Interface, + AttributeTargets.Interface | AttributeTargets.Method, Inherited = false, AllowMultiple = false)] public sealed class AsyncMethodBuilderAttribute : Attribute {