Skip to content

Commit d27938f

Browse files
committed
Remove restrictions on iterators
Remove or annotate any restrictions on iterator methods for `ref` and `unsafe` sections of the language reference.
1 parent 0ee6961 commit d27938f

File tree

5 files changed

+38
-8
lines changed

5 files changed

+38
-8
lines changed

docs/csharp/language-reference/builtin-types/ref-struct.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "ref struct types"
33
description: Learn about the ref struct type in C#
4-
ms.date: 10/12/2022
4+
ms.date: 06/28/2024
55
---
66
# `ref` structure types (C# reference)
77

@@ -14,7 +14,7 @@ You can use the `ref` modifier in the declaration of a [structure type](struct.m
1414
- A `ref struct` can't be a type argument.
1515
- A `ref struct` variable can't be captured by a [lambda expression](../operators/lambda-expressions.md) or a [local function](../../programming-guide/classes-and-structs/local-functions.md).
1616
- A `ref struct` variable can't be used in an [`async`](../keywords/async.md) method. However, you can use `ref struct` variables in synchronous methods, for example, in methods that return <xref:System.Threading.Tasks.Task> or <xref:System.Threading.Tasks.Task%601>.
17-
- A `ref struct` variable can't be used in [iterators](../../iterators.md).
17+
- Prior to C# 13, a `ref struct` variable can't be used in [iterators](../../iterators.md). Beginning with C# 13, `ref struct` types and `ref` locals may be used in iterators, provided they are not in code segments with the `yield return` statement.
1818

1919
You can define a disposable `ref struct`. To do that, ensure that a `ref struct` fits the [disposable pattern](~/_csharplang/proposals/csharp-8.0/using.md#pattern-based-using). That is, it has an instance `Dispose` method, which is accessible, parameterless and has a `void` return type. You can use the [using statement or declaration](../statements/using.md) with an instance of a disposable `ref struct`.
2020

docs/csharp/language-reference/compiler-messages/cs4013.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
description: "Compiler Error CS4013"
33
title: "Compiler Error CS4013"
4-
ms.date: 9/12/2022
4+
ms.date: 06/28/2024
55
f1_keywords:
66
- "CS4013"
77
helpviewer_keywords:
@@ -11,6 +11,8 @@ helpviewer_keywords:
1111

1212
Instance of type cannot be used inside a nested function, query expression, iterator block or async method
1313

14+
Beginning with C# 13, `ref struct` types can be used in iterator methods, provided that they are not in scope during a `yield return` statement.
15+
1416
## Example
1517

1618
The following sample generates CS4013:
@@ -34,7 +36,7 @@ public class C
3436
}
3537
```
3638

37-
This enumerator method extracts lines of text from a character array. It naively tries to use `ReadOnlySpan<T>` to improve performance.
39+
This enumerator method extracts lines of text from a character array. It naively tries to use `ReadOnlySpan<T>` to improve performance. The preceding example exhibits the same error in C# 13, because the `ReadOnlySpan` instance `chars` is in scope at the `yield return` statement.
3840

3941
## To correct this error
4042

@@ -75,3 +77,27 @@ To continue to use an iterator function, to correct this error, the method must
7577
yield return new string(chars, startIndex, chars.Length - startIndex);
7678
}
7779
```
80+
81+
In C# 13, a `ReadOnlySpan` can be used, but can only be used in code segments without a `yield return`:
82+
83+
```csharp
84+
static IEnumerable<string> Lines2(char[] text)
85+
{
86+
ReadOnlySpan<char> chars = text;
87+
88+
var lines = new List<string>();
89+
var index = chars.IndexOf('\n');
90+
while (index > 0)
91+
{
92+
lines.Add(chars[..index].ToString());
93+
chars = chars[(index + 1)..];
94+
index = chars.IndexOf('\n');
95+
}
96+
97+
lines.Add(chars.ToString());
98+
foreach(var line in lines)
99+
{
100+
yield return line;
101+
}
102+
}
103+
```

docs/csharp/language-reference/compiler-messages/cs8176.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
description: "Compiler Error CS8176"
33
title: "Compiler Error CS8176"
4-
ms.date: 9/19/2022
4+
ms.date: 06/28/2024
55
f1_keywords:
66
- "CS8176"
77
helpviewer_keywords:
@@ -13,6 +13,8 @@ Iterators cannot have by-reference locals
1313

1414
Iterator blocks use deferred execution, where the evaluation of an expression is delayed until its realized value is actually required. To manage that deferred execution state, iterator blocks use a state machine, capturing variable state in closures implemented in compiler-generated classes and properties. A local variable reference (on the stack) cannot be captured within the instance of a class in the heap, so the compiler issues an error.
1515

16+
Beginning with C# 13, this restriction was removed.
17+
1618
## Example
1719

1820
The following sample generates CS8176:

docs/csharp/language-reference/statements/yield.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "yield statement - provide the next element in an iterator"
33
description: "Use the yield statement in iterators to provide the next value or signal the end of an iteration"
4-
ms.date: 11/22/2022
4+
ms.date: 06/28/2024
55
f1_keywords:
66
- "yield"
77
- "yield_CSharpKeyword"
@@ -37,7 +37,7 @@ You can't use the `yield` statements in:
3737

3838
- methods with [in](../keywords/method-parameters.md#in-parameter-modifier), [ref](../keywords/ref.md), or [out](../keywords/method-parameters.md#out-parameter-modifier) parameters
3939
- [lambda expressions](../operators/lambda-expressions.md) and [anonymous methods](../operators/delegate-operator.md)
40-
- methods that contain [unsafe blocks](../keywords/unsafe.md)
40+
- [unsafe blocks](../keywords/unsafe.md). Prior to C# 13, `yield` was invalid in any method with an `unsafe` block. Beginning with C# 13, you can use `yield` in methods with `unsafe` blocks, but not in the `unsafe` block.
4141

4242
## Execution of an iterator
4343

docs/csharp/misc/cs1629.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
description: "Compiler Error CS1629"
33
title: "Compiler Error CS1629"
4-
ms.date: 07/20/2015
4+
ms.date: 06/28/2024
55
f1_keywords:
66
- "CS1629"
77
helpviewer_keywords:
@@ -11,6 +11,8 @@ ms.assetid: 907eae46-0265-4cd0-b27b-ff555d004259
1111
# Compiler Error CS1629
1212

1313
Unsafe code may not appear in iterators
14+
15+
This restriction is relaxed in C# 13. You can use `unsafe` blocks, but the `yield return` statement can't be used in an `unsafe` block.
1416

1517
The C# language specification does not allow unsafe code in iterators.
1618

0 commit comments

Comments
 (0)