diff --git a/src/fsharp/FSharp.Core/FSharp.Core.fsproj b/src/fsharp/FSharp.Core/FSharp.Core.fsproj
index 8ad25ce16c7..d3d795c8bd0 100644
--- a/src/fsharp/FSharp.Core/FSharp.Core.fsproj
+++ b/src/fsharp/FSharp.Core/FSharp.Core.fsproj
@@ -95,6 +95,12 @@
Collections/collections.fs
+
+ Collections/seqcore.fsi
+
+
+ Collections/seqcore.fs
+
Collections/seq.fsi
diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs
index ca062b62d2a..eb60fe3d612 100644
--- a/src/fsharp/FSharp.Core/seq.fs
+++ b/src/fsharp/FSharp.Core/seq.fs
@@ -13,49 +13,9 @@ namespace Microsoft.FSharp.Collections
open Microsoft.FSharp.Control
open Microsoft.FSharp.Collections
- module 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> =
- { new IEnumerator<'T> with
- member x.Current = unbox<'T> e.Current
- interface IEnumerator with
- member x.Current = unbox<'T> e.Current :> obj
- member x.MoveNext() = e.MoveNext()
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() =
- match e with
- | :? 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>)
+ module Internal =
+ module IEnumerator =
+ open Microsoft.FSharp.Collections.IEnumerator
let rec tryItem index (e : IEnumerator<'T>) =
if not (e.MoveNext()) then None
@@ -297,37 +257,6 @@ namespace Microsoft.FSharp.Collections
interface System.IDisposable with
member x.Dispose() = () }
- let readAndClear r =
- lock r (fun () -> match !r with None -> None | Some _ as res -> r := None; res)
-
- let generateWhileSome openf compute closef : IEnumerator<'U> =
- let started = ref false
- let curr = ref None
- let state = ref (Some(openf()))
- let getCurr() =
- check !started
- match !curr with None -> alreadyFinished() | Some x -> x
- let start() = if not !started then (started := true)
-
- let dispose() = readAndClear state |> Option.iter closef
- let finish() = (try dispose() finally curr := None)
- { new IEnumerator<'U> with
- member x.Current = getCurr()
- interface IEnumerator with
- member x.Current = box (getCurr())
- member x.MoveNext() =
- start()
- match !state with
- | None -> false (* we started, then reached the end, then got another MoveNext *)
- | Some s ->
- match (try compute s with e -> finish(); reraise()) with
- | None -> finish(); false
- | Some _ as x -> curr := x; true
-
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() = dispose() }
-
[]
type ArrayEnumerator<'T>(arr: 'T array) =
let mutable curr = -1
@@ -353,35 +282,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
- interface IEnumerator with
- member x.Current = (e :> IEnumerator).Current
- member x.MoveNext() = e.MoveNext()
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() =
- try
- e.Dispose()
- finally
- f()
- }
-
// Use generators for some implementations of IEnumerables.
//
module Generator =
@@ -526,293 +426,6 @@ namespace Microsoft.FSharp.Collections
| :? EnumeratorWrappingLazyGenerator<'T> as e -> e.Generator
| _ -> (new LazyGeneratorWrappingEnumerator<'T>(e) :> Generator<'T>)
-namespace Microsoft.FSharp.Core.CompilerServices
-
- open System
- open System.Diagnostics
- open Microsoft.FSharp.Core
- open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
- open Microsoft.FSharp.Core.Operators
- open Microsoft.FSharp.Control
- open Microsoft.FSharp.Collections
- open Microsoft.FSharp.Primitives.Basics
- open System.Collections
- open System.Collections.Generic
-
- module RuntimeHelpers =
-
- []
- type internal StructBox<'T when 'T:equality>(value:'T) =
- member x.Value = value
- static member Comparer =
- let gcomparer = HashIdentity.Structural<'T>
- { new IEqualityComparer> with
- member __.GetHashCode(v) = gcomparer.GetHashCode(v.Value)
- member __.Equals(v1,v2) = gcomparer.Equals(v1.Value,v2.Value) }
-
- let inline checkNonNull argName arg =
- match box arg with
- | 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)
-
- let GenerateUsing (openf : unit -> ('U :> System.IDisposable)) compute =
- Generate openf compute (fun (s:'U) -> s.Dispose())
-
- let EnumerateFromFunctions opener moveNext current =
- Generate
- opener
- (fun x -> if moveNext x then Some(current x) else None)
- (fun x -> match box(x) with :? System.IDisposable as id -> id.Dispose() | _ -> ())
-
- // A family of enumerators that can have additional 'finally' actions added to the enumerator through
- // the use of mutation. This is used to 'push' the disposal action for a 'use' into the next enumerator.
- // For example,
- // seq { use x = ...
- // while ... }
- // results in the 'while' loop giving an adjustable enumerator. This is then adjusted by adding the disposal action
- // from the 'use' into the enumerator. This means that we avoid constructing a two-deep enumerator chain in this
- // common case.
- type IFinallyEnumerator =
- abstract AppendFinallyAction : (unit -> unit) -> unit
-
- /// A concrete implementation of IEnumerable that adds the given compensation to the "Dispose" chain of any
- /// enumerators returned by the enumerable.
- []
- type FinallyEnumerable<'T>(compensation: unit -> unit, restf: unit -> seq<'T>) =
- interface IEnumerable<'T> with
- member x.GetEnumerator() =
- try
- let ie = restf().GetEnumerator()
- match ie with
- | :? IFinallyEnumerator as a ->
- a.AppendFinallyAction(compensation)
- ie
- | _ ->
- IEnumerator.EnumerateThenFinally compensation ie
- with e ->
- compensation()
- reraise()
- interface IEnumerable with
- member x.GetEnumerator() = ((x :> IEnumerable<'T>).GetEnumerator() :> IEnumerator)
-
- /// An optimized object for concatenating a sequence of enumerables
- []
- type ConcatEnumerator<'T,'U when 'U :> seq<'T>>(sources: seq<'U>) =
- let mutable outerEnum = sources.GetEnumerator()
- let mutable currInnerEnum = IEnumerator.Empty()
-
- let mutable started = false
- let mutable finished = false
- let mutable compensations = []
-
- [] // false = unchecked
- val mutable private currElement : 'T
-
- member x.Finish() =
- finished <- true
- try
- match currInnerEnum with
- | null -> ()
- | _ ->
- try
- currInnerEnum.Dispose()
- finally
- currInnerEnum <- null
- finally
- try
- match outerEnum with
- | null -> ()
- | _ ->
- try
- outerEnum.Dispose()
- finally
- outerEnum <- null
- finally
- let rec iter comps =
- match comps with
- | [] -> ()
- | h::t ->
- try h() finally iter t
- try
- compensations |> List.rev |> iter
- finally
- compensations <- []
-
- member x.GetCurrent() =
- IEnumerator.check started
- if finished then IEnumerator.alreadyFinished() else x.currElement
-
- interface IFinallyEnumerator with
- member x.AppendFinallyAction(f) =
- compensations <- f :: compensations
-
- interface IEnumerator<'T> with
- member x.Current = x.GetCurrent()
-
- interface IEnumerator with
- member x.Current = box (x.GetCurrent())
-
- member x.MoveNext() =
- if not started then (started <- true)
- if finished then false
- else
- let rec takeInner () =
- // check the inner list
- if currInnerEnum.MoveNext() then
- x.currElement <- currInnerEnum.Current
- true
- else
- // check the outer list
- let rec takeOuter() =
- if outerEnum.MoveNext() then
- let ie = outerEnum.Current
- // Optimization to detect the statically-allocated empty IEnumerables
- match box ie with
- | :? EmptyEnumerable<'T> ->
- // This one is empty, just skip, don't call GetEnumerator, try again
- takeOuter()
- | _ ->
- // OK, this one may not be empty.
- // Don't forget to dispose of the enumerator for the inner list now we're done with it
- currInnerEnum.Dispose()
- currInnerEnum <- ie.GetEnumerator()
- takeInner ()
- else
- // We're done
- x.Finish()
- false
- takeOuter()
- takeInner ()
-
- member x.Reset() = IEnumerator.noReset()
-
- interface System.IDisposable with
- member x.Dispose() =
- if not finished then
- x.Finish()
-
- let EnumerateUsing (resource : 'T :> System.IDisposable) (rest: 'T -> #seq<'U>) =
- (FinallyEnumerable((fun () -> match box resource with null -> () | _ -> resource.Dispose()),
- (fun () -> rest resource :> seq<_>)) :> seq<_>)
-
- let mkConcatSeq (sources: seq<'U :> seq<'T>>) =
- mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>)
-
- let EnumerateWhile (g : unit -> bool) (b: seq<'T>) : seq<'T> =
- let started = ref false
- let curr = ref None
- let getCurr() =
- IEnumerator.check !started
- match !curr with None -> IEnumerator.alreadyFinished() | Some x -> x
- let start() = if not !started then (started := true)
-
- let finish() = (curr := None)
- mkConcatSeq
- (mkSeq (fun () ->
- { new IEnumerator<_> with
- member x.Current = getCurr()
- interface IEnumerator with
- member x.Current = box (getCurr())
- member x.MoveNext() =
- start()
- let keepGoing = (try g() with e -> finish (); reraise ()) in
- if keepGoing then
- curr := Some(b); true
- else
- finish(); false
- member x.Reset() = IEnumerator.noReset()
- interface System.IDisposable with
- member x.Dispose() = () }))
-
- let EnumerateThenFinally (rest : seq<'T>) (compensation : unit -> unit) =
- (FinallyEnumerable(compensation, (fun () -> rest)) :> seq<_>)
-
- let CreateEvent (add : 'Delegate -> unit) (remove : 'Delegate -> unit) (create : (obj -> 'Args -> unit) -> 'Delegate ) :IEvent<'Delegate,'Args> =
- // Note, we implement each interface explicitly: this works around a bug in the CLR
- // implementation on CompactFramework 3.7, used on Windows Phone 7
- { new obj() with
- member x.ToString() = ""
- interface IEvent<'Delegate,'Args>
- interface IDelegateEvent<'Delegate> with
- member x.AddHandler(h) = add h
- member x.RemoveHandler(h) = remove h
- interface System.IObservable<'Args> with
- member x.Subscribe(r:IObserver<'Args>) =
- let h = create (fun _ args -> r.OnNext(args))
- add h
- { new System.IDisposable with
- member x.Dispose() = remove h } }
-
-
- []
- type GeneratedSequenceBase<'T>() =
- let mutable redirectTo : GeneratedSequenceBase<'T> = Unchecked.defaultof<_>
- let mutable redirect : bool = false
-
- abstract GetFreshEnumerator : unit -> IEnumerator<'T>
- abstract GenerateNext : next:byref> -> int // 0 = Stop, 1 = Yield, 2 = Goto
- abstract Close: unit -> unit
- abstract CheckClose: bool
- abstract LastGenerated : 'T
-
- //[]
- member x.MoveNextImpl() =
- let active =
- if redirect then redirectTo
- else x
- let mutable target = null
- match active.GenerateNext(&target) with
- | 1 ->
- true
- | 2 ->
- match target.GetEnumerator() with
- | :? GeneratedSequenceBase<'T> as g when not active.CheckClose ->
- redirectTo <- g
- | e ->
- redirectTo <-
- { new GeneratedSequenceBase<'T>() with
- member x.GetFreshEnumerator() = e
- member x.GenerateNext(_) = if e.MoveNext() then 1 else 0
- member x.Close() = try e.Dispose() finally active.Close()
- member x.CheckClose = true
- member x.LastGenerated = e.Current }
- redirect <- true
- x.MoveNextImpl()
- | _ (* 0 *) ->
- false
-
- interface IEnumerable<'T> with
- member x.GetEnumerator() = x.GetFreshEnumerator()
- interface IEnumerable with
- member x.GetEnumerator() = (x.GetFreshEnumerator() :> IEnumerator)
- interface IEnumerator<'T> with
- member x.Current = if redirect then redirectTo.LastGenerated else x.LastGenerated
- member x.Dispose() = if redirect then redirectTo.Close() else x.Close()
- interface IEnumerator with
- member x.Current = box (if redirect then redirectTo.LastGenerated else x.LastGenerated)
-
- //[]
- member x.MoveNext() = x.MoveNextImpl()
-
- member x.Reset() = raise <| new System.NotSupportedException()
-
namespace Microsoft.FSharp.Collections
@@ -849,7 +462,8 @@ namespace Microsoft.FSharp.Collections
#else
#endif
- open Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers
+ open Microsoft.FSharp.Collections.Internal
+ open Microsoft.FSharp.Collections.IEnumerator
let mkDelayedSeq (f: unit -> IEnumerable<'T>) = mkSeq (fun () -> f().GetEnumerator())
let mkUnfoldSeq f x = mkSeq (fun () -> IEnumerator.unfold f x)
@@ -1089,7 +703,7 @@ namespace Microsoft.FSharp.Collections
[]
let concat sources =
checkNonNull "sources" sources
- mkConcatSeq sources
+ RuntimeHelpers.mkConcatSeq sources
[]
let length (source : seq<'T>) =
@@ -1454,7 +1068,7 @@ namespace Microsoft.FSharp.Collections
let groupByValueType (keyf:'T->'Key) (seq:seq<'T>) = seq |> groupByImpl HashIdentity.Structural<'Key> keyf id
// Wrap a StructBox around all keys in case the key type is itself a type using null as a representation
- let groupByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> groupByImpl StructBox<'Key>.Comparer (fun t -> StructBox (keyf t)) (fun sb -> sb.Value)
+ let groupByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> groupByImpl RuntimeHelpers.StructBox<'Key>.Comparer (fun t -> RuntimeHelpers.StructBox (keyf t)) (fun sb -> sb.Value)
[]
let groupBy (keyf:'T->'Key) (seq:seq<'T>) =
@@ -1537,7 +1151,7 @@ namespace Microsoft.FSharp.Collections
let countByValueType (keyf:'T->'Key) (seq:seq<'T>) = seq |> countByImpl HashIdentity.Structural<'Key> keyf id
// Wrap a StructBox around all keys in case the key type is itself a type using null as a representation
- let countByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> countByImpl StructBox<'Key>.Comparer (fun t -> StructBox (keyf t)) (fun sb -> sb.Value)
+ let countByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> countByImpl RuntimeHelpers.StructBox<'Key>.Comparer (fun t -> RuntimeHelpers.StructBox (keyf t)) (fun sb -> sb.Value)
[]
let countBy (keyf:'T->'Key) (source:seq<'T>) =
diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi
index f05e9db76dd..7e081935b57 100644
--- a/src/fsharp/FSharp.Core/seq.fsi
+++ b/src/fsharp/FSharp.Core/seq.fsi
@@ -1342,97 +1342,3 @@ namespace Microsoft.FSharp.Collections
/// Thrown when any of the input sequences is null.
[]
val zip3: source1:seq<'T1> -> source2:seq<'T2> -> source3:seq<'T3> -> seq<'T1 * 'T2 * 'T3>
-
-namespace Microsoft.FSharp.Core.CompilerServices
-
- open System
- open System.Collections
- open System.Collections.Generic
- open Microsoft.FSharp.Core
- open Microsoft.FSharp.Collections
-
-
- []
- /// A group of functions used as part of the compiled representation of F# sequence expressions.
- module RuntimeHelpers =
-
- []
- type internal StructBox<'T when 'T : equality> =
- new : value:'T -> StructBox<'T>
- member Value : 'T
- static member Comparer : IEqualityComparer>
-
- /// The F# compiler emits calls to this function to
- /// implement the while operator for F# sequence expressions.
- ///
- /// A function that indicates whether iteration should continue.
- /// The input sequence.
- ///
- /// The result sequence.
- val EnumerateWhile : guard:(unit -> bool) -> source:seq<'T> -> seq<'T>
-
- /// The F# compiler emits calls to this function to
- /// implement the try/finally operator for F# sequence expressions.
- ///
- /// The input sequence.
- /// A computation to be included in an enumerator's Dispose method.
- ///
- /// The result sequence.
- val EnumerateThenFinally : source:seq<'T> -> compensation:(unit -> unit) -> seq<'T>
-
- /// The F# compiler emits calls to this function to implement the compiler-intrinsic
- /// conversions from untyped System.Collections.IEnumerable sequences to typed sequences.
- ///
- /// An initializer function.
- /// A function to iterate and test if end of sequence is reached.
- /// A function to retrieve the current element.
- ///
- /// The resulting typed sequence.
- val EnumerateFromFunctions: create:(unit -> 'T) -> moveNext:('T -> bool) -> current:('T -> 'U) -> seq<'U>
-
- /// The F# compiler emits calls to this function to implement the use operator for F# sequence
- /// expressions.
- ///
- /// The resource to be used and disposed.
- /// The input sequence.
- ///
- /// The result sequence.
- val EnumerateUsing : resource:'T -> source:('T -> 'Collection) -> seq<'U> when 'T :> IDisposable and 'Collection :> seq<'U>
-
- /// Creates an anonymous event with the given handlers.
- ///
- /// A function to handle adding a delegate for the event to trigger.
- /// A function to handle removing a delegate that the event triggers.
- /// A function to produce the delegate type the event can trigger.
- ///
- /// The initialized event.
- val CreateEvent : addHandler : ('Delegate -> unit) -> removeHandler : ('Delegate -> unit) -> createHandler : ((obj -> 'Args -> unit) -> 'Delegate) -> Microsoft.FSharp.Control.IEvent<'Delegate,'Args>
-
- []
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- type GeneratedSequenceBase<'T> =
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- ///
- /// A new sequence generator for the expression.
- new : unit -> GeneratedSequenceBase<'T>
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- ///
- /// A new enumerator for the sequence.
- abstract GetFreshEnumerator : unit -> IEnumerator<'T>
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- ///
- /// A reference to the sequence.
- ///
- /// A 0, 1, and 2 respectively indicate Stop, Yield, and Goto conditions for the sequence generator.
- abstract GenerateNext : result:byref> -> int
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- abstract Close: unit -> unit
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- abstract CheckClose: bool
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- abstract LastGenerated : 'T
- interface IEnumerable<'T>
- interface IEnumerable
- interface IEnumerator<'T>
- interface IEnumerator
-
diff --git a/src/fsharp/FSharp.Core/seqcore.fs b/src/fsharp/FSharp.Core/seqcore.fs
new file mode 100644
index 00000000000..e733d7f9a2d
--- /dev/null
+++ b/src/fsharp/FSharp.Core/seqcore.fs
@@ -0,0 +1,405 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.FSharp.Collections
+ #nowarn "52" // The value has been copied to ensure the original is not mutated by this operation
+
+ open System
+ open System.Diagnostics
+ open System.Collections
+ open System.Collections.Generic
+ open Microsoft.FSharp.Core
+ open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
+ open Microsoft.FSharp.Core.Operators
+ open Microsoft.FSharp.Control
+ open Microsoft.FSharp.Collections
+
+ 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 dispose (r : System.IDisposable) = r.Dispose()
+
+ let cast (e : IEnumerator) : IEnumerator<'T> =
+ { new IEnumerator<'T> with
+ member x.Current = unbox<'T> e.Current
+ interface IEnumerator with
+ member x.Current = unbox<'T> e.Current :> obj
+ member x.MoveNext() = e.MoveNext()
+ member x.Reset() = noReset()
+ interface System.IDisposable with
+ member x.Dispose() =
+ match e with
+ | :? 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>)
+
+ []
+ type EmptyEnumerable<'T> =
+ | EmptyEnumerable
+ interface IEnumerable<'T> with
+ member x.GetEnumerator() = Empty<'T>()
+ interface IEnumerable with
+ member x.GetEnumerator() = (Empty<'T>() :> IEnumerator)
+
+ let readAndClear r =
+ lock r (fun () -> match !r with None -> None | Some _ as res -> r := None; res)
+
+ let generateWhileSome openf compute closef : IEnumerator<'U> =
+ let started = ref false
+ let curr = ref None
+ let state = ref (Some(openf()))
+ let getCurr() =
+ check !started
+ match !curr with None -> alreadyFinished() | Some x -> x
+ let start() = if not !started then (started := true)
+
+ let dispose() = readAndClear state |> Option.iter closef
+ let finish() = (try dispose() finally curr := None)
+ { new IEnumerator<'U> with
+ member x.Current = getCurr()
+ interface IEnumerator with
+ member x.Current = box (getCurr())
+ member x.MoveNext() =
+ start()
+ match !state with
+ | None -> false (* we started, then reached the end, then got another MoveNext *)
+ | Some s ->
+ match (try compute s with e -> finish(); reraise()) with
+ | None -> finish(); false
+ | Some _ as x -> curr := x; true
+
+ member x.Reset() = noReset()
+ interface System.IDisposable with
+ member x.Dispose() = dispose() }
+
+ []
+ 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
+ interface IEnumerator with
+ member x.Current = (e :> IEnumerator).Current
+ member x.MoveNext() = e.MoveNext()
+ member x.Reset() = noReset()
+ interface System.IDisposable with
+ member x.Dispose() =
+ try
+ e.Dispose()
+ finally
+ f()
+ }
+
+ let inline checkNonNull argName arg =
+ match box arg with
+ | null -> nullArg argName
+ | _ -> ()
+
+ let mkSeq f =
+ { new IEnumerable<'U> with
+ member x.GetEnumerator() = f()
+ interface IEnumerable with
+ member x.GetEnumerator() = (f() :> IEnumerator) }
+
+namespace Microsoft.FSharp.Core.CompilerServices
+
+ open System
+ open System.Diagnostics
+ open Microsoft.FSharp.Core
+ open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
+ open Microsoft.FSharp.Core.Operators
+ open Microsoft.FSharp.Control
+ open Microsoft.FSharp.Collections
+ open Microsoft.FSharp.Collections.IEnumerator
+ open Microsoft.FSharp.Primitives.Basics
+ open System.Collections
+ open System.Collections.Generic
+
+ module RuntimeHelpers =
+
+ []
+ type internal StructBox<'T when 'T:equality>(value:'T) =
+ member x.Value = value
+ static member Comparer =
+ let gcomparer = HashIdentity.Structural<'T>
+ { new IEqualityComparer> with
+ member __.GetHashCode(v) = gcomparer.GetHashCode(v.Value)
+ member __.Equals(v1,v2) = gcomparer.Equals(v1.Value,v2.Value) }
+
+ let Generate openf compute closef =
+ mkSeq (fun () -> IEnumerator.generateWhileSome openf compute closef)
+
+ let GenerateUsing (openf : unit -> ('U :> System.IDisposable)) compute =
+ Generate openf compute (fun (s:'U) -> s.Dispose())
+
+ let EnumerateFromFunctions opener moveNext current =
+ Generate
+ opener
+ (fun x -> if moveNext x then Some(current x) else None)
+ (fun x -> match box(x) with :? System.IDisposable as id -> id.Dispose() | _ -> ())
+
+ // A family of enumerators that can have additional 'finally' actions added to the enumerator through
+ // the use of mutation. This is used to 'push' the disposal action for a 'use' into the next enumerator.
+ // For example,
+ // seq { use x = ...
+ // while ... }
+ // results in the 'while' loop giving an adjustable enumerator. This is then adjusted by adding the disposal action
+ // from the 'use' into the enumerator. This means that we avoid constructing a two-deep enumerator chain in this
+ // common case.
+ type IFinallyEnumerator =
+ abstract AppendFinallyAction : (unit -> unit) -> unit
+
+ /// A concrete implementation of IEnumerable that adds the given compensation to the "Dispose" chain of any
+ /// enumerators returned by the enumerable.
+ []
+ type FinallyEnumerable<'T>(compensation: unit -> unit, restf: unit -> seq<'T>) =
+ interface IEnumerable<'T> with
+ member x.GetEnumerator() =
+ try
+ let ie = restf().GetEnumerator()
+ match ie with
+ | :? IFinallyEnumerator as a ->
+ a.AppendFinallyAction(compensation)
+ ie
+ | _ ->
+ IEnumerator.EnumerateThenFinally compensation ie
+ with e ->
+ compensation()
+ reraise()
+ interface IEnumerable with
+ member x.GetEnumerator() = ((x :> IEnumerable<'T>).GetEnumerator() :> IEnumerator)
+
+ /// An optimized object for concatenating a sequence of enumerables
+ []
+ type ConcatEnumerator<'T,'U when 'U :> seq<'T>>(sources: seq<'U>) =
+ let mutable outerEnum = sources.GetEnumerator()
+ let mutable currInnerEnum = IEnumerator.Empty()
+
+ let mutable started = false
+ let mutable finished = false
+ let mutable compensations = []
+
+ [] // false = unchecked
+ val mutable private currElement : 'T
+
+ member x.Finish() =
+ finished <- true
+ try
+ match currInnerEnum with
+ | null -> ()
+ | _ ->
+ try
+ currInnerEnum.Dispose()
+ finally
+ currInnerEnum <- null
+ finally
+ try
+ match outerEnum with
+ | null -> ()
+ | _ ->
+ try
+ outerEnum.Dispose()
+ finally
+ outerEnum <- null
+ finally
+ let rec iter comps =
+ match comps with
+ | [] -> ()
+ | h::t ->
+ try h() finally iter t
+ try
+ compensations |> List.rev |> iter
+ finally
+ compensations <- []
+
+ member x.GetCurrent() =
+ IEnumerator.check started
+ if finished then IEnumerator.alreadyFinished() else x.currElement
+
+ interface IFinallyEnumerator with
+ member x.AppendFinallyAction(f) =
+ compensations <- f :: compensations
+
+ interface IEnumerator<'T> with
+ member x.Current = x.GetCurrent()
+
+ interface IEnumerator with
+ member x.Current = box (x.GetCurrent())
+
+ member x.MoveNext() =
+ if not started then (started <- true)
+ if finished then false
+ else
+ let rec takeInner () =
+ // check the inner list
+ if currInnerEnum.MoveNext() then
+ x.currElement <- currInnerEnum.Current
+ true
+ else
+ // check the outer list
+ let rec takeOuter() =
+ if outerEnum.MoveNext() then
+ let ie = outerEnum.Current
+ // Optimization to detect the statically-allocated empty IEnumerables
+ match box ie with
+ | :? EmptyEnumerable<'T> ->
+ // This one is empty, just skip, don't call GetEnumerator, try again
+ takeOuter()
+ | _ ->
+ // OK, this one may not be empty.
+ // Don't forget to dispose of the enumerator for the inner list now we're done with it
+ currInnerEnum.Dispose()
+ currInnerEnum <- ie.GetEnumerator()
+ takeInner ()
+ else
+ // We're done
+ x.Finish()
+ false
+ takeOuter()
+ takeInner ()
+
+ member x.Reset() = IEnumerator.noReset()
+
+ interface System.IDisposable with
+ member x.Dispose() =
+ if not finished then
+ x.Finish()
+
+ let EnumerateUsing (resource : 'T :> System.IDisposable) (rest: 'T -> #seq<'U>) =
+ (FinallyEnumerable((fun () -> match box resource with null -> () | _ -> resource.Dispose()),
+ (fun () -> rest resource :> seq<_>)) :> seq<_>)
+
+ let mkConcatSeq (sources: seq<'U :> seq<'T>>) =
+ mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>)
+
+ let EnumerateWhile (g : unit -> bool) (b: seq<'T>) : seq<'T> =
+ let started = ref false
+ let curr = ref None
+ let getCurr() =
+ IEnumerator.check !started
+ match !curr with None -> IEnumerator.alreadyFinished() | Some x -> x
+ let start() = if not !started then (started := true)
+
+ let finish() = (curr := None)
+ mkConcatSeq
+ (mkSeq (fun () ->
+ { new IEnumerator<_> with
+ member x.Current = getCurr()
+ interface IEnumerator with
+ member x.Current = box (getCurr())
+ member x.MoveNext() =
+ start()
+ let keepGoing = (try g() with e -> finish (); reraise ()) in
+ if keepGoing then
+ curr := Some(b); true
+ else
+ finish(); false
+ member x.Reset() = IEnumerator.noReset()
+ interface System.IDisposable with
+ member x.Dispose() = () }))
+
+ let EnumerateThenFinally (rest : seq<'T>) (compensation : unit -> unit) =
+ (FinallyEnumerable(compensation, (fun () -> rest)) :> seq<_>)
+
+ let CreateEvent (add : 'Delegate -> unit) (remove : 'Delegate -> unit) (create : (obj -> 'Args -> unit) -> 'Delegate ) :IEvent<'Delegate,'Args> =
+ // Note, we implement each interface explicitly: this works around a bug in the CLR
+ // implementation on CompactFramework 3.7, used on Windows Phone 7
+ { new obj() with
+ member x.ToString() = ""
+ interface IEvent<'Delegate,'Args>
+ interface IDelegateEvent<'Delegate> with
+ member x.AddHandler(h) = add h
+ member x.RemoveHandler(h) = remove h
+ interface System.IObservable<'Args> with
+ member x.Subscribe(r:IObserver<'Args>) =
+ let h = create (fun _ args -> r.OnNext(args))
+ add h
+ { new System.IDisposable with
+ member x.Dispose() = remove h } }
+
+
+ []
+ type GeneratedSequenceBase<'T>() =
+ let mutable redirectTo : GeneratedSequenceBase<'T> = Unchecked.defaultof<_>
+ let mutable redirect : bool = false
+
+ abstract GetFreshEnumerator : unit -> IEnumerator<'T>
+ abstract GenerateNext : next:byref> -> int // 0 = Stop, 1 = Yield, 2 = Goto
+ abstract Close: unit -> unit
+ abstract CheckClose: bool
+ abstract LastGenerated : 'T
+
+ //[]
+ member x.MoveNextImpl() =
+ let active =
+ if redirect then redirectTo
+ else x
+ let mutable target = null
+ match active.GenerateNext(&target) with
+ | 1 ->
+ true
+ | 2 ->
+ match target.GetEnumerator() with
+ | :? GeneratedSequenceBase<'T> as g when not active.CheckClose ->
+ redirectTo <- g
+ | e ->
+ redirectTo <-
+ { new GeneratedSequenceBase<'T>() with
+ member x.GetFreshEnumerator() = e
+ member x.GenerateNext(_) = if e.MoveNext() then 1 else 0
+ member x.Close() = try e.Dispose() finally active.Close()
+ member x.CheckClose = true
+ member x.LastGenerated = e.Current }
+ redirect <- true
+ x.MoveNextImpl()
+ | _ (* 0 *) ->
+ false
+
+ interface IEnumerable<'T> with
+ member x.GetEnumerator() = x.GetFreshEnumerator()
+ interface IEnumerable with
+ member x.GetEnumerator() = (x.GetFreshEnumerator() :> IEnumerator)
+ interface IEnumerator<'T> with
+ member x.Current = if redirect then redirectTo.LastGenerated else x.LastGenerated
+ member x.Dispose() = if redirect then redirectTo.Close() else x.Close()
+ interface IEnumerator with
+ member x.Current = box (if redirect then redirectTo.LastGenerated else x.LastGenerated)
+
+ //[]
+ member x.MoveNext() = x.MoveNextImpl()
+
+ member x.Reset() = raise <| new System.NotSupportedException()
diff --git a/src/fsharp/FSharp.Core/seqcore.fsi b/src/fsharp/FSharp.Core/seqcore.fsi
new file mode 100644
index 00000000000..ebd7accb8e5
--- /dev/null
+++ b/src/fsharp/FSharp.Core/seqcore.fsi
@@ -0,0 +1,150 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.FSharp.Collections
+ open System
+ open System.Collections
+ open System.Collections.Generic
+ open Microsoft.FSharp.Core
+ open Microsoft.FSharp.Collections
+ module internal IEnumerator =
+ val noReset : unit -> 'a
+ val notStarted : unit -> 'a
+ val alreadyFinished : unit -> 'a
+ val check : started:bool -> unit
+ val dispose : r:System.IDisposable -> unit
+ val cast :
+ e:System.Collections.IEnumerator ->
+ System.Collections.Generic.IEnumerator<'T>
+ []
+ type EmptyEnumerator<'T> =
+ class
+ interface System.IDisposable
+ interface System.Collections.IEnumerator
+ interface System.Collections.Generic.IEnumerator<'T>
+ new : unit -> EmptyEnumerator<'T>
+ end
+ val Empty : unit -> System.Collections.Generic.IEnumerator<'T>
+ []
+ type EmptyEnumerable<'T> =
+ | EmptyEnumerable
+ with
+ interface System.Collections.IEnumerable
+ interface System.Collections.Generic.IEnumerable<'T>
+ end
+
+ val readAndClear : r:'a option ref -> 'a option
+ val generateWhileSome :
+ openf:(unit -> 'a) ->
+ compute:('a -> 'U option) ->
+ closef:('a -> unit) -> System.Collections.Generic.IEnumerator<'U>
+ []
+ type Singleton<'T> =
+ class
+ interface System.IDisposable
+ interface System.Collections.IEnumerator
+ interface System.Collections.Generic.IEnumerator<'T>
+ new : v:'T -> Singleton<'T>
+ end
+ val Singleton : x:'T -> System.Collections.Generic.IEnumerator<'T>
+ val EnumerateThenFinally :
+ f:(unit -> unit) ->
+ e:System.Collections.Generic.IEnumerator<'T> ->
+ System.Collections.Generic.IEnumerator<'T>
+ val inline checkNonNull : argName:string -> arg:'a -> unit
+ val mkSeq :
+ f:(unit -> System.Collections.Generic.IEnumerator<'U>) ->
+ System.Collections.Generic.IEnumerable<'U>
+
+namespace Microsoft.FSharp.Core.CompilerServices
+
+ open System
+ open System.Collections
+ open System.Collections.Generic
+ open Microsoft.FSharp.Core
+ open Microsoft.FSharp.Collections
+
+ []
+ /// A group of functions used as part of the compiled representation of F# sequence expressions.
+ module RuntimeHelpers =
+
+ []
+ type internal StructBox<'T when 'T : equality> =
+ new : value:'T -> StructBox<'T>
+ member Value : 'T
+ static member Comparer : IEqualityComparer>
+
+ val internal mkConcatSeq : sources:(seq<#seq<'T>>) -> seq<'T>
+
+ /// The F# compiler emits calls to this function to
+ /// implement the while operator for F# sequence expressions.
+ ///
+ /// A function that indicates whether iteration should continue.
+ /// The input sequence.
+ ///
+ /// The result sequence.
+ val EnumerateWhile : guard:(unit -> bool) -> source:seq<'T> -> seq<'T>
+
+ /// The F# compiler emits calls to this function to
+ /// implement the try/finally operator for F# sequence expressions.
+ ///
+ /// The input sequence.
+ /// A computation to be included in an enumerator's Dispose method.
+ ///
+ /// The result sequence.
+ val EnumerateThenFinally : source:seq<'T> -> compensation:(unit -> unit) -> seq<'T>
+
+ /// The F# compiler emits calls to this function to implement the compiler-intrinsic
+ /// conversions from untyped System.Collections.IEnumerable sequences to typed sequences.
+ ///
+ /// An initializer function.
+ /// A function to iterate and test if end of sequence is reached.
+ /// A function to retrieve the current element.
+ ///
+ /// The resulting typed sequence.
+ val EnumerateFromFunctions: create:(unit -> 'T) -> moveNext:('T -> bool) -> current:('T -> 'U) -> seq<'U>
+
+ /// The F# compiler emits calls to this function to implement the use operator for F# sequence
+ /// expressions.
+ ///
+ /// The resource to be used and disposed.
+ /// The input sequence.
+ ///
+ /// The result sequence.
+ val EnumerateUsing : resource:'T -> source:('T -> 'Collection) -> seq<'U> when 'T :> IDisposable and 'Collection :> seq<'U>
+
+ /// Creates an anonymous event with the given handlers.
+ ///
+ /// A function to handle adding a delegate for the event to trigger.
+ /// A function to handle removing a delegate that the event triggers.
+ /// A function to produce the delegate type the event can trigger.
+ ///
+ /// The initialized event.
+ val CreateEvent : addHandler : ('Delegate -> unit) -> removeHandler : ('Delegate -> unit) -> createHandler : ((obj -> 'Args -> unit) -> 'Delegate) -> Microsoft.FSharp.Control.IEvent<'Delegate,'Args>
+
+ []
+ /// The F# compiler emits implementations of this type for compiled sequence expressions.
+ type GeneratedSequenceBase<'T> =
+ /// The F# compiler emits implementations of this type for compiled sequence expressions.
+ ///
+ /// A new sequence generator for the expression.
+ new : unit -> GeneratedSequenceBase<'T>
+ /// The F# compiler emits implementations of this type for compiled sequence expressions.
+ ///
+ /// A new enumerator for the sequence.
+ abstract GetFreshEnumerator : unit -> IEnumerator<'T>
+ /// The F# compiler emits implementations of this type for compiled sequence expressions.
+ ///
+ /// A reference to the sequence.
+ ///
+ /// A 0, 1, and 2 respectively indicate Stop, Yield, and Goto conditions for the sequence generator.
+ abstract GenerateNext : result:byref> -> int
+ /// The F# compiler emits implementations of this type for compiled sequence expressions.
+ abstract Close: unit -> unit
+ /// The F# compiler emits implementations of this type for compiled sequence expressions.
+ abstract CheckClose: bool
+ /// The F# compiler emits implementations of this type for compiled sequence expressions.
+ abstract LastGenerated : 'T
+ interface IEnumerable<'T>
+ interface IEnumerable
+ interface IEnumerator<'T>
+ interface IEnumerator