Skip to content

Commit 7050778

Browse files
Fix: removeAt and updateAt now raise ArgumentException for out-of-range index
AsyncSeq.removeAt and AsyncSeq.updateAt previously silently returned the source sequence unchanged when the index was >= the sequence length, which is inconsistent with List.removeAt, Array.removeAt, and AsyncSeq.insertAt. After the enumeration loop, check that the index was actually reached; if not (i.e. i <= index at end), raise ArgumentException matching the message used by AsyncSeq.insertAt. Adds 6 new tests covering out-of-range and boundary indices. Co-authored-by: Copilot <[email protected]>
1 parent fc443a8 commit 7050778

4 files changed

Lines changed: 47 additions & 3 deletions

File tree

RELEASE_NOTES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 4.15.0
2+
3+
* Bug fix: `AsyncSeq.removeAt` and `AsyncSeq.updateAt` now raise `ArgumentException` when the index is greater than or equal to the sequence length, consistent with `List.removeAt`, `Array.removeAt`, and `AsyncSeq.insertAt`. Previously they silently returned the sequence unchanged.
4+
15
### 4.14.0
26

37
* Added `AsyncSeq.mapAsyncParallelThrottled` — ordered, bounded-concurrency parallel map. Like `mapAsyncParallel` but limits the number of in-flight operations to `parallelism`, preventing unbounded resource use on large or infinite sequences.

src/FSharp.Control.AsyncSeq/AsyncSeq.fs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,15 +1706,19 @@ module AsyncSeq =
17061706
let mutable i = 0
17071707
for x in source do
17081708
if i <> index then yield x
1709-
i <- i + 1 }
1709+
i <- i + 1
1710+
if i <= index then
1711+
invalidArg "index" "The index is outside the range of elements in the collection." }
17101712

17111713
let updateAt (index : int) (value : 'T) (source : AsyncSeq<'T>) : AsyncSeq<'T> = asyncSeq {
17121714
if index < 0 then invalidArg "index" "must be non-negative"
17131715
let mutable i = 0
17141716
for x in source do
17151717
if i = index then yield value
17161718
else yield x
1717-
i <- i + 1 }
1719+
i <- i + 1
1720+
if i <= index then
1721+
invalidArg "index" "The index is outside the range of elements in the collection." }
17181722

17191723
let insertAt (index : int) (value : 'T) (source : AsyncSeq<'T>) : AsyncSeq<'T> = asyncSeq {
17201724
if index < 0 then invalidArg "index" "must be non-negative"

tests/FSharp.Control.AsyncSeq.Tests/AsyncSeqTests.fs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3784,6 +3784,24 @@ let ``AsyncSeq.removeAt raises ArgumentException for negative index`` () =
37843784
|> Async.RunSynchronously |> ignore)
37853785
|> ignore
37863786

3787+
[<Test>]
3788+
let ``AsyncSeq.removeAt raises ArgumentException when index is out of range`` () =
3789+
Assert.Throws<System.ArgumentException>(fun () ->
3790+
AsyncSeq.ofSeq [ 1; 2; 3 ]
3791+
|> AsyncSeq.removeAt 10
3792+
|> AsyncSeq.toArrayAsync
3793+
|> Async.RunSynchronously |> ignore)
3794+
|> ignore
3795+
3796+
[<Test>]
3797+
let ``AsyncSeq.removeAt raises ArgumentException when index equals sequence length`` () =
3798+
Assert.Throws<System.ArgumentException>(fun () ->
3799+
AsyncSeq.ofSeq [ 1; 2; 3 ]
3800+
|> AsyncSeq.removeAt 3
3801+
|> AsyncSeq.toArrayAsync
3802+
|> Async.RunSynchronously |> ignore)
3803+
|> ignore
3804+
37873805
// ===== updateAt =====
37883806

37893807
[<Test>]
@@ -3822,6 +3840,24 @@ let ``AsyncSeq.updateAt raises ArgumentException for negative index`` () =
38223840
|> Async.RunSynchronously |> ignore)
38233841
|> ignore
38243842

3843+
[<Test>]
3844+
let ``AsyncSeq.updateAt raises ArgumentException when index is out of range`` () =
3845+
Assert.Throws<System.ArgumentException>(fun () ->
3846+
AsyncSeq.ofSeq [ 1; 2; 3 ]
3847+
|> AsyncSeq.updateAt 10 99
3848+
|> AsyncSeq.toArrayAsync
3849+
|> Async.RunSynchronously |> ignore)
3850+
|> ignore
3851+
3852+
[<Test>]
3853+
let ``AsyncSeq.updateAt raises ArgumentException when index equals sequence length`` () =
3854+
Assert.Throws<System.ArgumentException>(fun () ->
3855+
AsyncSeq.ofSeq [ 1; 2; 3 ]
3856+
|> AsyncSeq.updateAt 3 99
3857+
|> AsyncSeq.toArrayAsync
3858+
|> Async.RunSynchronously |> ignore)
3859+
|> ignore
3860+
38253861
// ===== insertAt =====
38263862

38273863
[<Test>]

version.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>4.14.0</Version>
3+
<Version>4.15.0</Version>
44
</PropertyGroup>
55
</Project>

0 commit comments

Comments
 (0)