diff --git a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/OptionModule.fs b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/OptionModule.fs index 595eb7457cc..8c7c48c542a 100644 --- a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/OptionModule.fs +++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/OptionModule.fs @@ -215,4 +215,16 @@ type OptionModule() = member this.MapBindEquivalenceProperties () = let fn x = x + 3 Assert.AreEqual(Option.map fn None, Option.bind (fn >> Some) None) - Assert.AreEqual(Option.map fn (Some 5), Option.bind (fn >> Some) (Some 5)) \ No newline at end of file + Assert.AreEqual(Option.map fn (Some 5), Option.bind (fn >> Some) (Some 5)) + + [] + member this.ToSeq() = + Assert.IsFalse(Some 5 |> Option.toSeq |> Seq.isEmpty) + Assert.AreEqual(Some 5 |> Option.toSeq |> Seq.length, 1) + Assert.AreEqual(Some 5 |> Option.toSeq |> Seq.tryHead, Some 5) + Assert.IsFalse(Some "" |> Option.toSeq |> Seq.isEmpty) + Assert.AreEqual(Some "" |> Option.toSeq |> Seq.length, 1) + Assert.AreEqual(Some "" |> Option.toSeq |> Seq.tryHead, Some "") + Assert.IsTrue(None |> Option.toSeq |> Seq.isEmpty) + Assert.AreEqual(None |> Option.toSeq |> Seq.length, 0) + Assert.AreEqual(None |> Option.toSeq |> Seq.tryHead, None) \ No newline at end of file diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs index f2f634cab1f..afe19270481 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs @@ -2732,6 +2732,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.String ToString() Microsoft.FSharp.Core.OptionModule: System.Type GetType() diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs index 99d38a69f95..25cdc6ff9a4 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs @@ -2766,6 +2766,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.String ToString() Microsoft.FSharp.Core.OptionModule: System.Type GetType() diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs index d799117f863..dfd3167fdf0 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs @@ -2737,6 +2737,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.String ToString() Microsoft.FSharp.Core.OptionModule: System.Type GetType() diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs index 9c0f389633d..8bf07402cbc 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs @@ -2738,6 +2738,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.String ToString() Microsoft.FSharp.Core.OptionModule: System.Type GetType() diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs index b9de41ca1eb..20a66a5b6da 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs @@ -2750,6 +2750,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.String ToString() Microsoft.FSharp.Core.OptionModule: System.Type GetType() diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs index aedaca4bff3..50dfb1b011e 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs @@ -2737,6 +2737,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: System.String ToString() Microsoft.FSharp.Core.OptionModule: System.Type GetType() diff --git a/src/fsharp/FSharp.Core/local.fs b/src/fsharp/FSharp.Core/local.fs index 7df2e049e8f..c402e6377b4 100644 --- a/src/fsharp/FSharp.Core/local.fs +++ b/src/fsharp/FSharp.Core/local.fs @@ -84,6 +84,62 @@ open Microsoft.FSharp.Core.ICloneableExtensions #else #endif +module internal IEnumerator = + let noReset() = raise (new System.NotSupportedException(SR.GetString(SR.resetNotSupported))) + let notStarted() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationNotStarted))) + let alreadyFinished() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationAlreadyFinished))) + let check started = if not started then notStarted() + + let mkSeq f = + { new IEnumerable<'U> with + member x.GetEnumerator() = f() + interface System.Collections.IEnumerable with + member x.GetEnumerator() = (f() :> System.Collections.IEnumerator) } + + /// A concrete implementation of an enumerator that returns no values + [] + type EmptyEnumerator<'T>() = + let mutable started = false + interface IEnumerator<'T> with + member x.Current = + check started + (alreadyFinished() : 'T) + + interface System.Collections.IEnumerator with + member x.Current = + check started + (alreadyFinished() : obj) + member x.MoveNext() = + if not started then started <- true + false + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () + + let empty<'T> () = (new EmptyEnumerator<'T>() :> IEnumerator<'T>) + + [] + type EmptyEnumerable<'T> = + | EmptyEnumerable + interface IEnumerable<'T> with + member x.GetEnumerator() = empty<'T>() + interface System.Collections.IEnumerable with + member x.GetEnumerator() = (empty<'T>() :> System.Collections.IEnumerator) + + [] + type Singleton<'T>(v:'T) = + let mutable started = false + interface IEnumerator<'T> with + member x.Current = v + interface System.Collections.IEnumerator with + member x.Current = box v + member x.MoveNext() = if started then false else (started <- true; true) + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () + + let singleton x = new Singleton<'T>(x) :> IEnumerator<'T> + module internal List = diff --git a/src/fsharp/FSharp.Core/local.fsi b/src/fsharp/FSharp.Core/local.fsi index dcf8f2a6e15..d61c367ba0c 100644 --- a/src/fsharp/FSharp.Core/local.fsi +++ b/src/fsharp/FSharp.Core/local.fsi @@ -18,11 +18,28 @@ module internal DetailedExceptions = val invalidArg3ArraysDifferent: arg1:string -> arg2:string -> arg3:string -> len1:int -> len2:int -> len3:int -> _ /// Definitions internal for this library. -namespace Microsoft.FSharp.Primitives.Basics +namespace Microsoft.FSharp.Primitives.Basics open Microsoft.FSharp.Core open Microsoft.FSharp.Collections +module internal IEnumerator = + val noReset : unit -> 'T + val notStarted : unit -> 'T + val alreadyFinished : unit -> 'T + val check : bool -> unit + val mkSeq : (unit -> System.Collections.Generic.IEnumerator<'T>) -> System.Collections.Generic.IEnumerable<'T> + + [] + type EmptyEnumerable<'T> = + | EmptyEnumerable + interface System.Collections.Generic.IEnumerable<'T> + interface System.Collections.IEnumerable + + val Empty : unit -> System.Collections.Generic.IEnumerator<'T> + val Singleton : 'T -> System.Collections.Generic.IEnumerator<'T> + + module internal List = val allPairs : 'T1 list -> 'T2 list -> ('T1 * 'T2) list val choose: ('T -> 'U option) -> 'T list -> 'U list diff --git a/src/fsharp/FSharp.Core/option.fs b/src/fsharp/FSharp.Core/option.fs index 429cfb7abd6..dd91a262d3c 100644 --- a/src/fsharp/FSharp.Core/option.fs +++ b/src/fsharp/FSharp.Core/option.fs @@ -2,6 +2,7 @@ namespace Microsoft.FSharp.Core + open Microsoft.FSharp.Primitives.Basics open Microsoft.FSharp.Core.Operators [] @@ -79,6 +80,9 @@ namespace Microsoft.FSharp.Core [] let toList option = match option with None -> [ ] | Some x -> [ x ] + [] + let toSeq option = match option with Some x -> IEnumerator.mkSeq (fun () -> IEnumerator.Singleton x) | None -> upcast IEnumerator.EmptyEnumerable + [] let toNullable option = match option with None -> System.Nullable() | Some v -> System.Nullable(v) diff --git a/src/fsharp/FSharp.Core/option.fsi b/src/fsharp/FSharp.Core/option.fsi index ecb49808ae4..f9a3e8c16ec 100644 --- a/src/fsharp/FSharp.Core/option.fsi +++ b/src/fsharp/FSharp.Core/option.fsi @@ -174,6 +174,11 @@ namespace Microsoft.FSharp.Core [] val toList: option:'T option -> 'T list + /// Convert the option to a sequence of length 0 or 1. + /// The input option. + /// The result sequence. + [] + val toSeq: option: 'T option -> seq<'T> /// Convert the option to a Nullable value. /// The input option. diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 31c70f57ee6..344924dda74 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -15,11 +15,8 @@ namespace Microsoft.FSharp.Collections module IEnumerator = + open Microsoft.FSharp.Primitives.Basics.IEnumerator - let noReset() = raise (new System.NotSupportedException(SR.GetString(SR.resetNotSupported))) - let notStarted() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationNotStarted))) - let alreadyFinished() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationAlreadyFinished))) - let check started = if not started then notStarted() let dispose (r : System.IDisposable) = r.Dispose() let cast (e : IEnumerator) : IEnumerator<'T> = @@ -35,28 +32,6 @@ namespace Microsoft.FSharp.Collections | :? System.IDisposable as e -> e.Dispose() | _ -> () } - /// A concrete implementation of an enumerator that returns no values - [] - type EmptyEnumerator<'T>() = - let mutable started = false - interface IEnumerator<'T> with - member x.Current = - check started - (alreadyFinished() : 'T) - - interface System.Collections.IEnumerator with - member x.Current = - check started - (alreadyFinished() : obj) - member x.MoveNext() = - if not started then started <- true - false - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () - - let Empty<'T> () = (new EmptyEnumerator<'T>() :> IEnumerator<'T>) - let rec tryItem index (e : IEnumerator<'T>) = if not (e.MoveNext()) then None elif index = 0 then Some(e.Current) @@ -352,20 +327,6 @@ namespace Microsoft.FSharp.Collections let ofArray arr = (new ArrayEnumerator<'T>(arr) :> IEnumerator<'T>) - [] - type Singleton<'T>(v:'T) = - let mutable started = false - interface IEnumerator<'T> with - member x.Current = v - interface IEnumerator with - member x.Current = box v - member x.MoveNext() = if started then false else (started <- true; true) - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () - - let Singleton x = (new Singleton<'T>(x) :> IEnumerator<'T>) - let EnumerateThenFinally f (e : IEnumerator<'T>) = { new IEnumerator<'T> with member x.Current = e.Current @@ -385,6 +346,7 @@ namespace Microsoft.FSharp.Collections // module Generator = + open Microsoft.FSharp.Primitives.Basics open System.Collections open System.Collections.Generic @@ -554,22 +516,8 @@ namespace Microsoft.FSharp.Core.CompilerServices | null -> nullArg argName | _ -> () - let mkSeq f = - { new IEnumerable<'U> with - member x.GetEnumerator() = f() - interface IEnumerable with - member x.GetEnumerator() = (f() :> IEnumerator) } - - [] - type EmptyEnumerable<'T> = - | EmptyEnumerable - interface IEnumerable<'T> with - member x.GetEnumerator() = IEnumerator.Empty<'T>() - interface IEnumerable with - member x.GetEnumerator() = (IEnumerator.Empty<'T>() :> IEnumerator) - let Generate openf compute closef = - mkSeq (fun () -> IEnumerator.generateWhileSome openf compute closef) + IEnumerator.mkSeq (fun () -> IEnumerator.generateWhileSome openf compute closef) let GenerateUsing (openf : unit -> ('U :> System.IDisposable)) compute = Generate openf compute (fun (s:'U) -> s.Dispose()) @@ -684,7 +632,7 @@ namespace Microsoft.FSharp.Core.CompilerServices let ie = outerEnum.Current // Optimization to detect the statically-allocated empty IEnumerables match box ie with - | :? EmptyEnumerable<'T> -> + | :? IEnumerator.EmptyEnumerable<'T> -> // This one is empty, just skip, don't call GetEnumerator, try again takeOuter() | _ -> @@ -712,7 +660,7 @@ namespace Microsoft.FSharp.Core.CompilerServices (fun () -> rest resource :> seq<_>)) :> seq<_>) let mkConcatSeq (sources: seq<'U :> seq<'T>>) = - mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>) + IEnumerator.mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>) let EnumerateWhile (g : unit -> bool) (b: seq<'T>) : seq<'T> = let started = ref false @@ -724,7 +672,7 @@ namespace Microsoft.FSharp.Core.CompilerServices let finish() = (curr := None) mkConcatSeq - (mkSeq (fun () -> + (IEnumerator.mkSeq (fun () -> { new IEnumerator<_> with member x.Current = getCurr() interface IEnumerator with @@ -843,6 +791,8 @@ namespace Microsoft.FSharp.Collections [] module Seq = + open Microsoft.FSharp.Primitives.Basics.IEnumerator + #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions #else @@ -1238,7 +1188,7 @@ namespace Microsoft.FSharp.Collections foldArraySubRight f arr 0 (len - 2) arr.[len - 1] [] - let singleton x = mkSeq (fun () -> IEnumerator.Singleton x) + let singleton x = mkSeq (fun () -> Singleton x) []