Repository navigation
Conversation
|
Azure Pipelines: Successfully started running 3 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @dotnet/area-system-collections |
Manishram-ai
left a comment
There was a problem hiding this comment.
I reproduced this on .NET 8.0.8 with the example from the description. After the throw, Count is still 4 but the builder only contains 2. Removing items one at a time like the fix does keeps Count and the contents in sync.
UnionWith has the same problem though. If the enumerable throws after it yields a new item, the item ends up in the set but Count doesn't go up.
var builder = ImmutableHashSet.CreateBuilder<int>();
builder.UnionWith(new[] { 1, 2, 3, 4 });
try { builder.UnionWith(ThrowingEnumerable()); } catch (InvalidOperationException) { }
// builder.Contains(5) is true, but builder.Count is still 4
IEnumerable<int> ThrowingEnumerable()
{
yield return 5;
throw new InvalidOperationException();
}ImmutableDictionary's builder AddRange does the same thing. Not sure if you'd rather fix those here or in a separate PR.
|
@Manishram-ai I checked ImmutableHashSet.Builder.UnionWith and issue is more severe than just an incorrect count. For example: var builder = ImmutableHashSet.CreateBuilder<int>();
builder.UnionWith(new[] { 1, 2, 3, 4 });
try { builder.UnionWith(ThrowingEnumerable()); } catch (InvalidOperationException) { }
foreach (int item in builder) Console.WriteLine(item); // prints only "1 2 3" on .NET 10.0.10
IEnumerable<int> ThrowingEnumerable()
{
yield return 5;
yield return 6;
throw new InvalidOperationException();
}The original element 4 is no longer enumerated and elements are skipped only if UnionWith has 2+ elements (in this example). I suspect this is related to tree rebalancing and the builder retaining the old root when the final update is skipped. I think I will fix UnionWith and AddRange in separate PRs. |
|
Thanks for digging into it. I see the same on .NET 8.0.8: it enumerates |
ImmutableHashSet.Builder.ExceptWith can leave the builder in an inconsistent state if the input enumerable throws during enumeration.
For example:
If enumeration throws, updates are skipped leaving the builder with an incorrect count and potentially losing unrelated elements. Added a regression test that failed before the fix and passed afterward.