Incorrect codegen for Debug build with srtp and mutable struct
- Dominant language
- F#
- Stars
- 4.3k
- Forks
- 876
- Avg merge
- 4d 11h
- Merged PRs (30d)
- 131
Description
The showIt function in the following has incorrect code in Debug builds (the bug exists in both F# 7 and 8):
```
open System
open System.Buffers
open System.Text
let inline forEach<'C, 'E, 'I
when 'C: (member GetEnumerator: unit -> 'I)
and 'I: struct
and 'I: (member MoveNext: unit -> bool)
and 'I: (member Current : 'E) >
([] f: 'E -> unit) (container: 'C) =
let mutable iter = container.GetEnumerator()
while iter.MoveNext() do
f iter.Current
let showIt (buffer: ReadOnlySequence) =
buffer |> forEach (fun segment ->
let s = Encoding.ASCII.GetString(segment.Span)
Console.Write(s)
)
```
Using ILSpy, here's a (correct) Release build:
```
public static void showIt(ReadOnlySequence buffer)
{
ReadOnlySequence.Enumerator enumerator = buffer.GetEnumerator();
while (enumerator.MoveNext())
{
ReadOnlyMemory current = enumerator.Current;
Console.Write(Encoding.ASCII.GetString(current.Span));
}
}
```
Below is the incorrect Debug build. The problem is that `enumerator2` is always reinitialized in the loop (using the value of `enumerator`). `enumerator2.MoveNext()` will then mutate `enumerator2`, but this mutation will be lost when `enumerator2` is reinitialized:
```
public static void showIt(ReadOnlySequence buffer)
{
ReadOnlySequence readOnlySequence = buffer;
ReadOnlySequence.Enumerator enumerator = readOnlySequence.GetEnumerator();
while (true)
{
ReadOnlySequence.Enumerator enumerator2 = enumerator;
if (enumerator2.MoveNext())
{
ReadOnlyMemory segment = enumerator.Current;
string s = Encoding.ASCII.GetString(segment.Span);
Console.Write(s);
continue;
}
break;
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.