diff --git a/docsrc/tools/doclib.fs b/docsrc/tools/doclib.fs
index 683fc289a..396cfad4a 100644
--- a/docsrc/tools/doclib.fs
+++ b/docsrc/tools/doclib.fs
@@ -4,7 +4,7 @@ module DocLib
// Copyright 2010 Steffen Forkmann
// Apache license
-
+#nowarn "49"
open System.IO
module String =
diff --git a/src/FSharpPlus/Extensions/Array.fs b/src/FSharpPlus/Extensions/Array.fs
index 2639d8115..511b5164d 100644
--- a/src/FSharpPlus/Extensions/Array.fs
+++ b/src/FSharpPlus/Extensions/Array.fs
@@ -14,17 +14,17 @@ module Array =
/// The element to add
/// The array to add to
/// A new array with the element added to the beginning.
- let cons value array =
- raiseIfNull (nameof(array)) array
+ let cons value (array: 'T []) =
+ let array = nullArgCheck (nameof array) array
Array.insertAt 0 value array
/// Splits the array in head and tail.
/// The input array.
/// A tuple with the head and the tail of the original array.
/// Thrown when the input array is empty.
- let uncons array =
- raiseIfNull (nameof(array)) array
- if Array.isEmpty array then invalidArg (nameof(array)) LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ let uncons (array: 'T []) =
+ let array = nullArgCheck (nameof array) array
+ if Array.isEmpty array then invalidArg (nameof array) LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
else array[0], array[1..]
/// Applies an array of functions to an array of values and concatenates them.
@@ -38,42 +38,48 @@ module Array =
/// val it : int [] = [|2; 4; 6; 3; 6; 9|]
///
///
- let apply f x =
- raiseIfNull (nameof(x)) x
+ let apply (f: ('T -> 'U) []) (x: 'T []) : 'U [] =
+ let x = nullArgCheck (nameof x) x
let lenf, lenx = Array.length f, Array.length x
Array.init (lenf * lenx) (fun i -> let (d, r) = Math.DivRem (i, lenx) in f.[d] x.[r])
- /// Combines all values from the first array with the second, using the supplied mapping function.
- let lift2 f x y =
- raiseIfNull (nameof(x)) x
- raiseIfNull (nameof(y)) y
+ /// Combines all values from three arrays and calls a mapping function on this combination.
+ /// Mapping function taking three element combination as input.
+ /// First array.
+ /// Second array.
+ ///
+ /// Array with values returned from mapping function.
+ let lift2 (mapping: 'T1 -> 'T2 -> 'U) (array1: 'T1 []) (array2: 'T2 []) : 'U [] =
+ let array1 = nullArgCheck (nameof array1) array1
+ let array2 = nullArgCheck (nameof array2) array2
- let lenx, leny = Array.length x, Array.length y
- Array.init (lenx * leny) (fun i -> let (d, r) = Math.DivRem (i, leny) in f x.[d] y.[r])
+ let lenx, leny = Array.length array1, Array.length array2
+ Array.init (lenx * leny) (fun i -> let (d, r) = Math.DivRem (i, leny) in mapping array1.[d] array2.[r])
/// Combines all values from three arrays and calls a mapping function on this combination.
/// Mapping function taking three element combination as input.
- /// First array.
- /// Second array.
- /// Third array.
+ /// First array.
+ /// Second array.
+ /// Third array.
///
/// Array with values returned from mapping function.
- let lift3 mapping list1 list2 list3 =
- raiseIfNull (nameof(list1)) list1
- raiseIfNull (nameof(list2)) list2
- raiseIfNull (nameof(list3)) list3
+ let lift3 (mapping: 'T1 -> 'T2 -> 'T3 -> 'U) (array1: 'T1 []) (array2: 'T2 []) (array3: 'T3 []) : 'U [] =
+ let array1 = nullArgCheck (nameof array1) array1
+ let array2 = nullArgCheck (nameof array2) array2
+ let array3 = nullArgCheck (nameof array3) array3
- let lenx, leny, lenz = Array.length list1, Array.length list2, Array.length list3
- let combinedFirstTwo = Array.init (lenx * leny) (fun i -> let (d, r) = Math.DivRem (i, leny) in (list1.[d], list2.[r]))
+ let lenx, leny, lenz = Array.length array1, Array.length array2, Array.length array3
+ let combinedFirstTwo = Array.init (lenx * leny) (fun i -> let (d, r) = Math.DivRem (i, leny) in (array1.[d], array2.[r]))
- Array.init (lenx * leny * lenz) (fun i -> let (d, r) = Math.DivRem (i, lenz) in combinedFirstTwo.[d], list3.[r])
+ Array.init (lenx * leny * lenz) (fun i -> let (d, r) = Math.DivRem (i, lenz) in combinedFirstTwo.[d], array3.[r])
|> Array.map (fun x -> mapping (fst (fst x)) (snd (fst x)) (snd x))
/// Concatenates all elements, using the specified separator between each element.
- let intercalate (separator: 'T []) (source: seq<'T []>) =
- raiseIfNull (nameof(source)) source
+ let intercalate (separator: 'T []) (source: seq<'T []>) : 'T [] =
+ let separator = nullArgCheck (nameof separator) separator
+ let source = nullArgCheck (nameof source) source
#if FABLE_COMPILER
source |> Seq.intercalate separator |> Seq.toArray
@@ -88,8 +94,8 @@ module Array =
#endif
/// Inserts a separator element between each element in the source array.
- let intersperse element (source: 'T []) =
- raiseIfNull (nameof(source)) source
+ let intersperse element (source: 'T []) : 'T [] =
+ let source = nullArgCheck (nameof source) source
match source with
| [||] -> [||]
@@ -101,17 +107,17 @@ module Array =
| _ -> element)
/// Creates a sequence of arrays by splitting the source array on any of the given separators.
- let split (separators: seq<_ []>) (source: _ []) =
- raiseIfNull (nameof(separators)) separators
- raiseIfNull (nameof(source)) source
+ let split (separators: seq<'T []>) (source: 'T []) : seq<'T []> =
+ let separators = nullArgCheck (nameof separators) separators
+ let source = nullArgCheck (nameof source) source
source |> Array.toSeq |> Seq.split separators |> Seq.map Seq.toArray
/// Replaces a subsequence of the source array with the given replacement array.
let replace (oldValue: 'T []) (newValue: 'T []) (source: 'T[]) : 'T[] =
- raiseIfNull (nameof(oldValue)) oldValue
- raiseIfNull (nameof(newValue)) newValue
- raiseIfNull (nameof(source)) source
+ let oldValue = nullArgCheck (nameof oldValue) oldValue
+ let newValue = nullArgCheck (nameof newValue) newValue
+ let source = nullArgCheck (nameof source) source
#if FABLE_COMPILER
source |> Array.toSeq |> Seq.replace oldValue newValue |> Seq.toArray: 'T []
@@ -178,9 +184,9 @@ module Array =
///
/// The index of the slice or None.
///
- let findSliceIndex (slice: _ []) (source: _ []) =
- raiseIfNull (nameof(slice)) slice
- raiseIfNull (nameof(source)) source
+ let findSliceIndex (slice: 'T []) (source: 'T []) : int =
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
let index = Internals.FindSliceIndex.arrayImpl slice source
if index = -1 then
@@ -195,9 +201,9 @@ module Array =
///
/// The index of the slice or None.
///
- let tryFindSliceIndex (slice: _ []) (source: _ []) =
- raiseIfNull (nameof(slice)) slice
- raiseIfNull (nameof(source)) source
+ let tryFindSliceIndex (slice: 'T []) (source: 'T []) : int option =
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
let index = Internals.FindSliceIndex.arrayImpl slice source
if index = -1 then None else Some index
@@ -209,9 +215,9 @@ module Array =
///
/// The index of the slice or None.
///
- let findLastSliceIndex (slice: _ []) (source: _ []) =
- raiseIfNull (nameof(slice)) slice
- raiseIfNull (nameof(source)) source
+ let findLastSliceIndex (slice: _ []) (source: _ []) : int =
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
let index = Internals.FindLastSliceIndex.arrayImpl slice source
if index = -1 then
@@ -226,9 +232,9 @@ module Array =
///
/// The index of the slice or None.
///
- let tryFindLastSliceIndex (slice: _ []) (source: _ []) =
- raiseIfNull (nameof(slice)) slice
- raiseIfNull (nameof(source)) source
+ let tryFindLastSliceIndex (slice: 'T []) (source: 'T []) : int option =
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
let index = Internals.FindLastSliceIndex.arrayImpl slice source
if index = -1 then None else Some index
@@ -241,8 +247,8 @@ module Array =
///
/// A tuple with both resulting arrays.
///
- let partitionMap (mapper: 'T -> Choice<'T1,'T2>) (source: array<'T>) =
- raiseIfNull (nameof(source)) source
+ let partitionMap (mapper: 'T -> Choice<'T1, 'T2>) (source: array<'T>) : array<'T1> * array<'T2> =
+ let source = nullArgCheck (nameof source) source
let (x, y) = ResizeArray (), ResizeArray ()
Array.iter (mapper >> function Choice1Of2 e -> x.Add e | Choice2Of2 e -> y.Add e) source
@@ -251,19 +257,19 @@ module Array =
/// Safely build a new array whose elements are the results of applying the given function
/// to each of the elements of the two arrays pairwise.
/// If one array is shorter, excess elements are discarded from the right end of the longer array.
- let map2Shortest f (a1: 'T []) (a2: 'U []) =
- raiseIfNull (nameof(a1)) a1
- raiseIfNull (nameof(a2)) a2
+ let map2Shortest (f: 'T1 -> 'T2 -> 'U) (a1: 'T1 []) (a2: 'T2 []) : 'U [] =
+ let a1 = nullArgCheck (nameof a1) a1
+ let a2 = nullArgCheck (nameof a2) a2
Array.init (min a1.Length a2.Length) (fun i -> f a1.[i] a2.[i])
/// Safely build a new array whose elements are the results of applying the given function
/// to each of the elements of the three arrays pairwise.
/// If one array is shorter, excess elements are discarded from the right end of the longer array.
- let map3Shortest f (a1: 'T1 []) (a2: 'T2 []) (a3: 'T3 []) =
- raiseIfNull (nameof a1) a1
- raiseIfNull (nameof a2) a2
- raiseIfNull (nameof a3) a3
+ let map3Shortest (f: 'T1 -> 'T2 -> 'T3 -> 'U) (a1: 'T1 []) (a2: 'T2 []) (a3: 'T3 []) : 'U [] =
+ let a1 = nullArgCheck (nameof a1) a1
+ let a2 = nullArgCheck (nameof a2) a2
+ let a3 = nullArgCheck (nameof a3) a3
Array.init (min a1.Length a2.Length |> min a3.Length) (fun i -> f a1.[i] a2.[i] a3.[i])
///
@@ -272,9 +278,9 @@ module Array =
/// First input array.
/// Second input array.
/// Array with corresponding pairs of input arrays.
- let zipShortest (a1: array<'T1>) (a2: array<'T2>) =
- raiseIfNull (nameof(a1)) a1
- raiseIfNull (nameof(a2)) a2
+ let zipShortest (a1: array<'T1>) (a2: array<'T2>) : array<'T1 * 'T2> =
+ let a1 = nullArgCheck (nameof a1) a1
+ let a2 = nullArgCheck (nameof a2) a2
Array.init (min a1.Length a2.Length) (fun i -> a1.[i], a2.[i])
@@ -285,10 +291,10 @@ module Array =
/// Second input array.
/// Third input array.
/// Array with corresponding tuple of input arrays.
- let zip3Shortest (a1: array<'T1>) (a2: array<'T2>) (a3: array<'T3>) =
- raiseIfNull (nameof a1) a1
- raiseIfNull (nameof a2) a2
- raiseIfNull (nameof a3) a3
+ let zip3Shortest (a1: array<'T1>) (a2: array<'T2>) (a3: array<'T3>) : array<'T1 * 'T2 * 'T3> =
+ let a1 = nullArgCheck (nameof a1) a1
+ let a2 = nullArgCheck (nameof a2) a2
+ let a3 = nullArgCheck (nameof a3) a3
Array.init (min a1.Length a2.Length |> min a3.Length) (fun i -> a1.[i], a2.[i], a3.[i])
/// Same as choose but with access to the index.
@@ -296,8 +302,8 @@ module Array =
/// The input array.
///
/// Array with values x for each Array value where the function returns Some(x).
- let choosei mapping source =
- raiseIfNull (nameof(source)) source
+ let choosei (mapping: int -> 'T -> 'U option) (source: array<'T>) : array<'U> =
+ let source = nullArgCheck (nameof source) source
let mutable i = ref -1
let fi x =
diff --git a/src/FSharpPlus/Extensions/Enumerator.fs b/src/FSharpPlus/Extensions/Enumerator.fs
index 6fd3c50bb..a86fc3141 100644
--- a/src/FSharpPlus/Extensions/Enumerator.fs
+++ b/src/FSharpPlus/Extensions/Enumerator.fs
@@ -1,5 +1,6 @@
namespace FSharpPlus
+#nowarn "3261" // nullness checks
#if !FABLE_COMPILER
/// Additional operations on IEnumerator
diff --git a/src/FSharpPlus/Extensions/Exception.fs b/src/FSharpPlus/Extensions/Exception.fs
index 08b8e6030..2ff821e95 100644
--- a/src/FSharpPlus/Extensions/Exception.fs
+++ b/src/FSharpPlus/Extensions/Exception.fs
@@ -11,15 +11,15 @@ module Exception =
/// Throws the given exception with its original stacktrace.
let inline rethrow<'T> (exn: exn) =
- raiseIfNull (nameof exn) exn
+ let exn = nullArgCheck (nameof exn) exn
(ExceptionDispatchInfo.Capture exn).Throw ()
Unchecked.defaultof<'T>
/// Combines exceptions from 2 exceptions into a single AggregateException.
/// Exceptions already present in the first argument won't be added.
let add (exn1: exn) (exn2: exn) =
- raiseIfNull (nameof exn1) exn1
- raiseIfNull (nameof exn2) exn2
+ let exn1 = nullArgCheck (nameof exn1) exn1
+ let exn2 = nullArgCheck (nameof exn2) exn2
let f (e: exn) =
match e with
:? AggregateException as a -> a.InnerExceptions :> seq<_>
diff --git a/src/FSharpPlus/Extensions/Extensions.fs b/src/FSharpPlus/Extensions/Extensions.fs
index c9e42f3ec..83409e559 100644
--- a/src/FSharpPlus/Extensions/Extensions.fs
+++ b/src/FSharpPlus/Extensions/Extensions.fs
@@ -4,6 +4,7 @@ namespace FSharpPlus
module Extensions =
open System
+ open FSharpPlus.Internals.Errors
type Collections.Generic.IEnumerable<'T> with
member this.GetSlice = function
@@ -39,7 +40,7 @@ module Extensions =
let private (|Canceled|Faulted|Completed|) (t: Task<'a>) =
if t.IsCanceled then Canceled
- else if t.IsFaulted then Faulted t.Exception
+ else if t.IsFaulted then Faulted (Unchecked.nonNull t.Exception)
else Completed t.Result
type Task<'t> with
@@ -158,7 +159,7 @@ module Extensions =
Async.FromContinuations (fun (sc, ec, cc) ->
task.ContinueWith (fun (task: Task<'T>) ->
if task.IsFaulted then
- let e = task.Exception
+ let e = Unchecked.nonNull task.Exception
if e.InnerExceptions.Count = 1 then ec e.InnerExceptions[0]
else ec e
elif task.IsCanceled then cc (TaskCanceledException ())
@@ -185,7 +186,7 @@ module Extensions =
Async.FromContinuations (fun (sc, ec, cc) ->
task.ContinueWith (fun (task: Task) ->
if task.IsFaulted then
- let e = task.Exception
+ let e = Unchecked.nonNull task.Exception
if e.InnerExceptions.Count = 1 then ec e.InnerExceptions[0]
else ec e
elif task.IsCanceled then cc (TaskCanceledException ())
diff --git a/src/FSharpPlus/Extensions/HashSet.fs b/src/FSharpPlus/Extensions/HashSet.fs
index c0db14b3c..0e392f5ce 100644
--- a/src/FSharpPlus/Extensions/HashSet.fs
+++ b/src/FSharpPlus/Extensions/HashSet.fs
@@ -31,8 +31,8 @@ module HashSet =
/// The union of set1 and set2.
[]
let union (source1: HashSet<'T>) (source2: HashSet<'T>) : HashSet<'T> =
- raiseIfNull (nameof source1) source1
- raiseIfNull (nameof source2) source2
+ let source1 = nullArgCheck (nameof source1) source1
+ let source2 = nullArgCheck (nameof source2) source2
let union =
#if FABLE_COMPILER
HashSet<'T> ()
@@ -50,7 +50,7 @@ module HashSet =
/// A set containing the transformed elements.
[]
let map (mapping: 'T -> 'U) (source: HashSet<'T>) : HashSet<'U> =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
let result = empty<'U>
for item in source do
result.Add (mapping item) |> ignore
@@ -62,7 +62,7 @@ module HashSet =
/// true if the set contains value; otherwise, false.
[]
let contains (value: 'T) (source: HashSet<'T>) : bool =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.Contains value
/// Determines whether the first set is a subset of the second set.
@@ -71,6 +71,6 @@ module HashSet =
/// true if source1 is a subset of source2; otherwise, false.
[]
let isSubset (source1: HashSet<'T>) (source2: HashSet<'T>) : bool =
- raiseIfNull (nameof source1) source1
- raiseIfNull (nameof source2) source2
+ let source1 = nullArgCheck (nameof source1) source1
+ let source2 = nullArgCheck (nameof source2) source2
source1.IsSubsetOf source2
diff --git a/src/FSharpPlus/Extensions/List.fs b/src/FSharpPlus/Extensions/List.fs
index e8340743f..4c9c32b16 100644
--- a/src/FSharpPlus/Extensions/List.fs
+++ b/src/FSharpPlus/Extensions/List.fs
@@ -8,6 +8,7 @@ module List =
open System
open FSharp.Core.CompilerServices
+ open FSharpPlus.Internals.Errors
/// Returns a list that contains one item only.
///
@@ -475,7 +476,7 @@ module List =
open System.Reflection
/// Creates an infinite list which cycles the element of the source.
- let cycle lst =
+ let cycle (lst: 'T list) =
let last = ref lst
let rec copy = function
| [] -> failwith "empty list"
@@ -486,7 +487,7 @@ module List =
| x::xs -> x::copy xs
let cycled = copy lst
let strs = last.Value.GetType().GetFields(BindingFlags.NonPublic ||| BindingFlags.Instance) |> Array.map (fun field -> field.Name)
- let tailField = last.Value.GetType().GetField(Array.find(fun (s:string) -> s.ToLower().Contains("tail")) strs, BindingFlags.NonPublic ||| BindingFlags.Instance)
+ let tailField = last.Value.GetType().GetField(Array.find(fun (s:string) -> s.ToLower().Contains("tail")) strs, BindingFlags.NonPublic ||| BindingFlags.Instance) |> Unchecked.nonNull
tailField.SetValue(last.Value, cycled)
cycled
#else
diff --git a/src/FSharpPlus/Extensions/ResizeArray.fs b/src/FSharpPlus/Extensions/ResizeArray.fs
index 7a2e02f41..bc2deb148 100644
--- a/src/FSharpPlus/Extensions/ResizeArray.fs
+++ b/src/FSharpPlus/Extensions/ResizeArray.fs
@@ -4,7 +4,6 @@
[]
module ResizeArray =
- open System
open FSharpPlus.Internals.Errors
/// Builds a new ResizeArray whose elements are the results of applying the given function
@@ -16,8 +15,8 @@ module ResizeArray =
/// The result ResizeArray.
///
/// Thrown when the input ResizeArray is null.
- let map (mapping: 'T->'U) (source: ResizeArray<'T>) =
- raiseIfNull (nameof source) source
+ let map (mapping: 'T -> 'U) (source: ResizeArray<'T>) =
+ let source = nullArgCheck (nameof source) source
ResizeArray (Seq.map mapping source)
@@ -25,13 +24,13 @@ module ResizeArray =
/// The function to apply to elements from the input ResizeArray.
/// The input ResizeArray.
let iter (action: 'T -> unit) (source: ResizeArray<'T>) : unit =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
Seq.iter action source
/// Applies a ResizeArray of functions to a ResizeArray of values and concatenates them.
/// The functions.
- /// The values.
+ /// The values.
/// A concatenated list of the resulting ResizeArray after applying each function to each value.
///
///
@@ -40,16 +39,16 @@ module ResizeArray =
/// val it : int list = [2; 4; 6; 3; 6; 9]
///
///
- let apply (f: ResizeArray<'T->'U>) (ra: ResizeArray<'T>) =
- raiseIfNull (nameof ra) ra
+ let apply (f: ResizeArray<'T -> 'U>) (source: ResizeArray<'T>) : ResizeArray<'U> =
+ let source = nullArgCheck (nameof source) source
- ResizeArray (Seq.apply f ra)
+ ResizeArray (Seq.apply f source)
/// Combines all values from the first ResizeArray with the second, using the supplied mapping function.
- let lift2 mapping (ra1: ResizeArray<'T>) (ra2: ResizeArray<'U>) =
- raiseIfNull (nameof ra1) ra1
- raiseIfNull (nameof ra2) ra2
-
+ let lift2 mapping (ra1: ResizeArray<'T1>) (ra2: ResizeArray<'T2>) : ResizeArray<'U> =
+ let ra1 = nullArgCheck (nameof ra1) ra1
+ let ra2 = nullArgCheck (nameof ra2) ra2
+
ResizeArray (Seq.lift2 mapping ra1 ra2)
/// Combines values from three ResizeArrays and calls a mapping function on this combination.
@@ -59,37 +58,38 @@ module ResizeArray =
/// Third ResizeArray.
///
/// ResizeArray with values returned from mapping function.
- let lift3 mapping (ra1: ResizeArray<'T>) (ra2: ResizeArray<'U>) (ra3: ResizeArray<'V>) =
- raiseIfNull (nameof ra1) ra1
- raiseIfNull (nameof ra2) ra2
- raiseIfNull (nameof ra3) ra3
-
+ let lift3 mapping (ra1: ResizeArray<'T1>) (ra2: ResizeArray<'T2>) (ra3: ResizeArray<'T3>) : ResizeArray<'U> =
+ let ra1 = nullArgCheck (nameof ra1) ra1
+ let ra2 = nullArgCheck (nameof ra2) ra2
+ let ra3 = nullArgCheck (nameof ra3) ra3
+
ResizeArray (Seq.lift3 mapping ra1 ra2 ra3)
/// Concatenates all elements, using the specified separator between each element.
- let intercalate (separator: _ []) (source: seq<_ []>) =
- raiseIfNull (nameof separator) separator
- raiseIfNull (nameof source) source
+ //let intercalate (separator) (source) =
+ let intercalate (separator: ResizeArray<'T>) (source: seq>) : ResizeArray<'T> =
+ let separator = nullArgCheck (nameof separator) separator
+ let source = nullArgCheck (nameof source) source
- source |> Seq.intercalate separator |> Seq.toArray
+ source |> Seq.intercalate separator |> ResizeArray
/// Inserts a separator element between each element in the source ResizeArray.
- let intersperse element source =
- raiseIfNull (nameof element) element
- raiseIfNull (nameof source) source
-
- source |> Array.toSeq |> Seq.intersperse element |> Seq.toArray : 'T []
+ let intersperse (element: 'T) (source: ResizeArray<'T>) : ResizeArray<'T> =
+ source |> nullArgCheck (nameof source) |> Seq.intersperse element |> ResizeArray
/// Creates a sequence of arrays by splitting the source array on any of the given separators.
let split (separators: seq>) (source: ResizeArray<'T>) : seq> =
- raiseIfNull (nameof separators) separators
- raiseIfNull (nameof source) source
+ let separators = nullArgCheck (nameof separators) separators
+ let source = nullArgCheck (nameof source) source
+
source |> Seq.split separators |> Seq.map ResizeArray
/// Replaces a subsequence of the source array with the given replacement array.
let replace (oldValue: ResizeArray<'T>) (newValue: ResizeArray<'T>) (source: ResizeArray<'T>) : ResizeArray<'T> =
- raiseIfNull (nameof oldValue) oldValue
- raiseIfNull (nameof source) source
+ let oldValue = nullArgCheck (nameof oldValue) oldValue
+ let newValue = nullArgCheck (nameof newValue) newValue
+ let source = nullArgCheck (nameof source) source
+
source |> Seq.replace oldValue newValue |> ResizeArray
#if !FABLE_COMPILER
@@ -104,8 +104,8 @@ module ResizeArray =
/// The index of the slice.
///
let findSliceIndex (slice: ResizeArray<'T>) (source: ResizeArray<'T>) : int =
- raiseIfNull (nameof slice) slice
- raiseIfNull (nameof source) source
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
let index = Internals.FindSliceIndex.seqImpl slice source
if index = -1 then
@@ -121,8 +121,8 @@ module ResizeArray =
/// The index of the slice or None.
///
let tryFindSliceIndex (slice: ResizeArray<'T>) (source: ResizeArray<'T>) : int option =
- raiseIfNull (nameof slice) slice
- raiseIfNull (nameof source) source
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
let index = Internals.FindSliceIndex.seqImpl slice source
if index = -1 then None else Some index
@@ -137,6 +137,9 @@ module ResizeArray =
/// The index of the slice.
///
let findLastSliceIndex (slice: ResizeArray<'T>) (source: ResizeArray<'T>) : int =
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
+
let index = Internals.FindLastSliceIndex.seqImpl slice source
if index = -1 then
invalidArg (nameof slice) "The specified slice was not found in the sequence."
@@ -151,6 +154,9 @@ module ResizeArray =
/// The index of the slice or None.
///
let tryFindLastSliceIndex (slice: ResizeArray<'T>) (source: ResizeArray<'T>) : int option =
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
+
let index = Internals.FindLastSliceIndex.seqImpl slice source
if index = -1 then None else Some index
#endif
@@ -163,7 +169,7 @@ module ResizeArray =
/// A tuple with both resulting arrays.
///
let partitionMap (mapper: 'T -> Choice<'T1,'T2>) (source: ResizeArray<'T>) : ResizeArray<'T1> * ResizeArray<'T2> =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
let (x, y) = ResizeArray (), ResizeArray ()
iter (mapper >> function Choice1Of2 e -> x.Add e | Choice2Of2 e -> y.Add e) source
@@ -172,12 +178,12 @@ module ResizeArray =
/// Safely build a new ResizeArray whose elements are the results of applying the given function
/// to each of the elements of the two ResizeArrays pairwise.
/// If one array is shorter, excess elements are discarded from the right end of the longer array.
- let map2Shortest f (a1: ResizeArray<_>) (a2: ResizeArray<_>) =
- raiseIfNull (nameof a1) a1
- raiseIfNull (nameof a2) a2
-
+ let map2Shortest (f: 'T1 -> 'T2 -> 'U) (a1: ResizeArray<'T1>) (a2: ResizeArray<'T2>) : ResizeArray<'U> =
+ let a1 = nullArgCheck (nameof a1) a1
+ let a2 = nullArgCheck (nameof a2) a2
+
let len = min a1.Count a2.Count
- let ra = ResizeArray(len)
+ let ra = ResizeArray len
for i in 0..(len-1) do
ra.Add (f a1[i] a2[i])
ra
@@ -185,7 +191,11 @@ module ResizeArray =
/// Safely build a new ResizeArray whose elements are the results of applying the given function
/// to each of the elements of the three ResizeArrays pairwise.
/// If one array is shorter, excess elements are discarded from the right end of the longer array.
- let map3Shortest f (a1: ResizeArray<'T1>) (a2: ResizeArray<'T2>) (a3: ResizeArray<'T3>) =
+ let map3Shortest (f: 'T1 -> 'T2 -> 'T3 -> 'U) (a1: ResizeArray<'T1>) (a2: ResizeArray<'T2>) (a3: ResizeArray<'T3>) : ResizeArray<'U> =
+ let a1 = nullArgCheck (nameof a1) a1
+ let a2 = nullArgCheck (nameof a2) a2
+ let a3 = nullArgCheck (nameof a3) a3
+
let len = min a1.Count a2.Count |> min a3.Count
let ra = ResizeArray len
for i in 0..(len-1) do
@@ -198,10 +208,10 @@ module ResizeArray =
/// First input ResizeArray.
/// Second input ResizeArray.
/// ResizeArray with corresponding pairs of input ResizeArrays.
- let zipShortest (a1: ResizeArray<'T1>) (a2: ResizeArray<'T2>) =
- raiseIfNull (nameof a1) a1
- raiseIfNull (nameof a2) a2
-
+ let zipShortest (a1: ResizeArray<'T1>) (a2: ResizeArray<'T2>) : ResizeArray<'T1 * 'T2> =
+ let a1 = nullArgCheck (nameof a1) a1
+ let a2 = nullArgCheck (nameof a2) a2
+
let len = min a1.Count a2.Count
let ra = ResizeArray(len)
for i in 0..(len-1) do
@@ -215,7 +225,11 @@ module ResizeArray =
/// Second input ResizeArray.
/// Third input ResizeArray.
/// ResizeArray with corresponding pairs of input ResizeArrays.
- let zip3Shortest (a1: ResizeArray<'T1>) (a2: ResizeArray<'T2>) (a3: ResizeArray<'T3>) =
+ let zip3Shortest (a1: ResizeArray<'T1>) (a2: ResizeArray<'T2>) (a3: ResizeArray<'T3>) : ResizeArray<'T1 * 'T2 * 'T3> =
+ let a1 = nullArgCheck (nameof a1) a1
+ let a2 = nullArgCheck (nameof a2) a2
+ let a3 = nullArgCheck (nameof a3) a3
+
let len = min a1.Count a2.Count |> min a3.Count
let ra = ResizeArray len
for i in 0..(len-1) do
diff --git a/src/FSharpPlus/Extensions/Seq.fs b/src/FSharpPlus/Extensions/Seq.fs
index 90f73e8cc..c7d841f05 100644
--- a/src/FSharpPlus/Extensions/Seq.fs
+++ b/src/FSharpPlus/Extensions/Seq.fs
@@ -4,12 +4,15 @@ namespace FSharpPlus
[]
module Seq =
open System
+ open FSharpPlus.Internals.Errors
/// Adds an element to the beginning of the given sequence
/// The element to add
/// The sequence to add to
/// A new sequence with the element added to the beginning.
- let cons value source = seq { yield value; yield! source } : seq<'T>
+ let cons value (source: seq<'T>) : seq<'T> =
+ let source = nullArgCheck (nameof source) source
+ seq { yield value; yield! source }
/// Applies the given function to each element of the sequence and concatenates the results.
///
@@ -23,7 +26,10 @@ module Seq =
/// The result sequence.
///
/// Thrown when the input sequence is null.
- let bind (mapping: 'T->seq<'U>) source = Seq.collect mapping source
+ let bind (mapping: 'T -> seq<'U>) (source: seq<'T>) : seq<'U> =
+ let source = nullArgCheck (nameof source) source
+
+ Seq.collect mapping source
/// Applies a sequence of functions to a sequence of values and concatenates them.
/// The seq of functions.
@@ -36,10 +42,16 @@ module Seq =
/// val it : seq<int> = seq [2; 4; 6; 3; ...]
///
///
- let apply f x = bind (fun f -> Seq.map ((<|) f) x) f
+ let apply (f: seq<'T -> 'U>) (x: seq<'T>) : seq<'U> =
+ let f = nullArgCheck (nameof f) f
+ let x = nullArgCheck (nameof x) x
+ bind (fun f -> Seq.map ((<|) f) x) f
/// Combines all values from the first seq with the second, using the supplied mapping function.
- let lift2 f x1 x2 = Seq.allPairs x1 x2 |> Seq.map (fun (x, y) -> f x y)
+ let lift2 (f: 'T1 -> 'T2 -> 'U) (x1: seq<'T1>) (x2: seq<'T2>) : seq<'U> =
+ let x1 = nullArgCheck (nameof x1) x1
+ let x2 = nullArgCheck (nameof x2) x2
+ Seq.allPairs x1 x2 |> Seq.map (fun (x, y) -> f x y)
/// Combines values from three seq and calls a mapping function on this combination.
@@ -50,6 +62,10 @@ module Seq =
///
/// Seq with values returned from mapping function.
let lift3 (f: 'T1 -> 'T2 -> 'T3 -> 'U) (x1: seq<'T1>) (x2: seq<'T2>) (x3: seq<'T3>) : seq<'U> =
+ let x1 = nullArgCheck (nameof x1) x1
+ let x2 = nullArgCheck (nameof x2) x2
+ let x3 = nullArgCheck (nameof x3) x3
+
Seq.allPairs x2 x3
|> Seq.allPairs x1
|> Seq.map (fun x -> (fst x, fst (snd x), snd (snd x)))
@@ -66,7 +82,10 @@ module Seq =
/// Note: this function has since been added to FSharp.Core.
/// It will be removed in next major release of FSharpPlus.
///
- let foldBack folder source state = Array.foldBack folder (Seq.toArray source) state
+ let foldBack folder (source: seq<'T>) (state: 'State) : 'State =
+ let source = nullArgCheck (nameof source) source
+
+ Array.foldBack folder (Seq.toArray source) state
///
/// Chunks the seq up into groups with the same projected key by applying
@@ -86,41 +105,54 @@ module Seq =
/// The input seq.
///
/// The resulting sequence of keys tupled with an array of matching values
- let chunkBy (projection: 'T -> 'Key) (source: _ seq) = seq {
- use e = source.GetEnumerator ()
- if e.MoveNext () then
- let mutable g = projection e.Current
- let mutable members = ResizeArray ()
- members.Add e.Current
- while e.MoveNext () do
- let key = projection e.Current
- if g = key then members.Add e.Current
- else
- yield g, members
- g <- key
- members <- ResizeArray ()
- members.Add e.Current
- yield g, members }
+ let chunkBy (projection: 'T -> 'Key) (source: seq<'T>) : seq<'Key * ResizeArray<'T>> =
+ let source = nullArgCheck (nameof source) source
+
+ seq {
+ use e = source.GetEnumerator ()
+ if e.MoveNext () then
+ let mutable g = projection e.Current
+ let mutable members = ResizeArray ()
+ members.Add e.Current
+ while e.MoveNext () do
+ let key = projection e.Current
+ if g = key then members.Add e.Current
+ else
+ yield g, members
+ g <- key
+ members <- ResizeArray ()
+ members.Add e.Current
+ yield g, members }
/// Inserts a separator element between each element in the source seq.
- ///http://codebetter.com/matthewpodwysocki/2009/05/06/functionally-implementing-intersperse/
- let intersperse sep list = seq {
- let mutable notFirst = false
- for element in list do
- if notFirst then yield sep
- yield element
- notFirst <- true }
+ ///http://codebetter.com/matthewpodwysocki/2009/05/06/functionally-implementing-intersperse/
+ let intersperse sep (list: seq<'T>) : seq<'T> =
+ let list = nullArgCheck (nameof list) list
+
+ seq {
+ let mutable notFirst = false
+ for element in list do
+ if notFirst then yield sep
+ yield element
+ notFirst <- true }
/// Inserts a separator between each element in the source sequence.
- let intercalate separator source = seq {
- let mutable notFirst = false
- for element in source do
- if notFirst then yield! separator
- yield! element
- notFirst <- true }
+ let intercalate (separator: seq<'T>) (source: seq<#seq<'T>>) : seq<'T> =
+ let separator = nullArgCheck (nameof separator) separator
+ let source = nullArgCheck (nameof source) source
+
+ seq {
+ let mutable notFirst = false
+ for element in source do
+ if notFirst then yield! separator
+ yield! element
+ notFirst <- true }
/// Creates a sequence of sequences by splitting the source sequence on any of the given separators.
- let split separators source =
+ let split (separators: seq<#seq<'T>>) (source: seq<'T>) : seq> =
+ let separators = nullArgCheck (nameof separators) separators
+ let source = nullArgCheck (nameof source) source
+
let split options = seq {
match separators |> Seq.map Seq.toList |> Seq.toList with
| [] -> yield source
@@ -147,26 +179,31 @@ module Seq =
split StringSplitOptions.None
/// Replaces a subsequence of the source seq with the given replacement seq.
- let replace (oldValue: seq<'T>) (newValue: seq<'T>) (source: seq<'T>) : seq<'T> = seq {
- let old = oldValue |> Seq.toList
- if old.Length = 0 then
- yield! source
- else
- let candidate = ResizeArray old.Length
- let mutable sindex = 0
- for item in source do
- candidate.Add item
- if item = old.[sindex] then
- sindex <- sindex + 1
- if sindex >= old.Length then
+ let replace (oldValue: seq<'T>) (newValue: seq<'T>) (source: seq<'T>) : seq<'T> =
+ let oldValue = nullArgCheck (nameof oldValue) oldValue
+ let newValue = nullArgCheck (nameof newValue) newValue
+ let source = nullArgCheck (nameof source) source
+
+ seq {
+ let old = Seq.toList oldValue
+ if old.Length = 0 then
+ yield! source
+ else
+ let candidate = ResizeArray old.Length
+ let mutable sindex = 0
+ for item in source do
+ candidate.Add item
+ if item = old.[sindex] then
+ sindex <- sindex + 1
+ if sindex >= old.Length then
+ sindex <- 0
+ yield! newValue
+ candidate.Clear ()
+ else
sindex <- 0
- yield! newValue
+ yield! candidate
candidate.Clear ()
- else
- sindex <- 0
- yield! candidate
- candidate.Clear ()
- yield! candidate }
+ yield! candidate }
/// Returns a sequence that drops N elements of the original sequence and then yields the
/// remaining elements of the sequence.
@@ -176,7 +213,9 @@ module Seq =
/// The input sequence.
///
/// The result sequence.
- let drop count (source: seq<_>) =
+ let drop count (source: seq<_>) : seq<_> =
+ let source = nullArgCheck (nameof source) source
+
seq {
let mutable i = count
@@ -196,7 +235,7 @@ module Seq =
/// Note: this function has since been added to FSharp.Core.
/// It will be removed in next major release of FSharpPlus.
///
- let replicate count initial = Linq.Enumerable.Repeat (initial, count)
+ let replicate count (initial: 'T) : seq<'T> = Linq.Enumerable.Repeat (initial, count)
#endif
open System.Collections.ObjectModel
@@ -207,7 +246,8 @@ module Seq =
/// Converts a seq to an IReadOnlyList (from System.Collections.Generic).
/// The seq source
/// The seq converted to a System.Collections.Generic.IReadOnlyList
- let toIReadOnlyList (source: seq<_>) = source |> ResizeArray |> ReadOnlyCollection :> IReadOnlyList<_>
+ let toIReadOnlyList (source: seq<'T>) : IReadOnlyList<'T> =
+ source |> nullArgCheck (nameof source) |> ResizeArray |> ReadOnlyCollection :> IReadOnlyList<_>
#endif
#if !FABLE_COMPILER
///
@@ -224,7 +264,10 @@ module Seq =
///
/// The index of the slice.
///
- let findSliceIndex (slice: seq<_>) (source: seq<_>) =
+ let findSliceIndex (slice: seq<'T>) (source: seq<'T>) : int =
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
+
#if !FABLE_COMPILER
let index = Internals.FindSliceIndex.seqImpl slice source
#else
@@ -247,7 +290,10 @@ module Seq =
///
/// The index of the slice or None.
///
- let tryFindSliceIndex (slice: seq<_>) (source: seq<_>) =
+ let tryFindSliceIndex (slice: seq<'T>) (source: seq<'T>) : int option =
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
+
#if !FABLE_COMPILER
let index = Internals.FindSliceIndex.seqImpl slice source
#else
@@ -268,7 +314,10 @@ module Seq =
///
/// The index of the slice.
///
- let findLastSliceIndex (slice: seq<_>) (source: seq<_>) =
+ let findLastSliceIndex (slice: seq<'T>) (source: seq<'T>) : int =
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
+
#if !FABLE_COMPILER
let index = Internals.FindLastSliceIndex.seqImpl slice source
#else
@@ -290,7 +339,10 @@ module Seq =
///
/// The index of the slice or None.
///
- let tryFindLastSliceIndex (slice: seq<_>) (source: seq<_>) =
+ let tryFindLastSliceIndex (slice: seq<'T>) (source: seq<'T>) : int option =
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
+
#if !FABLE_COMPILER
let index = Internals.FindLastSliceIndex.seqImpl slice source
#else
@@ -304,6 +356,8 @@ module Seq =
/// The input seq.
///
/// Seq with values x for each List value where the function returns Some(x).
- let choosei mapping source =
- Seq.indexed source
+ let choosei (mapping: int -> 'T -> 'U option) (source: seq<'T>) : seq<'U> =
+ source
+ |> nullArgCheck (nameof source)
+ |> Seq.indexed
|> Seq.choose (fun (a, b) -> mapping a b)
diff --git a/src/FSharpPlus/Extensions/String.fs b/src/FSharpPlus/Extensions/String.fs
index 7eddcd68f..f18b241e5 100644
--- a/src/FSharpPlus/Extensions/String.fs
+++ b/src/FSharpPlus/Extensions/String.fs
@@ -10,77 +10,77 @@ module String =
/// Concatenates all elements, using the specified separator between each element.
let intercalate (separator: string) (source: seq) =
- raiseIfNull (nameof separator) separator
- raiseIfNull (nameof source) source
+ let separator = nullArgCheck (nameof separator) separator
+ let source = nullArgCheck (nameof source) source
String.Join (separator, source)
/// Inserts a separator char between each char in the source string.
let intersperse (element: char) (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
String.Join ("", Array.ofSeq (source |> Seq.intersperse element))
/// Creates a sequence of strings by splitting the source string on any of the given separators.
let split (separators: seq) (source: string) =
- raiseIfNull (nameof separators) separators
- raiseIfNull (nameof source) source
+ let separators = nullArgCheck (nameof separators) separators
+ let source = nullArgCheck (nameof source) source
source.Split (Seq.toArray separators, StringSplitOptions.None) :> seq<_>
/// Replaces a substring with the given replacement string.
let replace (oldValue: string) newValue (source: string) =
- raiseIfNull (nameof oldValue) oldValue
- raiseIfNull (nameof source) source
+ let oldValue = nullArgCheck (nameof oldValue) oldValue
+ let source = nullArgCheck (nameof source) source
if oldValue.Length = 0 then source else source.Replace (oldValue, newValue)
/// Does the source string contain the given subString? -- function wrapper for String.Contains method.
let isSubString (subString: string) (source: string) =
- raiseIfNull (nameof subString) subString
- raiseIfNull (nameof source) source
+ let subString = nullArgCheck (nameof subString) subString
+ let source = nullArgCheck (nameof source) source
source.Contains subString
/// Does the source string start with the given subString? -- function wrapper for String.StartsWith method using InvariantCulture.
let startsWith (subString: string) (source: string) =
- raiseIfNull (nameof subString) subString
- raiseIfNull (nameof source) source
+ let subString = nullArgCheck (nameof subString) subString
+ let source = nullArgCheck (nameof source) source
source.StartsWith (subString, false, CultureInfo.InvariantCulture)
/// Does the source string end with the given subString? -- function wrapper for String.EndsWith method using InvariantCulture.
- let endsWith subString (source: string) =
- raiseIfNull (nameof subString) subString
- raiseIfNull (nameof source) source
+ let endsWith (subString: string) (source: string) =
+ let subString = nullArgCheck (nameof subString) subString
+ let source = nullArgCheck (nameof source) source
source.EndsWith (subString, false, CultureInfo.InvariantCulture)
/// Does the source string contain the given character?
/// Use `String.isSubstring` to check for strings.
let contains char (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
Seq.contains char source
/// Converts to uppercase -- function wrapper for String.ToUpperInvariant method.
let toUpper (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
- if isNull source then source else source.ToUpperInvariant ()
+ source.ToUpperInvariant ()
/// Converts to lowercase -- function wrapper for String.ToLowerInvariant method.
let toLower (source: string) =
- raiseIfNull (nameof source) source
-
- if isNull source then source else source.ToLowerInvariant ()
+ let source = nullArgCheck (nameof source) source
+
+ source.ToLowerInvariant ()
/// Trims leading and trailing white spaces -- function wrapper for String.Trim method.
///
/// Note this is distinct from trim which trims the given characters,
/// not white spaces.
let trim (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.Trim ()
@@ -89,7 +89,7 @@ module String =
/// Note this is distinct from trim which trims the given characters,
/// not white spaces.
let trimStartWhiteSpaces (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.TrimStart ()
@@ -98,7 +98,7 @@ module String =
/// Note this is distinct from trim which trims the given characters,
/// not white spaces.
let trimEndWhiteSpaces (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.TrimEnd ()
@@ -106,8 +106,11 @@ module String =
/// Returns a new string whose textual value is the same as this string, but whose binary representation is in the specified Unicode normalization form.
///
- /// This is a null safe function wrapper of the String.Normalize method.
- let normalize normalizationForm (source: string) = if isNull source then source else source.Normalize normalizationForm
+ /// This is a function wrapper of the String.Normalize method.
+ let normalize normalizationForm (source: string) =
+ let source = nullArgCheck (nameof source) source
+
+ source.Normalize normalizationForm
/// Removes diacritics (accents) from the given source string.
///
@@ -115,71 +118,71 @@ module String =
/// (basically separating the "base" characters from the diacritics) and then scans
/// the result and retains only the base characters.
let removeDiacritics (source: string) =
- if isNull source then source
- else
- source
- |> normalize NormalizationForm.FormD
- |> String.filter (fun ch -> CharUnicodeInfo.GetUnicodeCategory ch <> UnicodeCategory.NonSpacingMark)
- |> normalize NormalizationForm.FormC
+ let source = nullArgCheck (nameof source) source
+
+ source
+ |> normalize NormalizationForm.FormD
+ |> String.filter (fun ch -> CharUnicodeInfo.GetUnicodeCategory ch <> UnicodeCategory.NonSpacingMark)
+ |> normalize NormalizationForm.FormC
#endif
/// Pads the beginning of the given string with spaces so that it has a specified total length.
let padLeft totalLength (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.PadLeft totalLength
/// Pads the beginning of the given string with a specified character so that it has a specified total length.
let padLeftWith totalLength paddingChar (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.PadLeft (totalLength, paddingChar)
/// Pads the end of the given string with spaces so that it has a specified total length.
let padRight totalLength (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.PadRight totalLength
/// Pads the end of the given string with a specified character so that it has a specified total length.
let padRightWith totalLength paddingChar (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.PadRight (totalLength, paddingChar)
/// Removes all leading and trailing occurrences of specified characters from the given string.
let trimBoth (trimChars: char seq) (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.Trim (Seq.toArray trimChars)
/// Removes all leading occurrences of specified characters from the given string.
let trimStart (trimChars: char seq) (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.TrimStart (Seq.toArray trimChars)
/// Removes all trailing occurrences of specified characters from the given string.
let trimEnd (trimChars: char seq) (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.TrimEnd (Seq.toArray trimChars)
/// Converts the given string to an array of chars.
let toArray (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.ToCharArray ()
/// Converts an array of chars to a String.
let ofArray (source: char []) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
String (source)
/// Converts the given string to a list of chars.
let toList (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
toArray source |> List.ofArray
@@ -188,13 +191,13 @@ module String =
/// Converts the given string to a seq of chars.
let toSeq (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source :> seq
/// Converts a seq of chars to a String.
let ofSeq (source: seq) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
String.Join (String.Empty, source)
@@ -205,20 +208,20 @@ module String =
/// Note: this is not exception safe, and will throw System.IndexOutOfRangeException when
/// the given index is out of bounds.
let item (index: int) (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source.[index]
/// Returns the char (as an Option) at the given index in the source string,
/// returning `None` if out of bounds.
let tryItem (index: int) (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
if index >= 0 && index < source.Length then Some source.[index] else None
/// Reverses the given string.
let rev (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
String (source.ToCharArray () |> Array.rev)
@@ -228,7 +231,7 @@ module String =
/// Note: will throw System.ArgumentOutOfRangeException if you try to take more than the
/// number of chars in the string.
let take count (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source[..count-1]
@@ -238,13 +241,13 @@ module String =
/// Note: will throw System.ArgumentOutOfRangeException if you try to skip more than the
/// number of chars in the string.
let skip count (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source[count..]
/// Takes chars from the source string while the given predicate is true.
let takeWhile (predicate: char -> bool) (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
if String.IsNullOrEmpty source then
String.Empty
@@ -258,7 +261,7 @@ module String =
/// Skips over chars from the source string while the given predicate is true.
let skipWhile (predicate: char -> bool) (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
if String.IsNullOrEmpty source then
String.Empty
@@ -273,14 +276,14 @@ module String =
/// Gets the first char of the string, or
/// None if the string is empty.
let tryHead (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
if String.length source = 0 then None else Some source.[0]
/// Gets the last char of the string, or
/// None if the string is empty.
let tryLast (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
let length = String.length source
if length = 0 then None else Some source.[length-1]
@@ -288,7 +291,7 @@ module String =
/// Returns a string that has at most N characters from the beginning of the original string.
/// It returns the original string if it is shorter than count.
let truncate count (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
if count < 1 then String.Empty
else if String.length source <= count then source
@@ -297,7 +300,7 @@ module String =
/// Returns a string that drops first N characters of the original string.
/// When count exceeds the length of the string it returns an empty string.
let drop count (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
if count < 1 then source
else if String.length source <= count then String.Empty
@@ -307,7 +310,7 @@ module String =
///
/// Note: throws an ArgumentException when not found.
let findIndex (predicate: char -> bool) (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
let rec go index =
if index >= source.Length then
@@ -318,7 +321,7 @@ module String =
/// Tries to find the first index of the char in the substring which satisfies the given predicate.
let tryFindIndex (predicate: char -> bool) (source: string) =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
let rec go index =
if index >= source.Length then None
@@ -336,8 +339,8 @@ module String =
/// The index of the slice.
///
let findSliceIndex (slice: string) (source: string) =
- raiseIfNull (nameof slice) slice
- raiseIfNull (nameof source) source
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
let index = source.IndexOf slice
if index = -1 then
@@ -369,8 +372,8 @@ module String =
/// The index of the slice or None.
///
let tryFindSliceIndex (slice: string) (source: string) =
- raiseIfNull (nameof slice) slice
- raiseIfNull (nameof source) source
+ let slice = nullArgCheck (nameof slice) slice
+ let source = nullArgCheck (nameof source) source
let index = source.IndexOf slice
if index = -1 then None else Some index
@@ -390,7 +393,7 @@ module String =
/// Converts the given string to an array of Int32 code-points (the actual Unicode Code Point number).
let toCodePoints (source : string) : seq =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
let mapper i c =
// Ignore the low-surrogate because it's already been converted
@@ -400,14 +403,14 @@ module String =
/// Converts the array of Int32 code-points (the actual Unicode Code Point number) to a string.
let ofCodePoints (source: seq) : string =
- raiseIfNull (nameof source) source
+ let source = nullArgCheck (nameof source) source
source |> Seq.map Char.ConvertFromUtf32 |> String.concat String.Empty
#endif
/// Converts a string to a byte-array using the specified encoding.
let getBytes (encoding: Encoding) (source: string) : byte [] =
- raiseIfNull (nameof encoding) encoding
- raiseIfNull (nameof source) source
+ let encoding = nullArgCheck (nameof encoding) encoding
+ let source = nullArgCheck (nameof source) source
encoding.GetBytes source
diff --git a/src/FSharpPlus/Extensions/Task.fs b/src/FSharpPlus/Extensions/Task.fs
index 66a3fe79a..1ca8a6628 100644
--- a/src/FSharpPlus/Extensions/Task.fs
+++ b/src/FSharpPlus/Extensions/Task.fs
@@ -9,14 +9,17 @@ module Task =
open System
open System.Threading
open System.Threading.Tasks
+ open FSharpPlus.Internals.Errors
let private (|Canceled|Faulted|Completed|) (t: Task<'a>) =
if t.IsCanceled then Canceled
- else if t.IsFaulted then Faulted t.Exception
+ else if t.IsFaulted then Faulted (Unchecked.nonNull t.Exception)
else Completed t.Result
/// Creates a task workflow from 'source' another, mapping its result with 'f'.
let map (f: 'T -> 'U) (source: Task<'T>) : Task<'U> =
+ let source = nullArgCheck (nameof source) source
+
if source.Status = TaskStatus.RanToCompletion then
try Task.FromResult (f source.Result)
with e ->
@@ -26,7 +29,7 @@ module Task =
else
let tcs = TaskCompletionSource<'U> ()
if source.Status = TaskStatus.Faulted then
- tcs.SetException source.Exception.InnerExceptions
+ tcs.SetException (Unchecked.nonNull source.Exception).InnerExceptions
tcs.Task
elif source.Status = TaskStatus.Canceled then
tcs.SetCanceled ()
@@ -47,6 +50,9 @@ module Task =
/// First task workflow.
/// Second task workflow.
let lift2 (f: 'T -> 'U -> 'V) (x: Task<'T>) (y: Task<'U>) : Task<'V> =
+ let x = nullArgCheck (nameof x) x
+ let y = nullArgCheck (nameof y) y
+
if x.Status = TaskStatus.RanToCompletion && y.Status = TaskStatus.RanToCompletion then
try Task.FromResult (f x.Result y.Result)
with e ->
@@ -57,9 +63,9 @@ module Task =
let tcs = TaskCompletionSource<'V> ()
match x.Status, y.Status with
| TaskStatus.Canceled, _ -> tcs.SetCanceled ()
- | TaskStatus.Faulted, _ -> tcs.SetException x.Exception.InnerExceptions
+ | TaskStatus.Faulted, _ -> tcs.SetException (Unchecked.nonNull x.Exception).InnerExceptions
| _, TaskStatus.Canceled -> tcs.SetCanceled ()
- | _, TaskStatus.Faulted -> tcs.SetException y.Exception.InnerExceptions
+ | _, TaskStatus.Faulted -> tcs.SetException (Unchecked.nonNull y.Exception).InnerExceptions
| TaskStatus.RanToCompletion, _ ->
let k = function
| Canceled -> tcs.SetCanceled ()
@@ -98,22 +104,26 @@ module Task =
/// First task workflow.
/// Second task workflow.
/// Third task workflow.
- let lift3 (f : 'T -> 'U -> 'V -> 'W) (x : Task<'T>) (y : Task<'U>) (z: Task<'V>) : Task<'W> =
+ let lift3 (f : 'T1 -> 'T2 -> 'T3 -> 'U) (x : Task<'T1>) (y : Task<'T2>) (z: Task<'T3>) : Task<'U> =
+ let x = nullArgCheck (nameof x) x
+ let y = nullArgCheck (nameof y) y
+ let z = nullArgCheck (nameof z) z
+
if x.Status = TaskStatus.RanToCompletion && y.Status = TaskStatus.RanToCompletion && z.Status = TaskStatus.RanToCompletion then
try Task.FromResult (f x.Result y.Result z.Result)
with e ->
- let tcs = TaskCompletionSource<'W> ()
+ let tcs = TaskCompletionSource<'U> ()
tcs.SetException e
tcs.Task
else
- let tcs = TaskCompletionSource<'W> ()
+ let tcs = TaskCompletionSource<'U> ()
match x.Status, y.Status, z.Status with
| TaskStatus.Canceled, _ , _ -> tcs.SetCanceled ()
- | TaskStatus.Faulted , _ , _ -> tcs.SetException x.Exception.InnerExceptions
+ | TaskStatus.Faulted , _ , _ -> tcs.SetException (Unchecked.nonNull x.Exception).InnerExceptions
| _ , TaskStatus.Canceled, _ -> tcs.SetCanceled ()
- | _ , TaskStatus.Faulted , _ -> tcs.SetException y.Exception.InnerExceptions
+ | _ , TaskStatus.Faulted , _ -> tcs.SetException (Unchecked.nonNull y.Exception).InnerExceptions
| _ , _ , TaskStatus.Canceled -> tcs.SetCanceled ()
- | _ , _ , TaskStatus.Faulted -> tcs.SetException z.Exception.InnerExceptions
+ | _ , _ , TaskStatus.Faulted -> tcs.SetException (Unchecked.nonNull z.Exception).InnerExceptions
| _ , _ , _ ->
x.ContinueWith (
function
@@ -143,6 +153,9 @@ module Task =
/// First Task workflow.
/// Second Task workflow.
let map2 mapper (task1: Task<'T1>) (task2: Task<'T2>) : Task<'U> =
+ let task1 = nullArgCheck (nameof task1) task1
+ let task2 = nullArgCheck (nameof task2) task2
+
if task1.Status = TaskStatus.RanToCompletion && task2.Status = TaskStatus.RanToCompletion then
try Task.FromResult (mapper task1.Result task2.Result)
with e ->
@@ -190,6 +203,10 @@ module Task =
/// Second Task workflow.
/// Third Task workflow.
let map3 mapper (task1: Task<'T1>) (task2: Task<'T2>) (task3: Task<'T3>) : Task<'U> =
+ let task1 = nullArgCheck (nameof task1) task1
+ let task2 = nullArgCheck (nameof task2) task2
+ let task3 = nullArgCheck (nameof task3) task3
+
if task1.Status = TaskStatus.RanToCompletion && task2.Status = TaskStatus.RanToCompletion && task3.Status = TaskStatus.RanToCompletion then
try Task.FromResult (mapper task1.Result task2.Result task3.Result)
with e ->
@@ -236,6 +253,9 @@ module Task =
/// Task workflow returning a function
/// Task workflow returning a value
let apply (f: Task<'T->'U>) (x: Task<'T>) : Task<'U> =
+ let f = nullArgCheck (nameof f) f
+ let x = nullArgCheck (nameof x) x
+
if f.Status = TaskStatus.RanToCompletion && x.Status = TaskStatus.RanToCompletion then
try Task.FromResult (f.Result x.Result)
with e ->
@@ -246,9 +266,9 @@ module Task =
let tcs = TaskCompletionSource<'U> ()
match f.Status, x.Status with
| TaskStatus.Canceled, _ -> tcs.SetCanceled ()
- | TaskStatus.Faulted, _ -> tcs.SetException f.Exception.InnerExceptions
+ | TaskStatus.Faulted, _ -> tcs.SetException (Unchecked.nonNull f.Exception).InnerExceptions
| _, TaskStatus.Canceled -> tcs.SetCanceled ()
- | _, TaskStatus.Faulted -> tcs.SetException x.Exception.InnerExceptions
+ | _, TaskStatus.Faulted -> tcs.SetException (Unchecked.nonNull x.Exception).InnerExceptions
| TaskStatus.RanToCompletion, _ ->
let k = function
| Canceled -> tcs.SetCanceled ()
@@ -283,15 +303,18 @@ module Task =
/// Creates a task workflow from two workflows 'x' and 'y', tupling its results.
let zipSequentially (x: Task<'T>) (y: Task<'U>) : Task<'T * 'U> =
+ let x = nullArgCheck (nameof x) x
+ let y = nullArgCheck (nameof y) y
+
if x.Status = TaskStatus.RanToCompletion && y.Status = TaskStatus.RanToCompletion then
Task.FromResult (x.Result, y.Result)
else
let tcs = TaskCompletionSource<'T * 'U> ()
match x.Status, y.Status with
| TaskStatus.Canceled, _ -> tcs.SetCanceled ()
- | TaskStatus.Faulted, _ -> tcs.SetException x.Exception.InnerExceptions
+ | TaskStatus.Faulted, _ -> tcs.SetException (Unchecked.nonNull x.Exception).InnerExceptions
| _, TaskStatus.Canceled -> tcs.SetCanceled ()
- | _, TaskStatus.Faulted -> tcs.SetException y.Exception.InnerExceptions
+ | _, TaskStatus.Faulted -> tcs.SetException (Unchecked.nonNull y.Exception).InnerExceptions
| TaskStatus.RanToCompletion, _ ->
let k = function
| Canceled -> tcs.SetCanceled ()
@@ -329,25 +352,30 @@ module Task =
let zip3 (task1: Task<'T1>) (task2: Task<'T2>) (task3: Task<'T3>) = map3 (fun x y z -> x, y, z) task1 task2 task3
/// Flattens two nested tasks into one.
- let join (source: Task>) : Task<'T> = source.Unwrap()
+ let join (source: Task>) : Task<'T> =
+ let source = nullArgCheck (nameof source) source
+
+ source.Unwrap()
/// Creates a task workflow from 'source' workflow, mapping and flattening its result with 'f'.
- let bind (f: 'T -> Task<'U>) (source: Task<'T>) : Task<'U> = source |> map f |> join
+ let bind (f: 'T -> Task<'U>) (source: Task<'T>) : Task<'U> = source |> Unchecked.nonNull |> map f |> join
/// Creates a task that ignores the result of the source task.
/// It can be used to convert non-generic Task to unit Task.
let ignore (task: Task) =
+ let task = nullArgCheck (nameof task) task
+
if task.Status = TaskStatus.RanToCompletion then Task.FromResult ()
else
let tcs = TaskCompletionSource ()
if task.Status = TaskStatus.Faulted then
- tcs.SetException task.Exception.InnerExceptions
+ tcs.SetException (Unchecked.nonNull task.Exception).InnerExceptions
elif task.Status = TaskStatus.Canceled then
tcs.SetCanceled ()
else
let k (t: Task) : unit =
if t.IsCanceled then tcs.SetCanceled ()
- elif t.IsFaulted then tcs.SetException t.Exception
+ elif t.IsFaulted then tcs.SetException (Unchecked.nonNull t.Exception).InnerExceptions
else tcs.SetResult ()
task.ContinueWith k |> ignore
tcs.Task
@@ -361,7 +389,7 @@ module Task =
let task = body ()
match task.Status with
| TaskStatus.RanToCompletion -> task
- | TaskStatus.Faulted -> task.ContinueWith((fun (x:Task<'T>) -> compensation (unwrapException x.Exception))).Unwrap ()
+ | TaskStatus.Faulted -> task.ContinueWith((fun (x:Task<'T>) -> compensation (unwrapException (Unchecked.nonNull x.Exception)))).Unwrap ()
| TaskStatus.Canceled -> task
| _ -> task.ContinueWith((fun (x:Task<'T>) -> tryWith (fun () -> x) compensation) ).Unwrap ()
with
@@ -389,13 +417,13 @@ module Task =
reraise ()
/// Used to de-sugar use .. blocks in Computation Expressions.
- let using (disp: #IDisposable) (body: _ -> Task<'a>) =
+ let using (disp: 'T when 'T :> IDisposable) (body: 'T -> Task<'U>) =
tryFinally
(fun () -> body disp)
(fun () -> if not (isNull (box disp)) then disp.Dispose ())
/// Creates a Task from a value
- let result value = Task.FromResult value
+ let result (value: 'T) = Task.FromResult value
/// Raises an exception in the Task
let raise<'T> (e: exn) =
diff --git a/src/FSharpPlus/Extensions/ValueTask.fs b/src/FSharpPlus/Extensions/ValueTask.fs
index cc0152070..952c4a34c 100644
--- a/src/FSharpPlus/Extensions/ValueTask.fs
+++ b/src/FSharpPlus/Extensions/ValueTask.fs
@@ -9,13 +9,14 @@ module ValueTask =
open System
open System.Threading
open System.Threading.Tasks
+ open FSharpPlus.Internals.Errors
- let inline internal (|Succeeded|Canceled|Faulted|) (t: ValueTask<'T>) =
+ let inline (|Succeeded|Canceled|Faulted|) (t: ValueTask<'T>) =
if t.IsCompletedSuccessfully then Succeeded t.Result
elif t.IsCanceled then Canceled
- else Faulted (t.AsTask().Exception)
+ else Faulted (t.AsTask().Exception |> Unchecked.nonNull)
- let inline internal continueTask (tcs: TaskCompletionSource<'Result>) (x: ValueTask<'t>) (k: 't -> unit) =
+ let inline continueTask (tcs: TaskCompletionSource<'Result>) (x: ValueTask<'t>) (k: 't -> unit) =
let f = function
| Succeeded r -> k r
| Canceled -> tcs.SetCanceled ()
@@ -23,7 +24,7 @@ module ValueTask =
if x.IsCompleted then f x
else x.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted (fun () -> f x)
- let inline internal continueWith (x: ValueTask<'t>) f =
+ let inline continueWith (x: ValueTask<'t>) f =
if x.IsCompleted then f x
else x.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted (fun () -> f x)
diff --git a/src/FSharpPlus/Internals.fs b/src/FSharpPlus/Internals.fs
index d3bf01922..d84400139 100644
--- a/src/FSharpPlus/Internals.fs
+++ b/src/FSharpPlus/Internals.fs
@@ -49,9 +49,12 @@ module Errors =
let exnNoSubtraction = new System.Exception "No subtraction defined for these values in this domain."
let exnUnreachable = new System.InvalidOperationException "This execution path is unreachable."
- let inline raiseIfNull paramName paramValue =
- if isNull paramValue then
- nullArg paramName
+ // Functions to remove when compiling with F#9 or higher
+ let inline nullArgCheck paramName paramValue =
+ if isNull paramValue then nullArg paramName
+ else paramValue
+
+ module Unchecked = let nonNull = id
module Decimal =
let inline trySqrt x =
@@ -145,6 +148,7 @@ type NonEmptySeq2<'T> =
#nowarn "51"
open System
open Microsoft.FSharp.NativeInterop
+open Errors // TODO: see if it makes sense to move checks to calling site
type BitConverter =
/// Converts a byte into an array of bytes with length one.
@@ -227,7 +231,7 @@ type BitConverter =
/// Converts an array of bytes into a short.
static member ToInt16 (value: byte[], startIndex: int, isLittleEndian: bool) =
- if isNull value then nullArg "value"
+ let value = nullArgCheck (nameof value) value
if startIndex >= value.Length then raise <| new ArgumentOutOfRangeException ("startIndex", "ArgumentOutOfRange_Index")
if startIndex > value.Length - 2 then raise <| new ArgumentException "Arg_ArrayPlusOffTooSmall"
use pbyte = fixed &value.[startIndex]
@@ -239,7 +243,7 @@ type BitConverter =
/// Converts an array of bytes into an int.
static member ToInt32 (value: byte[], startIndex: int, isLittleEndian: bool) : int =
- if isNull value then nullArg "value"
+ let value = nullArgCheck (nameof value) value
if startIndex >= value.Length then raise <| new ArgumentOutOfRangeException ("startIndex", "ArgumentOutOfRange_Index")
if startIndex > value.Length - 4 then raise <| new ArgumentException "Arg_ArrayPlusOffTooSmall"
use pbyte = fixed &value.[startIndex]
@@ -251,7 +255,7 @@ type BitConverter =
/// Converts an array of bytes into a long.
static member ToInt64 (value: byte[], startIndex: int, isLittleEndian: bool) =
- if isNull value then nullArg "value"
+ let value = nullArgCheck (nameof value) value
if startIndex >= value.Length then raise <| new ArgumentOutOfRangeException ("startIndex", "ArgumentOutOfRange_Index")
if startIndex > value.Length - 8 then raise <| new ArgumentException "Arg_ArrayPlusOffTooSmall"
use pbyte = fixed &value.[startIndex]
@@ -268,7 +272,7 @@ type BitConverter =
i2 ||| (i1 <<< 32)
static member ToGuid (value: byte[], startIndex: int, isLittleEndian: bool) =
- if isNull value then nullArg "value"
+ let value = nullArgCheck (nameof value) value
if startIndex >= value.Length then raise <| new ArgumentOutOfRangeException ("startIndex", "ArgumentOutOfRange_Index")
if startIndex > value.Length - 16 then raise <| new ArgumentException "Arg_ArrayPlusOffTooSmall"
if isLittleEndian then
@@ -311,7 +315,7 @@ type BitConverter =
/// Converts an array of bytes into a String.
static member ToString (value: byte [], startIndex, length) =
- if isNull value then nullArg "value"
+ let value = nullArgCheck (nameof value) value
let arrayLen = value.Length
if startIndex >= value.Length then raise <| new ArgumentOutOfRangeException ("startIndex", "ArgumentOutOfRange_StartIndex")
let realLength = length
@@ -333,12 +337,12 @@ type BitConverter =
/// Converts an array of bytes into a String.
static member ToString (value: byte []) =
- if isNull value then nullArg "value"
+ let value = nullArgCheck (nameof value) value
BitConverter.ToString (value, 0, value.Length)
/// Converts an array of bytes into a String.
static member ToString (value: byte [], startIndex) =
- if isNull value then nullArg "value"
+ let value = nullArgCheck (nameof value) value
BitConverter.ToString (value, startIndex, value.Length - startIndex)
#if !FABLE_COMPILER