diff --git a/standard/statements.md b/standard/statements.md index a8fc58a60..1aba8eb35 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -1127,7 +1127,16 @@ The compile-time processing of a `foreach` statement first determines the ***col - If among all the types `Tᵢ` for which there is an implicit conversion from `X` to `IEnumerable`, there is a unique type `T` such that `T` is not `dynamic` and for all the other `Tᵢ` there is an implicit conversion from `IEnumerable` to `IEnumerable`, then the collection type is the interface `IEnumerable`, the enumerator type is the interface `IEnumerator`, and the iteration type is `T`. - Otherwise, if there is more than one such type `T`, then an error is produced and no further steps are taken. - Otherwise, 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. + - Otherwise, determine whether the type 'X' has an appropriate `GetEnumerator` extension method: + - Perform extension method lookup on the type `X` with identifier `GetEnumerator`. If the member lookup does not produce a match, or it produces an ambiguity, or produces a match which is not a method group, an error is produced, and no further steps are taken. It is recommended that a warning be issued if member lookup produces anything except a method group or no match. + - Perform overload resolution using the resulting method group and a single argument of type `X`. If overload resolution produces no applicable methods, results in an ambiguity, or results in a single best method but that method is not accessible, an error is produced an no further steps are taken. + - This resolution permits the first argument to be passed by ref if `X` is a struct type, and the ref kind is `in`. + - If the return type `E` of the `GetEnumerator` method is not a class, struct or interface type, an error is produced, and no further steps are taken. + - Member lookup is performed on `E` with the identifier `Current` and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a public instance property that permits reading, an error is produced, and no further steps are taken. + - Member lookup is performed on `E` with the identifier `MoveNext` and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a method group, an error is produced, and no further steps are taken. + - Overload resolution is performed on the method group with an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, or its return type is not `bool`, an error is produced, and no further steps are taken. + - The collection type is `X`, the enumerator type is `E`, and the iteration type is the type of the `Current` property. + - Otherwise, an error is produced, and no further steps are taken. The above steps, if successful, unambiguously produce a collection type `C`, enumerator type `E` and iteration type `T`, `ref T`, or `ref readonly T`. A `foreach` statement of the form