提交 f6cea7c3 编写于 作者: L latkin

Merge branch 'master' into fsharp4

Conflicts:
	src/fsharp/FSharp.Core/array.fs
	src/fsharp/FSharp.Core/seq.fs
......@@ -9,6 +9,14 @@ open System
open FSharp.Core.Unittests.LibraryTestFx
open NUnit.Framework
module LeakUtils =
// when testing for liveness, the things that we want to observe must always be created in
// a nested function call to avoid the GC (possibly) treating them as roots past the last use in the block.
// We also need something non trivial to disuade the compiler from inlining in Release builds.
type ToRun<'a>(f : unit -> 'a) =
member this.Invoke() = f()
let run (toRun : ToRun<'a>) = toRun.Invoke()
// ---------------------------------------------------
......@@ -191,6 +199,41 @@ type AsyncModule() =
for _i = 1 to 50 do test()
[<Test>]
member this.``Async.AwaitWaitHandle does not leak memory`` () =
// This test checks that AwaitWaitHandle does not leak continuations (described in #131),
// We only test the worst case - when the AwaitWaitHandle is already set.
use manualResetEvent = new System.Threading.ManualResetEvent(true)
let tryToLeak() =
let resource =
LeakUtils.ToRun (fun () ->
let resource = obj()
let work =
async {
let! _ = Async.AwaitWaitHandle manualResetEvent
GC.KeepAlive(resource)
return ()
}
work |> Async.RunSynchronously |> ignore
WeakReference(resource))
|> LeakUtils.run
Assert.IsTrue(resource.IsAlive)
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
Assert.IsFalse(resource.IsAlive)
// The leak hangs on a race condition which is really hard to trigger in F# 3.0, hence the 100000 runs...
for _ in 1..100 do tryToLeak()
[<Test>]
member this.``AwaitWaitHandle.DisposedWaitHandle2``() =
let wh = new System.Threading.ManualResetEvent(false)
......
......@@ -12,7 +12,6 @@ namespace Microsoft.FSharp.Collections
open Microsoft.FSharp.Core.Operators
open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
open Microsoft.FSharp.Core.SR
open Microsoft.FSharp.Core.LanguagePrimitives.ErrorStrings
#if FX_NO_ICLONEABLE
open Microsoft.FSharp.Core.ICloneableExtensions
#else
......@@ -36,7 +35,7 @@ namespace Microsoft.FSharp.Collections
[<CompiledName("Last")>]
let inline last (array : 'T[]) =
checkNonNull "array" array
if array.Length = 0 then invalidArg "array" InputArrayEmptyString
if array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
array.[array.Length-1]
[<CompiledName("TryLast")>]
......@@ -205,7 +204,7 @@ namespace Microsoft.FSharp.Collections
[<CompiledName("Head")>]
let head (array : 'T[]) =
checkNonNull "array" array
if array.Length = 0 then invalidArg "array" InputArrayEmptyString else array.[0]
if array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString else array.[0]
[<CompiledName("Copy")>]
let copy (array: 'T[]) =
......@@ -719,18 +718,20 @@ namespace Microsoft.FSharp.Collections
let reduce f (array : _[]) =
checkNonNull "array" array
let len = array.Length
if len = 0 then invalidArg "array" InputArrayEmptyString else
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
let mutable res = array.[0]
for i = 1 to len - 1 do
res <- f.Invoke(res,array.[i])
res
if len = 0 then
invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
else
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
let mutable res = array.[0]
for i = 1 to len - 1 do
res <- f.Invoke(res,array.[i])
res
[<CompiledName("ReduceBack")>]
let reduceBack f (array : _[]) =
checkNonNull "array" array
let len = array.Length
if len = 0 then invalidArg "array" InputArrayEmptyString
if len = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
else foldSubRight f array 0 (len - 2) array.[len - 1]
[<CompiledName("SortInPlaceWith")>]
......@@ -843,7 +844,7 @@ namespace Microsoft.FSharp.Collections
[<CompiledName("Min")>]
let inline min (array:_[]) =
checkNonNull "array" array
if array.Length = 0 then invalidArg "array" InputArrayEmptyString
if array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
let mutable acc = array.[0]
for i = 1 to array.Length - 1 do
let curr = array.[i]
......@@ -854,7 +855,7 @@ namespace Microsoft.FSharp.Collections
[<CompiledName("MinBy")>]
let inline minBy f (array:_[]) =
checkNonNull "array" array
if array.Length = 0 then invalidArg "array" InputArrayEmptyString
if array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
let mutable accv = array.[0]
let mutable acc = f accv
for i = 1 to array.Length - 1 do
......@@ -868,7 +869,7 @@ namespace Microsoft.FSharp.Collections
[<CompiledName("Max")>]
let inline max (array:_[]) =
checkNonNull "array" array
if array.Length = 0 then invalidArg "array" InputArrayEmptyString
if array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
let mutable acc = array.[0]
for i = 1 to array.Length - 1 do
let curr = array.[i]
......@@ -879,7 +880,7 @@ namespace Microsoft.FSharp.Collections
[<CompiledName("MaxBy")>]
let inline maxBy f (array:_[]) =
checkNonNull "array" array
if array.Length = 0 then invalidArg "array" InputArrayEmptyString
if array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
let mutable accv = array.[0]
let mutable acc = f accv
for i = 1 to array.Length - 1 do
......
......@@ -1671,29 +1671,34 @@ namespace Microsoft.FSharp.Control
Action<obj>(fun _ ->
if latch.Enter() then
// if we got here - then we need to unregister RegisteredWaitHandle + trigger cancellation
// entrance to TP callback is protected by latch - so savedCont will never be called
match !rwh with
| None -> ()
| Some rwh -> rwh.Unregister(null) |> ignore
// entrance to TP callback is protected by latch - so savedCont will never be called
lock rwh (fun () ->
match !rwh with
| None -> ()
| Some rwh -> rwh.Unregister(null) |> ignore)
Async.Start (async { do (aux.ccont (OperationCanceledException()) |> unfake) }))
and registration : CancellationTokenRegistration= aux.token.Register(cancelHandler, null)
and registration : CancellationTokenRegistration = aux.token.Register(cancelHandler, null)
let savedCont = args.cont
try
rwh := Some(ThreadPool.RegisterWaitForSingleObject
(waitObject=waitHandle,
callBack=WaitOrTimerCallback(fun _ timeOut ->
if latch.Enter() then
rwh := None
registration.Dispose()
aux.trampolineHolder.Protect (fun () -> savedCont (not timeOut)) |> unfake),
state=null,
millisecondsTimeOutInterval=millisecondsTimeout,
executeOnlyOnce=true));
FakeUnit
lock rwh (fun () ->
rwh := Some(ThreadPool.RegisterWaitForSingleObject
(waitObject=waitHandle,
callBack=WaitOrTimerCallback(fun _ timeOut ->
if latch.Enter() then
lock rwh (fun () -> rwh.Value.Value.Unregister(null) |> ignore)
rwh := None
registration.Dispose()
aux.trampolineHolder.Protect (fun () -> savedCont (not timeOut)) |> unfake),
state=null,
millisecondsTimeOutInterval=millisecondsTimeout,
executeOnlyOnce=true));
FakeUnit)
with _ ->
if latch.Enter() then reraise() // reraise exception only if we successfully enter the latch (no other continuations were called)
if latch.Enter() then
registration.Dispose()
reraise() // reraise exception only if we successfully enter the latch (no other continuations were called)
else FakeUnit
)
#endif
......
......@@ -4,7 +4,6 @@ namespace Microsoft.FSharp.Primitives.Basics
open Microsoft.FSharp.Core
open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
open Microsoft.FSharp.Core.LanguagePrimitives.ErrorStrings
open Microsoft.FSharp.Collections
open Microsoft.FSharp.Core.Operators
open System.Diagnostics.CodeAnalysis
......@@ -327,7 +326,7 @@ module internal List =
let init count f =
if count < 0 then invalidArg "count" InputMustBeNonNegativeString
if count < 0 then invalidArg "count" LanguagePrimitives.ErrorStrings.InputMustBeNonNegativeString
if count = 0 then []
else
let res = freshConsNoTail (f 0)
......@@ -344,7 +343,7 @@ module internal List =
takeFreshConsTail cons2 (n - 1) xs
let take n l =
if n < 0 then invalidArg "count" InputMustBeNonNegativeString
if n < 0 then invalidArg "count" LanguagePrimitives.ErrorStrings.InputMustBeNonNegativeString
if n = 0 then [] else
match l with
| [] -> raise <| System.InvalidOperationException (SR.GetString(SR.notEnoughElements))
......@@ -714,7 +713,7 @@ module internal Array =
(# "newarr !0" type ('T) count : 'T array #)
let inline init (count:int) (f: int -> 'T) =
if count < 0 then invalidArg "count" InputMustBeNonNegativeString
if count < 0 then invalidArg "count" LanguagePrimitives.ErrorStrings.InputMustBeNonNegativeString
let arr = (zeroCreateUnchecked count : 'T array)
for i = 0 to count - 1 do
arr.[i] <- f i
......@@ -883,4 +882,4 @@ module internal Array =
res.[i] <- array.[startIndex+i]
else
Array.Copy(array, startIndex, res, 0, count)
res
\ No newline at end of file
res
......@@ -656,17 +656,17 @@ namespace Microsoft.FSharp.Core
module LanguagePrimitives =
module (* internal *) ErrorStrings =
[<Sealed>]
type (* internal *) ErrorStrings =
// inline functions cannot call GetString, so we must make these bits public
let AddressOpNotFirstClassString = SR.GetString(SR.addressOpNotFirstClass)
let NoNegateMinValueString = SR.GetString(SR.noNegateMinValue)
static member AddressOpNotFirstClassString with get () = SR.GetString(SR.addressOpNotFirstClass)
static member NoNegateMinValueString with get () = SR.GetString(SR.noNegateMinValue)
// needs to be public to be visible from inline function 'average' and others
let InputSequenceEmptyString = SR.GetString(SR.inputSequenceEmpty)
static member InputSequenceEmptyString with get () = SR.GetString(SR.inputSequenceEmpty)
// needs to be public to be visible from inline function 'average' and others
let InputArrayEmptyString = SR.GetString(SR.arrayWasEmpty)
static member InputArrayEmptyString with get () = SR.GetString(SR.arrayWasEmpty)
// needs to be public to be visible from inline function 'average' and others
let InputMustBeNonNegativeString = SR.GetString(SR.inputMustBeNonNegative)
static member InputMustBeNonNegativeString with get () = SR.GetString(SR.inputMustBeNonNegative)
[<CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")>] // nested module OK
module IntrinsicOperators =
......
......@@ -1015,22 +1015,23 @@ namespace Microsoft.FSharp.Core
val inline DivideByInt< ^T > : x:^T -> y:int -> ^T when ^T : (static member DivideByInt : ^T * int -> ^T)
/// <summary>For internal use only</summary>
module (* internal *) ErrorStrings =
[<Sealed>]
type (* internal *) ErrorStrings =
[<CompilerMessage("This value is for use by compiled F# code and should not be used directly", 1204, IsHidden=true)>]
val InputSequenceEmptyString : string
static member InputSequenceEmptyString : string with get
[<CompilerMessage("This value is for use by compiled F# code and should not be used directly", 1204, IsHidden=true)>]
val InputArrayEmptyString : string
static member InputArrayEmptyString : string with get
[<CompilerMessage("This value is for use by compiled F# code and should not be used directly", 1204, IsHidden=true)>]
val AddressOpNotFirstClassString : string
static member AddressOpNotFirstClassString : string with get
[<CompilerMessage("This value is for use by compiled F# code and should not be used directly", 1204, IsHidden=true)>]
val NoNegateMinValueString : string
static member NoNegateMinValueString : string with get
[<CompilerMessage("This value is for use by compiled F# code and should not be used directly", 1204, IsHidden=true)>]
val InputMustBeNonNegativeString : string
static member InputMustBeNonNegativeString : string with get
//-------------------------------------------------------------------------
......
......@@ -849,7 +849,6 @@ namespace Microsoft.FSharp.Collections
open System.Collections.Generic
open Microsoft.FSharp.Core
open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
open Microsoft.FSharp.Core.LanguagePrimitives.ErrorStrings
open Microsoft.FSharp.Core.Operators
open Microsoft.FSharp.Core.CompilerServices
open Microsoft.FSharp.Control
......@@ -1161,7 +1160,7 @@ namespace Microsoft.FSharp.Collections
let reduce f (source : seq<'T>) =
checkNonNull "source" source
use e = source.GetEnumerator()
if not (e.MoveNext()) then invalidArg "source" InputSequenceEmptyString;
if not (e.MoveNext()) then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString;
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
let mutable state = e.Current
while e.MoveNext() do
......@@ -1265,7 +1264,7 @@ namespace Microsoft.FSharp.Collections
checkNonNull "source" source
let arr = toArray source
match arr.Length with
| 0 -> invalidArg "source" InputSequenceEmptyString
| 0 -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
| len ->
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
foldArraySubRight f arr 0 (len - 2) arr.[len - 1]
......@@ -1564,7 +1563,7 @@ namespace Microsoft.FSharp.Collections
acc <- Checked.(+) acc e.Current
count <- count + 1
if count = 0 then
invalidArg "source" InputSequenceEmptyString
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
LanguagePrimitives.DivideByInt< (^a) > acc count
[<CompiledName("AverageBy")>]
......@@ -1577,7 +1576,7 @@ namespace Microsoft.FSharp.Collections
acc <- Checked.(+) acc (f e.Current)
count <- count + 1
if count = 0 then
invalidArg "source" InputSequenceEmptyString;
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString;
LanguagePrimitives.DivideByInt< (^U) > acc count
[<CompiledName("Min")>]
......@@ -1585,7 +1584,7 @@ namespace Microsoft.FSharp.Collections
checkNonNull "source" source
use e = source.GetEnumerator()
if not (e.MoveNext()) then
invalidArg "source" InputSequenceEmptyString;
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString;
let mutable acc = e.Current
while e.MoveNext() do
let curr = e.Current
......@@ -1598,7 +1597,7 @@ namespace Microsoft.FSharp.Collections
checkNonNull "source" source
use e = source.GetEnumerator()
if not (e.MoveNext()) then
invalidArg "source" InputSequenceEmptyString;
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString;
let first = e.Current
let mutable acc = f first
let mutable accv = first
......@@ -1632,7 +1631,7 @@ namespace Microsoft.FSharp.Collections
checkNonNull "source" source
use e = source.GetEnumerator()
if not (e.MoveNext()) then
invalidArg "source" InputSequenceEmptyString;
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString;
let mutable acc = e.Current
while e.MoveNext() do
let curr = e.Current
......@@ -1645,7 +1644,7 @@ namespace Microsoft.FSharp.Collections
checkNonNull "source" source
use e = source.GetEnumerator()
if not (e.MoveNext()) then
invalidArg "source" InputSequenceEmptyString;
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString;
let first = e.Current
let mutable acc = f first
let mutable accv = first
......@@ -1735,7 +1734,7 @@ namespace Microsoft.FSharp.Collections
checkNonNull "source" source
use e = source.GetEnumerator()
if (e.MoveNext()) then e.Current
else invalidArg "source" InputSequenceEmptyString
else invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
[<CompiledName("TryHead")>]
let tryHead (source : seq<_>) =
......@@ -1762,7 +1761,7 @@ namespace Microsoft.FSharp.Collections
while (e.MoveNext()) do res <- e.Current
res
else
invalidArg "source" InputSequenceEmptyString
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
[<CompiledName("TryLast")>]
let tryLast (source : seq<_>) =
......@@ -1786,7 +1785,7 @@ namespace Microsoft.FSharp.Collections
else
v
else
invalidArg "source" InputSequenceEmptyString
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
[<CompiledName("Reverse")>]
let rev source =
......
......@@ -508,12 +508,14 @@ module MembersTest =
let s = 2.0f<kg>
let d = 2.0M<kg>
#if !NetCore
let tmpCulture = System.Threading.Thread.CurrentThread.CurrentCulture
System.Threading.Thread.CurrentThread.CurrentCulture <- System.Globalization.CultureInfo("en-US")
test "f" (f.ToString().Equals("2"))
test "s" (s.ToString().Equals("2"))
test "d" (d.ToString().Equals("2.0"))
System.Threading.Thread.CurrentThread.CurrentCulture <- tmpCulture
#endif
let fc = (f :> System.IComparable<float<kg>>).CompareTo(f+f)
let sc = (s :> System.IComparable<float32<kg>>).CompareTo(s+s)
......
......@@ -85,6 +85,7 @@ type internal ServiceProvider(getService:Type->obj) =
member sp.TextManager:IVsTextManager = downcast (getService (typeof<SVsTextManager>))
member sp.Rdt:IVsRunningDocumentTable = downcast (getService (typeof<SVsRunningDocumentTable>))
member sp.XmlService:IVsXMLMemberIndexService = downcast (getService (typeof<SVsXMLMemberIndexService>))
member sp.DTE:EnvDTE.DTE = downcast (getService (typeof<SDTE>))
static member Stub = ServiceProvider(fun _t->raise (Error.UseOfUnitializedServiceProvider))
/// Isolate VsTextManager as much as possible to ease transition into new editor architecture
......
......@@ -6,6 +6,9 @@ open System
open System.Text
open System.Collections.Generic
open Internal.Utilities.Collections
open Microsoft.VisualStudio
open EnvDTE
open EnvDTE80
open Microsoft.VisualStudio.Shell.Interop
open Microsoft.FSharp.Compiler.SourceCodeServices
......@@ -27,9 +30,14 @@ module internal XmlDocumentation =
else xml
/// Provide Xml Documentation
type Provider(xmlIndexService:IVsXMLMemberIndexService) =
type Provider(xmlIndexService:IVsXMLMemberIndexService, dte: DTE) =
/// Index of assembly name to xml member index.
let mutable xmlCache = new AgedLookup<string,IVsXMLMemberIndex>(10,areSame=(fun (x,y) -> x = y))
let events = dte.Events :?> Events2
let solutionEvents = events.SolutionEvents
do solutionEvents.add_AfterClosing(fun () ->
xmlCache.Clear())
let HasTrailingEndOfLine(sb:StringBuilder) =
if sb.Length = 0 then true
......@@ -188,7 +196,7 @@ module internal XmlDocumentation =
with e->
Assert.Exception(e)
reraise()
/// Append an XmlCommnet to the segment.
let AppendXmlComment(documentationProvider:IdealDocumentationProvider, segment:StringBuilder, xml, showExceptions, showParameters, paramName) =
match xml with
......
......@@ -5,12 +5,12 @@ open System
open System.Text
open Microsoft.VisualStudio.Shell.Interop
open Microsoft.FSharp.Compiler.SourceCodeServices
open EnvDTE
module internal XmlDocumentation =
type Provider =
interface IdealDocumentationProvider
new : xmlIndexService:IVsXMLMemberIndexService -> Provider
new : xmlIndexService:IVsXMLMemberIndexService * dte: DTE -> Provider
/// Build a data tip text string with xml comments injected.
val BuildDataTipText : IdealDocumentationProvider * DataTipText -> string
......
......@@ -1593,7 +1593,7 @@ and [<Guid(FSharpConstants.languageServiceGuidString)>]
Source.CreateSource(fls, buffer, fls.GetColorizer(buffer), fileChangeEx)
ls.Initialize
(sp,
(XmlDocumentation.Provider(sp.XmlService) :> IdealDocumentationProvider),
(XmlDocumentation.Provider(sp.XmlService, sp.DTE) :> IdealDocumentationProvider),
(preferences :> LanguagePreferences),
enableStandaloneFileIntellisense,
createSource)
......@@ -2113,4 +2113,4 @@ type FSharpPackage() as self =
override x.Terminate() = ()
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册