diff --git a/standard/README.md b/standard/README.md index f69577501..094fed2b5 100644 --- a/standard/README.md +++ b/standard/README.md @@ -493,6 +493,8 @@ - [§13.12](statements.md#1312-the-checked-and-unchecked-statements) The checked and unchecked statements - [§13.13](statements.md#1313-the-lock-statement) The lock statement - [§13.14](statements.md#1314-the-using-statement) The using statement + - [§13.14.1](statements.md#13141-general) General + - [§13.14.2](statements.md#13142-using-declaration) Using declaration - [§13.15](statements.md#1315-the-yield-statement) The yield statement - [§14](namespaces.md#14-namespaces) Namespaces - [§14.1](namespaces.md#141-general) General @@ -771,6 +773,7 @@ - [§23.5.7.8](attributes.md#23578-the-notnull-attribute) The NotNull attribute - [§23.5.7.9](attributes.md#23579-the-notnullifnotnull-attribute) The NotNullIfNotNull attribute - [§23.5.7.10](attributes.md#235710-the-notnullwhen-attribute) The NotNullWhen attribute + - [§23.5.8](attributes.md#2358-the-enumeratorcancellation-attribute) The EnumeratorCancellation attribute - [§23.6](attributes.md#236-attributes-for-interoperation) Attributes for interoperation - [§24](unsafe-code.md#24-unsafe-code) Unsafe code - [§24.1](unsafe-code.md#241-general) General diff --git a/standard/attributes.md b/standard/attributes.md index c58c3966c..b3cd07a51 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -495,7 +495,7 @@ A number of attributes affect the language in some way. These attributes include - `System.ObsoleteAttribute` ([§23.5.4](attributes.md#2354-the-obsolete-attribute)), which is used to mark a member as obsolete. - `System.Runtime.CompilerServices.AsyncMethodBuilderAttribute` ([§23.5.5](attributes.md#2355-the-asyncmethodbuilder-attribute)), which is used to establish a task builder for an async method. - `System.Runtime.CompilerServices.CallerLineNumberAttribute` ([§23.5.6.2](attributes.md#23562-the-callerlinenumber-attribute)), `System.Runtime.CompilerServices.CallerFilePathAttribute` ([§23.5.6.3](attributes.md#23563-the-callerfilepath-attribute)), and `System.Runtime.CompilerServices.CallerMemberNameAttribute` ([§23.5.6.4](attributes.md#23564-the-callermembername-attribute)), which are used to supply information about the calling context to optional parameters. -- `System.Runtime.CompilerServices.EnumeratorCancellationAttribute` (§enumerator-cancellation), which is used to specify parameter for the cancellation token in an asynchronous iterator. +- `System.Runtime.CompilerServices.EnumeratorCancellationAttribute` ([§23.5.8](attributes.md#2358-the-enumeratorcancellation-attribute)), which is used to specify parameter for the cancellation token in an asynchronous iterator. The Nullable static analysis attributes ([§23.5.7](attributes.md#2357-code-analysis-attributes)) can improve the correctness of warnings generated for nullabilities and null states ([§8.9.5](types.md#895-nullabilities-and-null-states)). @@ -1061,17 +1061,17 @@ Specifies that a nullable argument won’t be `null` when the method returns the > > *end example* -### §enumerator-cancellation The EnumeratorCancellation attribute +### 23.5.8 The EnumeratorCancellation attribute -Specifies the parameter representing the `CancellationToken` for an asynchronous iterator (§15.15). The argument for this parameter shall be combined with the argument passed to `IAsyncEnumerable.GetAsyncEnumerator(CancellationToken)`. This combined token shall be polled by `IAsyncEnumerator.MoveNextAsync()` (§15.15.5.2). The tokens shall be combined into a single token as if by `CancellationToken.CreateLinkedTokenSource` and its `Token` property. The combined token will be canceled if either of the two source tokens are canceled. The combined token is seen as the argument to the asynchronous iterator method (§15.15) in the body of that method. +Specifies the parameter representing the `CancellationToken` for an asynchronous iterator ([§15.15](classes.md#1515-synchronous-and-asynchronous-iterators)). The argument for this parameter shall be combined with the argument passed to `IAsyncEnumerable.GetAsyncEnumerator(CancellationToken)`. This combined token shall be polled by `IAsyncEnumerator.MoveNextAsync()` ([§15.15.5.2](classes.md#151552-advance-the-enumerator)). The tokens shall be combined into a single token as if by `CancellationToken.CreateLinkedTokenSource` and its `Token` property. The combined token will be canceled if either of the two source tokens are canceled. The combined token is seen as the argument to the asynchronous iterator method ([§15.15](classes.md#1515-synchronous-and-asynchronous-iterators)) in the body of that method. It is an error if the `System.Runtime.CompilerServices.EnumeratorCancellation` attribute is applied to more than one parameter. The compiler may produce a warning if: - The `EnumeratorCancellation` attribute is applied to a parameter of a type other than `CancellationToken`, -- or if the `EnumeratorCancellation` attribute is applied to a parameter on a method that isn't an asynchronous iterator (§15.15), +- or if the `EnumeratorCancellation` attribute is applied to a parameter on a method that isn’t an asynchronous iterator ([§15.15](classes.md#1515-synchronous-and-asynchronous-iterators)), - or if the `EnumeratorCancellation` attribute is applied to a parameter on a method that returns an asynchronous enumerable interface ([§15.15.3](classes.md#15153-enumerable-interfaces)) rather than an asynchronous enumerator interface ([§15.15.2](classes.md#15152-enumerator-interfaces)). -The iterator won't have access to the `CancellationToken` argument for `GetAsyncEnumerator` when no attributes have this parameter. +The iterator won’t have access to the `CancellationToken` argument for `GetAsyncEnumerator` when no attributes have this parameter. > *Example*: The method `GetStringsAsync()` is an asynchronous iterator. Before doing any work to retrieve the next value, it checks the cancellation token to determine if the iteration should be canceled. If cancellation is requested, no further action is taken. > diff --git a/standard/classes.md b/standard/classes.md index 60fd3be06..79820d0bb 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -5504,7 +5504,7 @@ An iterator block may occur as a *method_body*, *operator_body* or *accessor_bod When a function is implemented using an iterator block, it is a compile-time error for the parameter list of the function to specify any `in`, `out`, or `ref` parameters, or a parameter of a `ref struct` type. -An asynchronous iterator shall support cancellation of the asynchronous operation. This is described in §enumerator-cancellation. +An asynchronous iterator shall support cancellation of the asynchronous operation. This is described in [§23.5.8](attributes.md#2358-the-enumeratorcancellation-attribute). ### 15.15.2 Enumerator interfaces @@ -5575,7 +5575,7 @@ The precise action performed by `MoveNext` or `MoveNextAsync` depends on the sta When `MoveNext` executes the iterator block, execution can be interrupted in four ways: By a `yield return` statement, by a `yield break` statement, by encountering the end of the iterator block, and by an exception being thrown and propagated out of the iterator block. -> *Note*: `MoveNextAsync` is suspended if it evaluates an `await` expression that awaits a task type that hasn't completed. *end note* +> *Note*: `MoveNextAsync` is suspended if it evaluates an `await` expression that awaits a task type that hasn’t completed. *end note* - When a `yield return` statement is encountered ([§9.4.4.20](variables.md#94420-yield-statements)): - The expression given in the statement is evaluated, implicitly converted to the yield type, and assigned to the `Current` property of the enumerator object. @@ -5622,7 +5622,7 @@ The `Dispose` or `DisposeAsync` method is used to clean up the iteration by brin When a function member or local function returning an enumerable interface type or an async enumerable interface type is implemented using an iterator block, invoking the function does not immediately execute the code in the iterator block. Instead, an ***enumerable object*** is created and returned. -A synchronous enumerable object implements `IEnumerable` and `IEnumerable`, where `T` is the yield type of the iterator. Its `GetEnumerator` method returns an enumerator object (§15.15.5). An async enumerable object implements `IAsyncEnumerable` where `T` is the yield type of the iterator. Its `GetAsyncEnumerator` method returns an asynchronous enumerator object (§15.15.5). +A synchronous enumerable object implements `IEnumerable` and `IEnumerable`, where `T` is the yield type of the iterator. Its `GetEnumerator` method returns an enumerator object ([§15.15.5](classes.md#15155-enumerator-objects)). An async enumerable object implements `IAsyncEnumerable` where `T` is the yield type of the iterator. Its `GetAsyncEnumerator` method returns an asynchronous enumerator object ([§15.15.5](classes.md#15155-enumerator-objects)). An enumerable object is initialized with a copy of the argument values (if any) and instance value passed to the function. @@ -5636,4 +5636,4 @@ An enumerable object may implement more interfaces than those specified above. An enumerable object provides an implementation of the `GetEnumerator` methods of the `IEnumerable` and `IEnumerable` interfaces. The two `GetEnumerator` methods share a common implementation that acquires and returns an available enumerator object. The enumerator object is initialized with the argument values and instance value saved when the enumerable object was initialized, but otherwise the enumerator object functions as described in [§15.15.5](classes.md#15155-enumerator-objects). -An asynchronous enumerable object provides an implementation of the `GetAsyncEnumerator` method of the `IAsyncEnumerable` interface. This method returns an available asynchronous enumerator object. The enumerator object is initialized with the argument values and instance value saved when the enumerable object was initialized, including the optional cancellation token, but otherwise the enumerator object functions as described in [§15.15.5](classes.md#15155-enumerator-objects). An asynchronous iterator method can mark one parameter as the cancellation token using `System.Runtime.CompilerServices.EnumeratorCancellationAttribute` (§enumerator-cancellation). An implementation shall provide a mechanism to combine cancellation tokens such that an asynchronous iterator is canceled when either cancellation token (the argument to `GetAsyncEnumerator` or the argument attributed with the attribute `System.Runtime.CompilerServices.EnumeratorCancellationAttribute`) requests cancellation. +An asynchronous enumerable object provides an implementation of the `GetAsyncEnumerator` method of the `IAsyncEnumerable` interface. This method returns an available asynchronous enumerator object. The enumerator object is initialized with the argument values and instance value saved when the enumerable object was initialized, including the optional cancellation token, but otherwise the enumerator object functions as described in [§15.15.5](classes.md#15155-enumerator-objects). An asynchronous iterator method can mark one parameter as the cancellation token using `System.Runtime.CompilerServices.EnumeratorCancellationAttribute` ([§23.5.8](attributes.md#2358-the-enumeratorcancellation-attribute)). An implementation shall provide a mechanism to combine cancellation tokens such that an asynchronous iterator is canceled when either cancellation token (the argument to `GetAsyncEnumerator` or the argument attributed with the attribute `System.Runtime.CompilerServices.EnumeratorCancellationAttribute`) requests cancellation. diff --git a/standard/grammar.md b/standard/grammar.md index cc8de540b..37cb0cd9e 100644 --- a/standard/grammar.md +++ b/standard/grammar.md @@ -1838,16 +1838,26 @@ lock_statement : 'lock' '(' expression ')' embedded_statement ; -// Source: §13.14 The using statement +// Source: §13.14.1 General using_statement - : 'using' '(' resource_acquisition ')' embedded_statement + : 'await'? 'using' '(' resource_acquisition ')' embedded_statement ; resource_acquisition - : local_variable_declaration + : non_ref_local_variable_declaration | expression ; +non_ref_local_variable_declaration + : implicitly_typed_local_variable_declaration + | explicitly_typed_local_variable_declaration + ; + +// Source: §13.14.2 Using declaration +using_declaration + : 'await'? 'using' non_ref_local_variable_declaration ';' statement_list? + ; + // Source: §13.15 The yield statement yield_statement : 'yield' 'return' expression ';' diff --git a/standard/statements.md b/standard/statements.md index aa336b7a3..8f2f8cfb6 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -1114,7 +1114,7 @@ The iteration variable corresponds to a local variable with a scope that extends The compile-time processing of a `foreach` statement first determines the ***collection type*** (`C`), ***enumerator type*** (`E`) and ***iteration type*** (`T`, `ref T` or `ref readonly T`) of the expression. -The determination is similar for the synchronous and asynchronous versions. Different interfaces with different methods and return types distinguish the synchronous and asynchronous versions. The general process proceeds as follows. Names within '«' and '»' are placeholders for the actual names for synchronous and asynchronous iterators. The types allowed for «GetEnumerator», «MoveNext», «IEnumerable»\, «IEnumerator»\, and any other distinctions are detailed in [§13.9.5.2](statements.md#13952-synchronous-foreach) for a synchronous `foreach` statement, and in [§13.9.5.3](statements.md#13953-await-foreach) for an asynchronous `foreach` statement. +The determination is similar for the synchronous and asynchronous versions. Different interfaces with different methods and return types distinguish the synchronous and asynchronous versions. The general process proceeds as follows. Names within ‘«’ and ‘»’ are placeholders for the actual names for synchronous and asynchronous iterators. The types allowed for «GetEnumerator», «MoveNext», «IEnumerable»\, «IEnumerator»\, and any other distinctions are detailed in [§13.9.5.2](statements.md#13952-synchronous-foreach) for a synchronous `foreach` statement, and in [§13.9.5.3](statements.md#13953-await-foreach) for an asynchronous `foreach` statement. 1. Determine whether the type `X` has an appropriate «GetEnumerator» method: 1. Perform member lookup on the type `X` with identifier «GetEnumerator» and no type arguments. If the member lookup does not produce a match, or it produces an ambiguity, or produces a match that is not a method group, check for an enumerable interface as described in step 2. It is recommended that a warning be issued if member lookup produces anything except a method group or no match. @@ -1130,25 +1130,25 @@ The determination is similar for the synchronous and asynchronous versions. Diff > *Note*: If *expression* has the value `null`, a `System.NullReferenceException` is thrown at run-time. *end note* -An implementation is permitted to implement a given *foreach_statement* differently; e.g., for performance reasons, as long as the behavior is consistent with the expansions described in §13.9.5.2 and §13.9.5.3. +An implementation is permitted to implement a given *foreach_statement* differently; e.g., for performance reasons, as long as the behavior is consistent with the expansions described in [§13.9.5.2](statements.md#13952-synchronous-foreach) and [§13.9.5.3](statements.md#13953-await-foreach). #### 13.9.5.2 Synchronous foreach -A synchronous `foreach` does not include the `await` keyword before the `foreach` keyword. The determination of ***collection type***, ***enumeration type*** and ***iteration type*** proceeds as described in §13.9.5.1, where: +A synchronous `foreach` does not include the `await` keyword before the `foreach` keyword. The determination of ***collection type***, ***enumeration type*** and ***iteration type*** proceeds as described in [§13.9.5.1](statements.md#13951-general), where: - «GetEnumerator» is a `GetEnumerator` method. - «MoveNext» is a `MoveNext` method with a `bool` return type. - «IEnumerable»\ is the `System.Collections.Generic.IEnumerable` interface. - «IEnumerator»\ is the `System.Collections.Generic.IEnumerator` interface. -In addition, the following modifications are made to the steps in §13.9.5.1: +In addition, the following modifications are made to the steps in [§13.9.5.1](statements.md#13951-general): -Before the process described in §13.9.5.1, the following steps are taken: +Before the process described in [§13.9.5.1](statements.md#13951-general), the following steps are taken: -- If the type `X` of *expression* is an array type then there is an implicit reference conversion from `X` to the `IEnumerable` interface where `T` is the element type of the array `X` (§17.2.3). +- If the type `X` of *expression* is an array type then there is an implicit reference conversion from `X` to the `IEnumerable` interface where `T` is the element type of the array `X` ([§17.2.3](arrays.md#1723-arrays-and-the-generic-collection-interfaces)). - If the type `X` of *expression* is `dynamic` then there is an implicit conversion from *expression* to the `IEnumerable` interface ([§10.2.10](conversions.md#10210-implicit-dynamic-conversions)). The collection type is the `IEnumerable` interface and the enumerator type is the `IEnumerator` interface. If the `var` identifier is given as the *local_variable_type* then the iteration type is `dynamic`, otherwise it is `object`. -If the process in §13.9.5.1 completes without producing a single collection type, enumerator type, and iteration type, the following steps are taken: +If the process in [§13.9.5.1](statements.md#13951-general) completes without producing a single collection type, enumerator type, and iteration type, the following steps are taken: - If there is an implicit conversion from `X` to the `System.Collections.IEnumerable` interface, then the collection type is this interface, the enumerator type is the interface `System.Collections.IEnumerator`, and the iteration type is `object`. - Otherwise, an error is produced, and no further steps are taken. @@ -1331,14 +1331,14 @@ The order in which `foreach` traverses the elements of an array, is as follows: #### 13.9.5.3 await foreach -An asynchronous foreach uses the `await foreach` syntax. The determination of ***collection type***, ***enumeration type*** and ***iteration type*** proceeds as described in §13.9.5.1, where: +An asynchronous foreach uses the `await foreach` syntax. The determination of ***collection type***, ***enumeration type*** and ***iteration type*** proceeds as described in [§13.9.5.1](statements.md#13951-general), where: -- «GetEnumerator» is a `GetEnumeratorAsync` method that has an awaitable return type (§12.9.9.2). +- «GetEnumerator» is a `GetEnumeratorAsync` method that has an awaitable return type ([§12.9.9.2](expressions.md#12992-awaitable-expressions)). - «MoveNext» is a `MoveNextAsync` method that has an awaitable return type ([§12.9.9.2](expressions.md#12992-awaitable-expressions)) where the *await_expression* is classified as a `bool` ([§12.9.9.3](expressions.md#12993-classification-of-await-expressions)). - «IEnumerable»\ is the `System.Collections.Generic.IAsyncEnumerable` interface. - «IEnumerator»\ is the `System.Collections.Generic.IAsyncEnumerator` interface. -It is an error for the ***iteration type*** of an `await foreach` statement to be a reference variable (§9.7). +It is an error for the ***iteration type*** of an `await foreach` statement to be a reference variable ([§9.7](variables.md#97-reference-variables-and-returns)). An `await foreach` statement of the form @@ -1364,11 +1364,11 @@ finally } ``` -In the case where the expression `enumerable` represents a method call expression and one of the parameters is marked with the `EnumeratorCancellationAttribute` (§enumerator-cancellation) the `CancellationToken` is passed to the `GetAsyncEnumerator` method. Other library methods may require a `CancellationToken` is passed to `GetAsyncEnumerator`. When those methods are part of the expression `enumerable`, the tokens shall be combined into a single token as if by `CreateLinkedTokenSource` and its `Token` property. +In the case where the expression `enumerable` represents a method call expression and one of the parameters is marked with the `EnumeratorCancellationAttribute` ([§23.5.8](attributes.md#2358-the-enumeratorcancellation-attribute)) the `CancellationToken` is passed to the `GetAsyncEnumerator` method. Other library methods may require a `CancellationToken` is passed to `GetAsyncEnumerator`. When those methods are part of the expression `enumerable`, the tokens shall be combined into a single token as if by `CreateLinkedTokenSource` and its `Token` property. The body of the `finally` block is constructed according to the following steps: -- If `E` has an accessible `DisposeAsync()` method where the return type is awaitable (§12.9.9.2), the `finally` clause is expanded to the semantic equivalent of: +- If `E` has an accessible `DisposeAsync()` method where the return type is awaitable ([§12.9.9.2](expressions.md#12992-awaitable-expressions)), the `finally` clause is expanded to the semantic equivalent of: ```csharp finally @@ -1417,7 +1417,7 @@ The body of the `finally` block is constructed according to the following steps: The local variable `d` is not visible to or accessible to any user code. In particular, it does not conflict with any other variable whose scope includes the `finally` block. -> *Note*: An `await foreach` is not required to dispose of `e` synchronously if an asynchronous dispose mechanism isn't available. *end note* +> *Note*: An `await foreach` is not required to dispose of `e` synchronously if an asynchronous dispose mechanism isn’t available. *end note* ## 13.10 Jump statements @@ -1907,7 +1907,7 @@ While a mutual-exclusion lock is held, code executing in the same execution thre ## 13.14 The using statement -### §using-general General +### 13.14.1 General The `using` statement obtains one or more resources, executes a statement, and then disposes of the resource. @@ -2102,9 +2102,9 @@ is semantically equivalent to } ``` -> *Note*: Any jump statements (§13.10) in the *embedded_statement* must conform to expanded form of the `using` statement. *end note* +> *Note*: Any jump statements ([§13.10](statements.md#1310-jump-statements)) in the *embedded_statement* must conform to expanded form of the `using` statement. *end note* -### §using-declarations Using declaration +### 13.14.2 Using declaration A syntactic variant of the using statement is a *using declaration*. @@ -2114,7 +2114,7 @@ using_declaration ; ``` -A *using declaration* has the same semantics as, and can be rewritten as, the corresponding resource-acquisition form of the using statement (§using-general), as follows: +A *using declaration* has the same semantics as, and can be rewritten as, the corresponding resource-acquisition form of the using statement ([§13.14.1](statements.md#13141-general)), as follows: ```csharp using «local_variable_type» «local_variable_declarators»