[release/9.0-staging] Fix LINQ handling of iterator.Take(...).Last(...)#112714
Merged
stephentoub merged 1 commit intodotnet:release/9.0-stagingfrom Feb 21, 2025
Merged
[release/9.0-staging] Fix LINQ handling of iterator.Take(...).Last(...)#112714stephentoub merged 1 commit intodotnet:release/9.0-stagingfrom
stephentoub merged 1 commit intodotnet:release/9.0-stagingfrom
Conversation
When the Take amount is larger than the number of elements in the source `Iterator<T>`, Last ends up throwing an exception and LastOrDefault ends up returning the default value, rather than returning the last value in the taken region. As part of fixing this, I sured up the tests to try to cover more such sequences of operations. In doing so, the tests got a lot slower, so I tracked down and fixed places where we were doing a lot of unnecessary work.
Contributor
|
Tagging subscribers to this area: @dotnet/area-system-linq |
Contributor
There was a problem hiding this comment.
PR Overview
This pull request backports a fix to the LINQ implementation so that calls to iterator.Take(...).Last(...) now correctly return the actual last element rather than a default value or throwing an exception. Key changes include:
- Adjusting a condition in the SkipTake speed‐optimized code to correctly select the proper branch when handling the last element.
- Updating internal transformation helpers and test cases to use the new CreateSources method instead of IdentityTransforms.
- Revising various test methods to improve coverage and consistency across different enumerable scenarios.
Reviewed Changes
| File | Description |
|---|---|
| src/libraries/System.Linq/tests/EnumerableTests.cs | Updated transformation helpers and test cases to use CreateSources for more robust scenarios. |
| src/libraries/System.Linq/tests/SelectManyTests.cs | Revised parameterized tests to use a fixed loop for testing multiple ranges. |
| src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs | Changed a condition in the Take method to address an issue with incorrectly retrieving the last element. |
| Other test files | Adjusted test expectations and minor refactorings for consistency in enumerable behavior. |
Copilot reviewed 14 out of 14 changed files in this pull request and generated no comments.
Comments suppressed due to low confidence (1)
src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs:433
- Changing the condition from '>= _minIndexInclusive' to '> _minIndexInclusive' directly affects branch selection for retrieving the last element. Please verify that this change correctly resolves the issue without introducing unintended side effects.
count > _minIndexInclusive)
Tip: Copilot code review supports C#, Go, Java, JavaScript, Markdown, Python, Ruby and TypeScript, with more languages coming soon. Learn more
eiriktsarpalis
approved these changes
Feb 20, 2025
Member
|
Adding approved per-email with Steve |
61d986c
into
dotnet:release/9.0-staging
89 of 92 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport of #112680 to release/9.0-staging
Customer Impact
Code that does
commonLINQOperators.Take(...).Last(), wherecertainLINQOperatorsare things likeRange,Select,Where, etc., if the value passed to take is larger than the number of elements in the source,Lastwill throw an exception, andLastOrDefaultwill end up returning the default value rather than the actual last value. Essentially, the consumer can start operating on incorrect data or hit unexpected failures.Regression
This was introduced accidentally in .NET 9 as part of a change that consolidated several internal abstractions in LINQ.
Testing
Revamped the LINQ tests to execute various combinations that lead to this, but also a bunch of other combinations to try to root out any other similar issues.
Risk
Low. The change is isolated to a single block and is now much better tested. Developers would have either been getting back erroneous results, or erroneous exceptions; it'd be difficult for someone to have taken a meaningful dependency on the bug.