diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index cbf79fbdfb3..66369ac7fa1 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -4868,9 +4868,9 @@ module TcDeclarations = //------------------------------------------------------------------------- // Bind module types //------------------------------------------------------------------------- - -let rec TcSignatureElementNonMutRec (cenv: cenv) parent typeNames endm (env: TcEnv) synSigDecl: Cancellable = - cancellable { +#nowarn 3511 +let rec TcSignatureElementNonMutRec (cenv: cenv) parent typeNames endm (env: TcEnv) synSigDecl: Async2 = + async2 { let g = cenv.g try match synSigDecl with @@ -5019,14 +5019,14 @@ let rec TcSignatureElementNonMutRec (cenv: cenv) parent typeNames endm (env: TcE return env - with RecoverableException exn -> + with exn -> errorRecovery exn endm return env } and TcSignatureElements cenv parent endm env xml mutRecNSInfo defs = - cancellable { + async2 { // Ensure the .Deref call in UpdateAccModuleOrNamespaceType succeeds if cenv.compilingCanonicalFslibModuleType then let checkXmlDocs = cenv.diagnosticOptions.CheckXmlDocs @@ -5042,10 +5042,16 @@ and TcSignatureElements cenv parent endm env xml mutRecNSInfo defs = } and TcSignatureElementsNonMutRec cenv parent typeNames endm env defs = - Cancellable.fold (TcSignatureElementNonMutRec cenv parent typeNames endm) env defs + async2 { + match defs with + | [] -> return env + | def :: rest -> + let! env = TcSignatureElementNonMutRec cenv parent typeNames endm env def + return! TcSignatureElementsNonMutRec cenv parent typeNames endm env rest + } and TcSignatureElementsMutRec cenv parent typeNames m mutRecNSInfo envInitial (defs: SynModuleSigDecl list) = - cancellable { + async2 { let m = match defs with [] -> m | _ -> defs |> List.map (fun d -> d.Range) |> List.reduce unionRanges let scopem = (defs, m) ||> List.foldBack (fun h m -> unionRanges h.Range m) @@ -5100,7 +5106,7 @@ and TcSignatureElementsMutRec cenv parent typeNames m mutRecNSInfo envInitial (d and TcModuleOrNamespaceSignatureElementsNonMutRec cenv parent env (id, moduleKind, defs, m: range, xml) = - cancellable { + async2 { let endm = m.EndRange // use end of range for errors // Create the module type that will hold the results of type checking.... @@ -5258,7 +5264,7 @@ let TcModuleOrNamespaceElementsMutRec (cenv: cenv) parent typeNames m envInitial /// The non-mutually recursive case for a declaration let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem env synDecl = - cancellable { + async2 { let g = cenv.g cenv.synArgNameGenerator.Reset() let tpenv = emptyUnscopedTyparEnv @@ -5369,7 +5375,6 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem // Now typecheck. let! moduleContents, topAttrsNew, envAtEnd = TcModuleOrNamespaceElements cenv (Parent (mkLocalModuleRef moduleEntity)) endm envForModule xml None [] moduleDefs - |> cenv.stackGuard.GuardCancellable // Get the inferred type of the decls and record it in the modul. moduleEntity.entity_modul_type <- MaybeLazy.Strict moduleTyAcc.Value @@ -5461,7 +5466,6 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem let! moduleContents, topAttrs, envAtEnd = TcModuleOrNamespaceElements cenv parent endm envNS xml mutRecNSInfo [] defs - |> cenv.stackGuard.GuardCancellable MutRecBindingChecking.TcMutRecDefns_UpdateNSContents nsInfo let env, openDecls = @@ -5491,20 +5495,17 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem return (defns, [], topAttrs), env, envAtEnd - with RecoverableException exn -> + with exn -> errorRecovery exn synDecl.Range return ([], [], []), env, env } /// The non-mutually recursive case for a sequence of declarations -and [] TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm (defsSoFar, env, envAtEnd) (moreDefs: SynModuleDecl list) (ct: CancellationToken) = - - if ct.IsCancellationRequested then - ValueOrCancelled.Cancelled(OperationCanceledException ct) - else +and TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm (defsSoFar, env, envAtEnd) (moreDefs: SynModuleDecl list) = + async2 { match moreDefs with | [] -> - ValueOrCancelled.Value (List.rev defsSoFar, envAtEnd) + return List.rev defsSoFar, envAtEnd | firstDef :: otherDefs -> // Lookahead one to find out the scope of the next declaration. let scopem = @@ -5513,17 +5514,12 @@ and [] TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm else unionRanges (List.head otherDefs).Range endm - let result = Cancellable.run ct (TcModuleOrNamespaceElementNonMutRec cenv parent typeNames scopem env firstDef |> cenv.stackGuard.GuardCancellable) - - match result with - | ValueOrCancelled.Cancelled x -> - ValueOrCancelled.Cancelled x - | ValueOrCancelled.Value(firstDef, env, envAtEnd) -> - TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm ((firstDef :: defsSoFar), env, envAtEnd) otherDefs ct - + let! firstDef, env, envAtEnd = TcModuleOrNamespaceElementNonMutRec cenv parent typeNames scopem env firstDef + return! TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm ((firstDef :: defsSoFar), env, envAtEnd) otherDefs + } and TcModuleOrNamespaceElements cenv parent endm env xml mutRecNSInfo openDecls0 synModuleDecls = - cancellable { + async2 { // Ensure the deref_nlpath call in UpdateAccModuleOrNamespaceType succeeds if cenv.compilingCanonicalFslibModuleType then let checkXmlDocs = cenv.diagnosticOptions.CheckXmlDocs @@ -5545,21 +5541,15 @@ and TcModuleOrNamespaceElements cenv parent endm env xml mutRecNSInfo openDecls0 return (moduleContents, topAttrsNew, envAtEnd) | None -> - let! ct = Cancellable.token () - let result = TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm ([], env, env) synModuleDecls ct - - match result with - | ValueOrCancelled.Value(compiledDefs, envAtEnd) -> - // Apply the functions for each declaration to build the overall expression-builder - let moduleDefs = List.collect p13 compiledDefs - let moduleDefs = match openDecls0 with [] -> moduleDefs | _ -> TMDefOpens openDecls0 :: moduleDefs - let moduleContents = TMDefs moduleDefs - - // Collect up the attributes that are global to the file - let topAttrsNew = List.collect p33 compiledDefs - return (moduleContents, topAttrsNew, envAtEnd) - | ValueOrCancelled.Cancelled x -> - return! Cancellable(fun _ -> ValueOrCancelled.Cancelled x) + let! compiledDefs, envAtEnd = TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm ([], env, env) synModuleDecls + // Apply the functions for each declaration to build the overall expression-builder + let moduleDefs = List.collect p13 compiledDefs + let moduleDefs = match openDecls0 with [] -> moduleDefs | _ -> TMDefOpens openDecls0 :: moduleDefs + let moduleContents = TMDefs moduleDefs + + // Collect up the attributes that are global to the file + let topAttrsNew = List.collect p33 compiledDefs + return (moduleContents, topAttrsNew, envAtEnd) } @@ -5771,7 +5761,7 @@ let CheckOneImplFile let (ParsedImplFileInput (fileName, isScript, qualNameOfFile, _, implFileFrags, isLastCompiland, _, _)) = synImplFile let infoReader = InfoReader(g, amap) - cancellable { + async2 { use _ = Activity.start "CheckDeclarations.CheckOneImplFile" [| @@ -5796,7 +5786,6 @@ let CheckOneImplFile let defs = [ for x in implFileFrags -> SynModuleDecl.NamespaceFragment x ] let! moduleContents, topAttrs, envAtEnd = TcModuleOrNamespaceElements cenv ParentNone qualNameOfFile.Range envinner PreXmlDoc.Empty None openDecls0 defs - |> cenv.stackGuard.GuardCancellable let implFileTypePriorToSig = moduleTyAcc.Value @@ -5916,7 +5905,7 @@ let CheckOneImplFile /// Check an entire signature file let CheckOneSigFile (g, amap, thisCcu, checkForErrors, conditionalDefines, tcSink, isInternalTestSpanStackReferring, diagnosticOptions) tcEnv (sigFile: ParsedSigFileInput) = - cancellable { + async2 { use _ = Activity.start "CheckDeclarations.CheckOneSigFile" [| @@ -5947,7 +5936,7 @@ let CheckOneSigFile (g, amap, thisCcu, checkForErrors, conditionalDefines, tcSin try sigFileType |> IterTyconsOfModuleOrNamespaceType (fun tycon -> FinalTypeDefinitionChecksAtEndOfInferenceScope(cenv.infoReader, tcEnv.NameEnv, cenv.tcSink, false, tcEnv.DisplayEnv, tycon)) - with RecoverableException exn -> errorRecovery exn sigFile.QualifiedName.Range + with exn -> errorRecovery exn sigFile.QualifiedName.Range UpdatePrettyTyparNames.updateModuleOrNamespaceType sigFileType diff --git a/src/Compiler/Checking/CheckDeclarations.fsi b/src/Compiler/Checking/CheckDeclarations.fsi index 9b06fcc828d..1a2be70f80d 100644 --- a/src/Compiler/Checking/CheckDeclarations.fsi +++ b/src/Compiler/Checking/CheckDeclarations.fsi @@ -60,7 +60,7 @@ val CheckOneImplFile: ModuleOrNamespaceType option * ParsedImplFileInput * FSharpDiagnosticOptions -> - Cancellable + Async2 val CheckOneSigFile: TcGlobals * @@ -73,7 +73,7 @@ val CheckOneSigFile: FSharpDiagnosticOptions -> TcEnv -> ParsedSigFileInput -> - Cancellable + Async2 exception NotUpperCaseConstructor of range: range diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 0db023fc327..61ea9f3010e 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -296,7 +296,7 @@ and IProjectReference = abstract FileName: string /// Evaluate raw contents of the assembly file generated by the project - abstract EvaluateRawContents: unit -> Async + abstract EvaluateRawContents: unit -> Async2 /// Get the logical timestamp that would be the timestamp of the assembly file generated by the project /// diff --git a/src/Compiler/Driver/CompilerConfig.fsi b/src/Compiler/Driver/CompilerConfig.fsi index 0e6c25727f8..82cd78e36d7 100644 --- a/src/Compiler/Driver/CompilerConfig.fsi +++ b/src/Compiler/Driver/CompilerConfig.fsi @@ -19,7 +19,6 @@ open FSharp.Compiler.Features open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Syntax open FSharp.Compiler.Text -open FSharp.Compiler.BuildGraph exception FileNameNotResolved of searchedLocations: string * fileName: string * range: range @@ -89,7 +88,7 @@ and IProjectReference = /// Evaluate raw contents of the assembly file generated by the project. /// 'None' may be returned if an in-memory view of the contents is, for some reason, /// not available. In this case the on-disk view of the contents will be preferred. - abstract EvaluateRawContents: unit -> Async + abstract EvaluateRawContents: unit -> Async2 /// Get the logical timestamp that would be the timestamp of the assembly file generated by the project. /// diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 4ab1ca3d7e4..51984a146e5 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2249,14 +2249,14 @@ and [] TcImports // NOTE: When used in the Language Service this can cause the transitive checking of projects. Hence it must be cancellable. member tcImports.TryRegisterAndPrepareToImportReferencedDll (ctok, r: AssemblyResolution) - : Async<(_ * (unit -> AvailableImportedAssembly list)) option> = - async { + : Async2<(_ * (unit -> AvailableImportedAssembly list)) option> = + async2 { CheckDisposed() let m = r.originalReference.Range let fileName = r.resolvedPath let! contentsOpt = - async { + async2 { match r.ProjectReference with | Some ilb -> return! ilb.EvaluateRawContents() | None -> return ProjectAssemblyDataResult.Unavailable true @@ -2319,7 +2319,7 @@ and [] TcImports // NOTE: When used in the Language Service this can cause the transitive checking of projects. Hence it must be cancellable. member tcImports.RegisterAndImportReferencedAssemblies(ctok, nms: AssemblyResolution list) = - async { + async2 { CheckDisposed() let tcConfig = tcConfigP.Get ctok @@ -2332,7 +2332,7 @@ and [] TcImports let! results = nms |> List.map (fun nm -> - async { + async2 { try use _ = new CompilationGlobalsScope() return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) @@ -2376,7 +2376,7 @@ and [] TcImports ReportWarnings warns tcImports.RegisterAndImportReferencedAssemblies(ctok, res) - |> Async.RunImmediate + |> Async2.RunImmediate |> ignore true @@ -2466,7 +2466,7 @@ and [] TcImports // we dispose TcImports is because we need to dispose type providers, and type providers are never included in the framework DLL set. // If a framework set ever includes type providers, you will not have to worry about explicitly calling Dispose as the Finalizer will handle it. static member BuildFrameworkTcImports(tcConfigP: TcConfigProvider, frameworkDLLs, nonFrameworkDLLs) = - async { + async2 { let ctok = CompilationThreadToken() let tcConfig = tcConfigP.Get ctok @@ -2543,7 +2543,7 @@ and [] TcImports resolvedAssemblies |> List.choose tryFindEquivPrimaryAssembly let! fslibCcu, fsharpCoreAssemblyScopeRef = - async { + async2 { if tcConfig.compilingFSharpCore then // When compiling FSharp.Core.dll, the fslibCcu reference to FSharp.Core.dll is a delayed ccu thunk fixed up during type checking return CcuThunk.CreateDelayed getFSharpCoreLibraryName, ILScopeRef.Local @@ -2634,7 +2634,7 @@ and [] TcImports (tcConfigP: TcConfigProvider, baseTcImports, nonFrameworkReferences, knownUnresolved, dependencyProvider) = - async { + async2 { let ctok = CompilationThreadToken() let tcConfig = tcConfigP.Get ctok @@ -2652,7 +2652,7 @@ and [] TcImports } static member BuildTcImports(tcConfigP: TcConfigProvider, dependencyProvider) = - async { + async2 { let ctok = CompilationThreadToken() let tcConfig = tcConfigP.Get ctok @@ -2684,7 +2684,7 @@ let RequireReferences (ctok, tcImports: TcImports, tcEnv, thisAssemblyName, reso let ccuinfos = tcImports.RegisterAndImportReferencedAssemblies(ctok, resolutions) - |> Async.RunImmediate + |> Async2.RunImmediate let asms = ccuinfos diff --git a/src/Compiler/Driver/CompilerImports.fsi b/src/Compiler/Driver/CompilerImports.fsi index 2a95347ecbf..0649b707464 100644 --- a/src/Compiler/Driver/CompilerImports.fsi +++ b/src/Compiler/Driver/CompilerImports.fsi @@ -206,14 +206,14 @@ type TcImports = member internal Base: TcImports option static member BuildFrameworkTcImports: - TcConfigProvider * AssemblyResolution list * AssemblyResolution list -> Async + TcConfigProvider * AssemblyResolution list * AssemblyResolution list -> Async2 static member BuildNonFrameworkTcImports: TcConfigProvider * TcImports * AssemblyResolution list * UnresolvedAssemblyReference list * DependencyProvider -> - Async + Async2 static member BuildTcImports: - tcConfigP: TcConfigProvider * dependencyProvider: DependencyProvider -> Async + tcConfigP: TcConfigProvider * dependencyProvider: DependencyProvider -> Async2 /// Process a group of #r in F# Interactive. /// Adds the reference to the tcImports and add the ccu to the type checking environment. diff --git a/src/Compiler/Driver/GraphChecking/GraphProcessing.fs b/src/Compiler/Driver/GraphChecking/GraphProcessing.fs index 33dd1c42c46..ccdf5c61730 100644 --- a/src/Compiler/Driver/GraphChecking/GraphProcessing.fs +++ b/src/Compiler/Driver/GraphChecking/GraphProcessing.fs @@ -4,6 +4,7 @@ open System.Threading open FSharp.Compiler.GraphChecking open System.Threading.Tasks open System +open Internal.Utilities.Library /// Information about the node in a graph, describing its relation with other nodes. type NodeInfo<'Item> = @@ -38,16 +39,13 @@ type ProcessedNode<'Item, 'Result> = type GraphProcessingException(msg, ex: System.Exception) = inherit exn(msg, ex) -let processGraph<'Item, 'Result when 'Item: equality and 'Item: comparison> +let processGraphAsync<'Item, 'Result when 'Item: equality and 'Item: comparison> (graph: Graph<'Item>) - (work: ('Item -> ProcessedNode<'Item, 'Result>) -> NodeInfo<'Item> -> 'Result) - (parentCt: CancellationToken) - : ('Item * 'Result)[] = + (work: ('Item -> ProcessedNode<'Item, 'Result>) -> NodeInfo<'Item> -> Async2<'Result>) + : Async2<('Item * 'Result)[]> = + let transitiveDeps = graph |> Graph.transitive let dependents = graph |> Graph.reverse - // Cancellation source used to signal either an exception in one of the items or end of processing. - use localCts = new CancellationTokenSource() - use cts = CancellationTokenSource.CreateLinkedTokenSource(parentCt, localCts.Token) let makeNode (item: 'Item) : GraphNode<'Item, 'Result> = let info = @@ -91,203 +89,36 @@ let processGraph<'Item, 'Result when 'Item: equality and 'Item: comparison> |> Option.defaultWith (fun () -> failwith $"Results for item '{node.Info.Item}' are not yet available") } - let processedCount = IncrementableInt(0) - - /// Create a setter and getter for an exception raised in one of the work items. - /// Only the first exception encountered is stored - this can cause non-deterministic errors if more than one item fails. - let raiseExn, getExn = - let mutable exn: ('Item * System.Exception) option = None - let lockObj = obj () - // Only set the exception if it hasn't been set already - let setExn newExn = - lock lockObj (fun () -> - match exn with - | Some _ -> () - | None -> exn <- newExn - - localCts.Cancel()) - - let getExn () = exn - setExn, getExn - - let incrementProcessedNodesCount () = - if processedCount.Increment() = nodes.Count then - localCts.Cancel() - let rec queueNode node = - Async.Start( - async { - let! res = async { processNode node } |> Async.Catch - - match res with - | Choice1Of2() -> () - | Choice2Of2 ex -> raiseExn (Some(node.Info.Item, ex)) - }, - cts.Token - ) - - and processNode (node: GraphNode<'Item, 'Result>) : unit = - - let info = node.Info - - let singleRes = work getItemPublicNode info - node.Result <- Some singleRes - - let unblockedDependents = - node.Info.Dependents - |> lookupMany - // For every dependent, increment its number of processed dependencies, - // and filter dependents which now have all dependencies processed (but didn't before). - |> Array.filter (fun dependent -> - let pdc = dependent.ProcessedDepsCount.Increment() - // Note: We cannot read 'dependent.ProcessedDepsCount' again to avoid returning the same item multiple times. - pdc = dependent.Info.Deps.Length) - - unblockedDependents |> Array.iter queueNode - incrementProcessedNodesCount () - - leaves |> Array.iter queueNode - - // Wait for end of processing, an exception, or an external cancellation request. - cts.Token.WaitHandle.WaitOne() |> ignore - // If we stopped early due to external cancellation, throw. - parentCt.ThrowIfCancellationRequested() - - // If we stopped early due to an exception, reraise it. - match getExn () with - | None -> () - | Some(item, ex) -> raise (GraphProcessingException($"Encountered exception when processing item '{item}'", ex)) - - // All calculations succeeded - extract the results and sort in input order. - nodes.Values - |> Seq.map (fun node -> - let result = - node.Result - |> Option.defaultWith (fun () -> failwith $"Unexpected lack of result for item '{node.Info.Item}'") - - node.Info.Item, result) - |> Seq.sortBy fst - |> Seq.toArray - -let processGraphAsync<'Item, 'Result when 'Item: equality and 'Item: comparison> - (graph: Graph<'Item>) - (work: ('Item -> ProcessedNode<'Item, 'Result>) -> NodeInfo<'Item> -> Async<'Result>) - : Async<('Item * 'Result)[]> = - async { - let transitiveDeps = graph |> Graph.transitive - let dependents = graph |> Graph.reverse - // Cancellation source used to signal either an exception in one of the items or end of processing. - let! parentCt = Async.CancellationToken - use localCts = new CancellationTokenSource() - - let completionSignal = TaskCompletionSource() - - use _ = parentCt.Register(fun () -> completionSignal.TrySetCanceled() |> ignore) - - use cts = CancellationTokenSource.CreateLinkedTokenSource(parentCt, localCts.Token) - - let makeNode (item: 'Item) : GraphNode<'Item, 'Result> = - let info = - let exists = graph.ContainsKey item - - if - not exists - || not (transitiveDeps.ContainsKey item) - || not (dependents.ContainsKey item) - then - printfn $"Unexpected inconsistent state of the graph for item '{item}'" - - { - Item = item - Deps = graph[item] - TransitiveDeps = transitiveDeps[item] - Dependents = dependents[item] - } - - { - Info = info - Result = None - ProcessedDepsCount = IncrementableInt(0) - } - - let nodes = graph.Keys |> Seq.map (fun item -> item, makeNode item) |> readOnlyDict - - let lookupMany items = - items |> Array.map (fun item -> nodes[item]) - - let leaves = - nodes.Values |> Seq.filter (fun n -> n.Info.Deps.Length = 0) |> Seq.toArray - - let getItemPublicNode item = - let node = nodes[item] - - { - ProcessedNode.Info = node.Info - ProcessedNode.Result = - node.Result - |> Option.defaultWith (fun () -> failwith $"Results for item '{node.Info.Item}' are not yet available") - } - - let processedCount = IncrementableInt(0) - - let handleExn (item, ex: exn) = + async2 { try - localCts.Cancel() - with :? ObjectDisposedException -> - // If it's disposed already, it means that the processing has already finished, most likely due to cancellation or failure in another node. - () - - match ex with - | :? OperationCanceledException -> completionSignal.TrySetCanceled() - | _ -> - completionSignal.TrySetException( - GraphProcessingException($"[*] Encountered exception when processing item '{item}': {ex.Message}", ex) - ) - |> ignore - - let incrementProcessedNodesCount () = - if processedCount.Increment() = nodes.Count then - completionSignal.TrySetResult() |> ignore - - let rec queueNode node = - Async.Start( - async { - use! _catch = Async.OnCancel(completionSignal.TrySetCanceled >> ignore) - let! res = processNode node |> Async.Catch - - match res with - | Choice1Of2() -> () - | Choice2Of2 ex -> handleExn (node.Info.Item, ex) - }, - cts.Token - ) - - and processNode (node: GraphNode<'Item, 'Result>) : Async = - async { - - let info = node.Info + do! processNode node + with ex -> + return raise (GraphProcessingException($"Encountered exception when processing item '{node.Info.Item}'", ex)) + } - let! singleRes = work getItemPublicNode info - node.Result <- Some singleRes + and processNode (node: GraphNode<'Item, 'Result>) = + async2 { + let info = node.Info - let unblockedDependents = - node.Info.Dependents - |> lookupMany - // For every dependent, increment its number of processed dependencies, - // and filter dependents which now have all dependencies processed (but didn't before). - |> Array.filter (fun dependent -> - let pdc = dependent.ProcessedDepsCount.Increment() - // Note: We cannot read 'dependent.ProcessedDepsCount' again to avoid returning the same item multiple times. - pdc = dependent.Info.Deps.Length) + let! singleRes = work getItemPublicNode info + node.Result <- Some singleRes - unblockedDependents |> Array.iter queueNode - incrementProcessedNodesCount () - } + let unblockedDependents = + node.Info.Dependents + |> lookupMany + // For every dependent, increment its number of processed dependencies, + // and filter dependents which now have all dependencies processed (but didn't before). + |> Array.filter (fun dependent -> + let pdc = dependent.ProcessedDepsCount.Increment() + // Note: We cannot read 'dependent.ProcessedDepsCount' again to avoid returning the same item multiple times. + pdc = dependent.Info.Deps.Length) - leaves |> Array.iter queueNode + do! unblockedDependents |> Seq.map queueNode |> Async2.Parallel |> Async2.Ignore + } - // Wait for end of processing, an exception, or an external cancellation request. - do! completionSignal.Task |> Async.AwaitTask + async2 { + do! leaves |> Seq.map queueNode |> Async2.Parallel |> Async2.Ignore // All calculations succeeded - extract the results and sort in input order. return @@ -301,3 +132,11 @@ let processGraphAsync<'Item, 'Result when 'Item: equality and 'Item: comparison> |> Seq.sortBy fst |> Seq.toArray } + +let processGraph<'Item, 'Result when 'Item: equality and 'Item: comparison> + (graph: Graph<'Item>) + (work: ('Item -> ProcessedNode<'Item, 'Result>) -> NodeInfo<'Item> -> 'Result) + (parentCt: CancellationToken) + : ('Item * 'Result)[] = + let work node info = async2 { return work node info } + Async2.RunImmediate(processGraphAsync graph (fun lookup info -> async2 { return! work lookup info }), parentCt) diff --git a/src/Compiler/Driver/GraphChecking/GraphProcessing.fsi b/src/Compiler/Driver/GraphChecking/GraphProcessing.fsi index 7a8c9f9885e..5e8d8bb46bf 100644 --- a/src/Compiler/Driver/GraphChecking/GraphProcessing.fsi +++ b/src/Compiler/Driver/GraphChecking/GraphProcessing.fsi @@ -3,6 +3,8 @@ module internal FSharp.Compiler.GraphChecking.GraphProcessing open System.Threading +open Internal.Utilities.Library + /// Information about the node in a graph, describing its relation with other nodes. type NodeInfo<'Item> = { Item: 'Item @@ -40,5 +42,5 @@ val processGraph<'Item, 'Result when 'Item: equality and 'Item: comparison> : val processGraphAsync<'Item, 'Result when 'Item: equality and 'Item: comparison> : graph: Graph<'Item> -> - work: (('Item -> ProcessedNode<'Item, 'Result>) -> NodeInfo<'Item> -> Async<'Result>) -> - Async<('Item * 'Result)[]> + work: (('Item -> ProcessedNode<'Item, 'Result>) -> NodeInfo<'Item> -> Async2<'Result>) -> + Async2<('Item * 'Result)[]> diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs index c6de5e776a1..dcc768cecd0 100644 --- a/src/Compiler/Driver/ParseAndCheckInputs.fs +++ b/src/Compiler/Driver/ParseAndCheckInputs.fs @@ -1225,8 +1225,8 @@ let CheckOneInput tcSink: TcResultsSink, tcState: TcState, input: ParsedInput - ) : Cancellable = - cancellable { + ) : Async2 = + async2 { try use _ = Activity.start "ParseAndCheckInputs.CheckOneInput" [| Activity.Tags.fileName, input.FileName |] @@ -1344,7 +1344,7 @@ let DiagnosticsLoggerForInput (tcConfig: TcConfig, oldLogger) = /// Typecheck a single file (or interactive entry into F# Interactive) let CheckOneInputEntry (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt) tcState input = - cancellable { + async2 { // Equip loggers to locally filter w.r.t. scope pragmas in each input use _ = UseTransformedDiagnosticsLogger(fun oldLogger -> DiagnosticsLoggerForInput(tcConfig, oldLogger)) @@ -1355,7 +1355,7 @@ let CheckOneInputEntry (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcG return! CheckOneInput(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, TcResultsSink.NoSink, tcState, input) } - |> Cancellable.runWithoutCancellation + |> Async2.runWithoutCancellation /// Finish checking multiple files (or one interactive entry into F# Interactive) let CheckMultipleInputsFinish (results, tcState: TcState) = @@ -1371,7 +1371,7 @@ let CheckMultipleInputsFinish (results, tcState: TcState) = (tcEnvAtEndOfLastFile, topAttrs, implFiles, ccuSigsForFiles), tcState let CheckOneInputAndFinish (checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input) = - cancellable { + async2 { let! result, tcState = CheckOneInput(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input) let finishedResult = CheckMultipleInputsFinish([ result ], tcState) return finishedResult @@ -1445,8 +1445,8 @@ let CheckOneInputWithCallback _skipImplIfSigExists: bool): (unit -> bool) * TcConfig * TcImports * TcGlobals * LongIdent option * TcResultsSink * TcState * ParsedInput * bool ) - : Cancellable> = - cancellable { + : Async2> = + async2 { try CheckSimulateException tcConfig @@ -1820,7 +1820,7 @@ let CheckMultipleInputsUsingGraphMode : Finisher = let (Finisher(finisher = finisher)) = - cancellable { + async2 { use _ = UseDiagnosticsLogger logger let checkForErrors2 () = @@ -1833,7 +1833,7 @@ let CheckMultipleInputsUsingGraphMode node (checkForErrors2, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, currentTcState, input, false) } - |> Cancellable.runWithoutCancellation + |> Async2.runWithoutCancellation Finisher( node, diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fsi b/src/Compiler/Driver/ParseAndCheckInputs.fsi index 36f3493724c..f34642d083b 100644 --- a/src/Compiler/Driver/ParseAndCheckInputs.fsi +++ b/src/Compiler/Driver/ParseAndCheckInputs.fsi @@ -183,7 +183,7 @@ val CheckOneInput: tcSink: NameResolution.TcResultsSink * tcState: TcState * input: ParsedInput -> - Cancellable<(TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType) * TcState> + Async2<(TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType) * TcState> val CheckOneInputWithCallback: node: NodeToTypeCheck -> @@ -196,7 +196,7 @@ val CheckOneInputWithCallback: tcState: TcState * input: ParsedInput * _skipImplIfSigExists: bool -> - Cancellable> + Async2> val AddCheckResultsToTcState: tcGlobals: TcGlobals * @@ -251,4 +251,4 @@ val CheckOneInputAndFinish: tcSink: NameResolution.TcResultsSink * tcState: TcState * input: ParsedInput -> - Cancellable<(TcEnv * TopAttribs * CheckedImplFile list * ModuleOrNamespaceType list) * TcState> + Async2<(TcEnv * TopAttribs * CheckedImplFile list * ModuleOrNamespaceType list) * TcState> diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index 89f196c810f..924e2e13056 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -605,7 +605,7 @@ let main1 // Import basic assemblies let tcGlobals, frameworkTcImports = TcImports.BuildFrameworkTcImports(foundationalTcConfigP, sysRes, otherRes) - |> Async.RunImmediate + |> Async2.RunImmediate let ilSourceDocs = [ @@ -653,7 +653,7 @@ let main1 let tcImports = TcImports.BuildNonFrameworkTcImports(tcConfigP, frameworkTcImports, otherRes, knownUnresolved, dependencyProvider) - |> Async.RunImmediate + |> Async2.RunImmediate // register tcImports to be disposed in future disposables.Register tcImports diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj index a249c5d2bb1..9448dbc6eb8 100644 --- a/src/Compiler/FSharp.Compiler.Service.fsproj +++ b/src/Compiler/FSharp.Compiler.Service.fsproj @@ -130,6 +130,7 @@ + diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs index e776fe0aae0..b6a3bc250bc 100644 --- a/src/Compiler/Facilities/AsyncMemoize.fs +++ b/src/Compiler/Facilities/AsyncMemoize.fs @@ -8,10 +8,11 @@ open System.Runtime.CompilerServices open FSharp.Compiler.DiagnosticsLogger open Internal.Utilities.Library +open System type AsyncLazyState<'t> = - | Initial of computation: Async<'t> - | Running of initialComputation: Async<'t> * work: Task<'t> * CancellationTokenSource * requestCount: int + | Initial of computation: Async2<'t> + | Running of initialComputation: Async2<'t> * work: Task<'t> * CancellationTokenSource * requestCount: int | Completed of result: 't | Faulted of exn @@ -49,16 +50,16 @@ type AsyncLazy<'t> private (initial: AsyncLazyState<'t>, cancelUnawaited: bool, | state -> state // Nothing more to do if state already transitioned. let detachable (work: Task<'t>) = - async { + async2 { try - let! ct = Async.CancellationToken + let! ct = Async2.CancellationToken // Using ContinueWith with a CancellationToken allows detaching from the running 'work' task. // If the current async workflow is canceled, the 'work' task will continue running independently. - do! work.ContinueWith(ignore>, ct) |> Async.AwaitTask + do! work.ContinueWith(ignore>, ct) with :? TaskCanceledException -> () // If we're here it means there was no cancellation and the 'work' task has completed. - return! work |> Async.AwaitTask + return! work } let onComplete (t: Task<'t>) = @@ -79,21 +80,21 @@ type AsyncLazy<'t> private (initial: AsyncLazyState<'t>, cancelUnawaited: bool, let cts = new CancellationTokenSource() let work = - Async + Async2 .StartAsTask(computation, cancellationToken = cts.Token) .ContinueWith(onComplete, TaskContinuationOptions.NotOnCanceled) Running(computation, work, cts, 1), detachable work | Running(c, work, cts, count) -> Running(c, work, cts, count + 1), detachable work - | Completed result as state -> state, async { return result } - | Faulted exn as state -> state, async { return raise exn } + | Completed result as state -> state, async2 { return result } + | Faulted exn as state -> state, async2 { return raise exn } // computation will deallocate after state transition to Completed ot Faulted. new(computation, ?cancelUnawaited: bool, ?cacheException) = AsyncLazy(Initial computation, defaultArg cancelUnawaited true, defaultArg cacheException true) member _.Request() = - async { + async2 { try return! withStateUpdate request finally @@ -176,7 +177,7 @@ type private KeyData<'TKey, 'TVersion> = Version: 'TVersion } -type Job<'t> = AsyncLazy * CapturingDiagnosticsLogger> +type internal Job<'t> = AsyncLazy * CapturingDiagnosticsLogger> [] type internal AsyncMemoize<'TKey, 'TVersion, 'TValue @@ -224,19 +225,19 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue } let wrappedComputation = - Async.TryCancelled( - async { + Async2.TryCancelled( + async2 { let sw = Stopwatch.StartNew() log Started key let logger = CapturingDiagnosticsLogger "cache" SetThreadDiagnosticsLoggerNoUnwind logger - match! computation |> Async.Catch with - | Choice1Of2 result -> + try + let! result = computation log Finished key Interlocked.Add(&duration, sw.ElapsedMilliseconds) |> ignore return Result.Ok result, logger - | Choice2Of2 exn -> + with exn -> log Failed key return Result.Error exn, logger }, @@ -261,7 +262,7 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue cached |> Option.map countHit |> Option.defaultWith cacheSetNewJob - async { + async2 { let otherVersions, job = lock cache getOrAdd log Requested key @@ -279,6 +280,9 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue | Error exn -> return raise exn } + member this.GetAsync(key, computation: Async<_>) = + this.Get(key, async2 { return! computation }) |> Async2.toAsync + member _.TryGet(key: 'TKey, predicate: 'TVersion -> bool) : 'TValue option = lock cache <| fun () -> diff --git a/src/Compiler/Facilities/AsyncMemoize.fsi b/src/Compiler/Facilities/AsyncMemoize.fsi index 1014dfc6874..cf7ef30cd6d 100644 --- a/src/Compiler/Facilities/AsyncMemoize.fsi +++ b/src/Compiler/Facilities/AsyncMemoize.fsi @@ -1,7 +1,6 @@ namespace Internal.Utilities.Collections -open System.Threading.Tasks -open FSharp.Compiler.BuildGraph +open Internal.Utilities.Library [] module internal Utils = @@ -62,7 +61,9 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue member Clear: predicate: ('TKey -> bool) -> unit - member Get: key: ICacheKey<'TKey, 'TVersion> * computation: Async<'TValue> -> Async<'TValue> + member Get: key: ICacheKey<'TKey, 'TVersion> * computation: Async2<'TValue> -> Async2<'TValue> + + member GetAsync: key: ICacheKey<'TKey, 'TVersion> * computation: Async<'TValue> -> Async<'TValue> member TryGet: key: 'TKey * predicate: ('TVersion -> bool) -> 'TValue option diff --git a/src/Compiler/Facilities/BuildGraph.fs b/src/Compiler/Facilities/BuildGraph.fs index db77f52ea10..8a635a04647 100644 --- a/src/Compiler/Facilities/BuildGraph.fs +++ b/src/Compiler/Facilities/BuildGraph.fs @@ -5,6 +5,8 @@ module FSharp.Compiler.BuildGraph open System.Threading open System.Globalization +open Internal.Utilities.Library + [] module GraphNode = @@ -20,13 +22,13 @@ module GraphNode = | None -> () [] -type GraphNode<'T> private (computation: Async<'T>, cachedResult: ValueOption<'T>, cachedResultNode: Async<'T>) = +type internal GraphNode<'T> private (computation: Async2<'T>, cachedResult: ValueOption<'T>, cachedResultNode: Async2<'T>) = let mutable computation = computation let mutable requestCount = 0 let mutable cachedResult = cachedResult - let mutable cachedResultNode: Async<'T> = cachedResultNode + let mutable cachedResultNode: Async2<'T> = cachedResultNode let isCachedResultNodeNotNull () = not (obj.ReferenceEquals(cachedResultNode, null)) @@ -38,13 +40,15 @@ type GraphNode<'T> private (computation: Async<'T>, cachedResult: ValueOption<'T if isCachedResultNodeNotNull () then cachedResultNode else - async { - let! ct = Async.CancellationToken + async2 { + let! ct = Async2.CancellationToken Interlocked.Increment(&requestCount) |> ignore - let enter = semaphore.WaitAsync(ct) + + let mutable acquired = false try - do! enter |> Async.AwaitTask + do! semaphore.WaitAsync(ct) + acquired <- true match cachedResult with | ValueSome value -> return value @@ -52,17 +56,15 @@ type GraphNode<'T> private (computation: Async<'T>, cachedResult: ValueOption<'T Thread.CurrentThread.CurrentUICulture <- GraphNode.culture let! result = computation cachedResult <- ValueSome result - cachedResultNode <- async.Return result + cachedResultNode <- Async2.fromValue result computation <- Unchecked.defaultof<_> return result finally - // At this point, the semaphore awaiter is either already completed or about to get canceled. - // If calling Wait() does not throw an exception it means the semaphore was successfully taken and needs to be released. - try - enter.Wait() - semaphore.Release() |> ignore - with _ -> - () + if acquired then + try + semaphore.Release() |> ignore + with _ -> + () Interlocked.Decrement(&requestCount) |> ignore } @@ -74,7 +76,7 @@ type GraphNode<'T> private (computation: Async<'T>, cachedResult: ValueOption<'T member _.IsComputing = requestCount > 0 static member FromResult(result: 'T) = - let nodeResult = async.Return result + let nodeResult = Async2.fromValue result GraphNode(nodeResult, ValueSome result, nodeResult) new(computation) = GraphNode(computation, ValueNone, Unchecked.defaultof<_>) diff --git a/src/Compiler/Facilities/BuildGraph.fsi b/src/Compiler/Facilities/BuildGraph.fsi index 2b3016bf99b..b3d55dd91ff 100644 --- a/src/Compiler/Facilities/BuildGraph.fsi +++ b/src/Compiler/Facilities/BuildGraph.fsi @@ -2,6 +2,8 @@ module internal FSharp.Compiler.BuildGraph +open Internal.Utilities.Library + /// Contains helpers related to the build graph [] module internal GraphNode = @@ -18,7 +20,7 @@ module internal GraphNode = type internal GraphNode<'T> = /// - computation - The computation code to run. - new: computation: Async<'T> -> GraphNode<'T> + new: computation: Async2<'T> -> GraphNode<'T> /// Creates a GraphNode with given result already cached. static member FromResult: 'T -> GraphNode<'T> @@ -26,7 +28,7 @@ type internal GraphNode<'T> = /// Return NodeCode which, when executed, will get the value of the computation if already computed, or /// await an existing in-progress computation for the node if one exists, or else will synchronously /// start the computation on the current thread. - member GetOrComputeValue: unit -> Async<'T> + member GetOrComputeValue: unit -> Async2<'T> /// Return 'Some' if the computation has already been computed, else None if /// the computation is in-progress or has not yet been started. diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index b3d08d6d1a3..ae4cf8a9131 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -939,6 +939,8 @@ module StackGuardMetrics = /// Guard against depth of expression nesting, by moving to new stack when a maximum depth is reached type StackGuard(name: string) = + do ignore name + let depth = new ThreadLocal() static member inline IsStackSufficient() = @@ -972,26 +974,17 @@ type StackGuard(name: string) = else let fileName = System.IO.Path.GetFileName(path) let depthWhenJump = depth.Value - StackGuardMetrics.countJump memberName $"{fileName}:{line}" depthWhenJump - async { - do! Async.SwitchToNewThread() - Thread.CurrentThread.Name <- $"F# Extra Compilation Thread for {name} (depth {depthWhenJump})" - return f () - } - |> Async.RunImmediate + async2 { return f () } |> Async2.runWithoutCancellation finally depth.Value <- depth.Value - 1 - [] - member x.GuardCancellable(original: Cancellable<'T>) = - Cancellable(fun ct -> x.Guard(fun () -> Cancellable.run ct original)) // UseMultipleDiagnosticLoggers in ParseAndCheckProject.fs provides similar functionality. // We should probably adapt and reuse that code. module MultipleDiagnosticsLoggers = - let Parallel computations = + let Parallel (computations: Async2<_> seq) = let computationsWithLoggers, diagnosticsReady = [ for i, computation in computations |> Seq.indexed do @@ -1001,7 +994,7 @@ module MultipleDiagnosticsLoggers = // Inject capturing logger into the computation. Signal the TaskCompletionSource when done. let computationsWithLoggers = - async { + async2 { SetThreadDiagnosticsLoggerNoUnwind logger try @@ -1024,11 +1017,11 @@ module MultipleDiagnosticsLoggers = finishedLogger.CommitDelayedDiagnostics target } - async { + async2 { try // We want to restore the current diagnostics context when finished. use _ = new CompilationGlobalsScope() - let! results = Async.Parallel computationsWithLoggers + let! results = Async2.Parallel computationsWithLoggers do! replayDiagnostics |> Async.AwaitTask return results finally @@ -1043,8 +1036,8 @@ module MultipleDiagnosticsLoggers = replayDiagnostics.Wait() } - let Sequential computations = - async { + let Sequential (computations: Async2<_> seq) = + async2 { let results = ResizeArray() for computation in computations do diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index 7a083efae7e..1b5a1f7a19d 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -9,6 +9,8 @@ open FSharp.Compiler.Text open System.Runtime.CompilerServices open System.Runtime.InteropServices +open Internal.Utilities.Library + /// Represents the style being used to format errors [] type DiagnosticStyle = @@ -475,7 +477,6 @@ type StackGuard = [] line: int -> 'T - member GuardCancellable: Internal.Utilities.Library.Cancellable<'T> -> Internal.Utilities.Library.Cancellable<'T> /// This represents the global state established as each task function runs as part of the build. /// @@ -497,7 +498,7 @@ module MultipleDiagnosticsLoggers = /// Run computations using Async.Parallel. /// Captures the diagnostics from each computation and commits them to the caller's logger preserving their order. /// When done, restores caller's build phase and diagnostics logger. - val Parallel: computations: Async<'T> seq -> Async<'T array> + val Parallel: computations: Async2<'T> seq -> Async2<'T array> /// Run computations sequentially starting immediately on the current thread. - val Sequential: computations: Async<'T> seq -> Async<'T array> + val Sequential: computations: Async2<'T> seq -> Async2<'T array> diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index fc1a55ca445..e86300c487e 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -4687,7 +4687,7 @@ type FsiEvaluationSession unresolvedReferences, fsiOptions.DependencyProvider ) - |> Async.RunImmediate + |> Async2.RunImmediate with e -> stopProcessingRecovery e range0 failwithf "Error creating evaluation session: %A" e @@ -4806,7 +4806,7 @@ type FsiEvaluationSession member _.ParseAndCheckInteraction(code) = fsiInteractionProcessor.ParseAndCheckInteraction(legacyReferenceResolver, fsiInteractionProcessor.CurrentState, code) - |> Cancellable.runWithoutCancellation + |> Async2.runWithoutCancellation member _.InteractiveChecker = checker diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs index 1b00bcb1ff1..c4e151e7169 100644 --- a/src/Compiler/Service/BackgroundCompiler.fs +++ b/src/Compiler/Service/BackgroundCompiler.fs @@ -57,7 +57,7 @@ type internal IBackgroundCompiler = sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - Async + Async2 /// Type-check the result obtained by parsing, but only if the antecedent type checking context is available. abstract member CheckFileInProjectAllowingStaleCachedResults: @@ -67,7 +67,7 @@ type internal IBackgroundCompiler = sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - Async + Async2 abstract member ClearCache: options: seq * userOpName: string -> unit @@ -83,31 +83,31 @@ type internal IBackgroundCompiler = symbol: FSharp.Compiler.Symbols.FSharpSymbol * canInvalidateProject: bool * userOpName: string -> - Async> + Async2> abstract member FindReferencesInFile: fileName: string * projectSnapshot: FSharpProjectSnapshot * symbol: FSharp.Compiler.Symbols.FSharpSymbol * userOpName: string -> - Async> + Async2> abstract member GetAssemblyData: options: FSharpProjectOptions * outputFileName: string * userOpName: string -> - Async + Async2 abstract member GetAssemblyData: projectSnapshot: FSharpProjectSnapshot * outputFileName: string * userOpName: string -> - Async + Async2 /// Fetch the check information from the background compiler (which checks w.r.t. the FileSystem API) abstract member GetBackgroundCheckResultsForFileInProject: - fileName: string * options: FSharpProjectOptions * userOpName: string -> Async + fileName: string * options: FSharpProjectOptions * userOpName: string -> Async2 /// Fetch the parse information from the background compiler (which checks w.r.t. the FileSystem API) abstract member GetBackgroundParseResultsForFileInProject: - fileName: string * options: FSharpProjectOptions * userOpName: string -> Async + fileName: string * options: FSharpProjectOptions * userOpName: string -> Async2 abstract member GetCachedCheckFileResult: builder: IncrementalBuilder * fileName: string * sourceText: ISourceText * options: FSharpProjectOptions -> - Async<(FSharpParseFileResults * FSharpCheckFileResults) option> + Async2<(FSharpParseFileResults * FSharpCheckFileResults) option> abstract member GetProjectOptionsFromScript: fileName: string * @@ -122,7 +122,7 @@ type internal IBackgroundCompiler = assumeDotNetFramework: bool option * optionsStamp: int64 option * userOpName: string -> - Async + Async2 abstract GetProjectSnapshotFromScript: fileName: string * @@ -138,44 +138,44 @@ type internal IBackgroundCompiler = assumeDotNetFramework: bool option * optionsStamp: int64 option * userOpName: string -> - Async + Async2 abstract member GetSemanticClassificationForFile: fileName: string * options: FSharpProjectOptions * userOpName: string -> - Async + Async2 abstract member GetSemanticClassificationForFile: fileName: string * snapshot: FSharpProjectSnapshot * userOpName: string -> - Async + Async2 abstract member InvalidateConfiguration: options: FSharpProjectOptions * userOpName: string -> unit abstract InvalidateConfiguration: projectSnapshot: FSharpProjectSnapshot * userOpName: string -> unit - abstract member NotifyFileChanged: fileName: string * options: FSharpProjectOptions * userOpName: string -> Async + abstract member NotifyFileChanged: fileName: string * options: FSharpProjectOptions * userOpName: string -> Async2 - abstract member NotifyProjectCleaned: options: FSharpProjectOptions * userOpName: string -> Async + abstract member NotifyProjectCleaned: options: FSharpProjectOptions * userOpName: string -> Async2 /// Parses and checks the source file and returns untyped AST and check results. abstract member ParseAndCheckFileInProject: fileName: string * fileVersion: int * sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - Async + Async2 abstract member ParseAndCheckFileInProject: fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> - Async + Async2 /// Parse and typecheck the whole project. - abstract member ParseAndCheckProject: options: FSharpProjectOptions * userOpName: string -> Async + abstract member ParseAndCheckProject: options: FSharpProjectOptions * userOpName: string -> Async2 - abstract member ParseAndCheckProject: projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async + abstract member ParseAndCheckProject: projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async2 abstract member ParseFile: fileName: string * sourceText: ISourceText * options: FSharpParsingOptions * cache: bool * flatErrors: bool * userOpName: string -> - Async + Async2 abstract member ParseFile: - fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async + fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async2 /// Try to get recent approximate type check results for a file. abstract member TryGetRecentCheckResultsForFile: @@ -316,7 +316,7 @@ type internal BackgroundCompiler then { new IProjectReference with member x.EvaluateRawContents() = - async { + async2 { Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm) return! self.GetAssemblyData(opts, userOpName + ".CheckReferencedProject(" + nm + ")") } @@ -330,7 +330,7 @@ type internal BackgroundCompiler | FSharpReferencedProject.PEReference(getStamp, delayedReader) -> { new IProjectReference with member x.EvaluateRawContents() = - cancellable { + async2 { let! ilReaderOpt = delayedReader.TryGetILModuleReader() match ilReaderOpt with @@ -343,7 +343,6 @@ type internal BackgroundCompiler // continue to try to use an on-disk DLL return ProjectAssemblyDataResult.Unavailable false } - |> Cancellable.toAsync member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = delayedReader.OutputFile @@ -352,13 +351,12 @@ type internal BackgroundCompiler | FSharpReferencedProject.ILModuleReference(nm, getStamp, getReader) -> { new IProjectReference with member x.EvaluateRawContents() = - cancellable { + async2 { let ilReader = getReader () let ilModuleDef, ilAsmRefs = ilReader.ILModuleDef, ilReader.ILAssemblyRefs let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData return ProjectAssemblyDataResult.Available data } - |> Cancellable.toAsync member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = nm @@ -368,7 +366,7 @@ type internal BackgroundCompiler /// CreateOneIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. let CreateOneIncrementalBuilder (options: FSharpProjectOptions, userOpName) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.CreateOneIncrementalBuilder" [| Activity.Tags.project, options.ProjectFileName |] @@ -474,14 +472,14 @@ type internal BackgroundCompiler let tryGetBuilderNode options = incrementalBuildersCache.TryGet(AnyCallerThread, options) - let tryGetBuilder options : Async option = + let tryGetBuilder options : Async2 option = tryGetBuilderNode options |> Option.map (fun x -> x.GetOrComputeValue()) - let tryGetSimilarBuilder options : Async option = + let tryGetSimilarBuilder options : Async2 option = incrementalBuildersCache.TryGetSimilar(AnyCallerThread, options) |> Option.map (fun x -> x.GetOrComputeValue()) - let tryGetAnyBuilder options : Async option = + let tryGetAnyBuilder options : Async2 option = incrementalBuildersCache.TryGetAny(AnyCallerThread, options) |> Option.map (fun x -> x.GetOrComputeValue()) @@ -495,16 +493,14 @@ type internal BackgroundCompiler getBuilderNode) let createAndGetBuilder (options, userOpName) = - async { - let! ct = Async.CancellationToken + async2 { + let! ct = Async2.CancellationToken let getBuilderNode = createBuilderNode (options, userOpName, ct) return! getBuilderNode.GetOrComputeValue() } - let getOrCreateBuilder (options, userOpName) : Async = - async { - use! _holder = Cancellable.UseToken() - + let getOrCreateBuilder (options, userOpName) : Async2 = + async2 { match tryGetBuilder options with | Some getBuilder -> match! getBuilder with @@ -558,7 +554,7 @@ type internal BackgroundCompiler | _ -> let res = GraphNode( - async { + async2 { let! res = self.CheckOneFileImplAux( parseResults, @@ -582,7 +578,7 @@ type internal BackgroundCompiler member _.ParseFile (fileName: string, sourceText: ISourceText, options: FSharpParsingOptions, cache: bool, flatErrors: bool, userOpName: string) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.ParseFile" @@ -599,7 +595,7 @@ type internal BackgroundCompiler | Some res -> return res | None -> Interlocked.Increment(&actualParseFileCount) |> ignore - let! ct = Async.CancellationToken + let! ct = Async2.CancellationToken let parseDiagnostics, parseTree, anyErrors = ParseAndCheckFile.parseFile ( @@ -619,7 +615,7 @@ type internal BackgroundCompiler parseCacheLock.AcquireLock(fun ltok -> parseFileCache.Set(ltok, (fileName, hash, options), res)) return res else - let! ct = Async.CancellationToken + let! ct = Async2.CancellationToken let parseDiagnostics, parseTree, anyErrors = ParseAndCheckFile.parseFile ( @@ -638,7 +634,7 @@ type internal BackgroundCompiler /// Fetch the parse information from the background compiler (which checks w.r.t. the FileSystem API) member _.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.GetBackgroundParseResultsForFileInProject" @@ -678,7 +674,7 @@ type internal BackgroundCompiler } member _.GetCachedCheckFileResult(builder: IncrementalBuilder, fileName, sourceText: ISourceText, options) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.GetCachedCheckFileResult" [| Activity.Tags.fileName, fileName |] @@ -715,9 +711,9 @@ type internal BackgroundCompiler tcPrior: PartialCheckResults, tcInfo: TcInfo, creationDiags: FSharpDiagnostic[] - ) : Async = + ) : Async2 = - async { + async2 { // Get additional script #load closure information if applicable. // For scripts, this will have been recorded by GetProjectOptionsFromScript. let tcConfig = tcPrior.TcConfig @@ -745,7 +741,7 @@ type internal BackgroundCompiler keepAssemblyContents, suggestNamesForErrors ) - |> Cancellable.toAsync + |> Async2.toAsync GraphNode.SetPreferredUILang tcConfig.preferredUiLang return (parseResults, checkAnswer, sourceText.GetHashCode() |> int64, tcPrior.ProjectTimeStamp) @@ -764,7 +760,7 @@ type internal BackgroundCompiler creationDiags: FSharpDiagnostic[] ) = - async { + async2 { match! bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) with | Some(_, results) -> return FSharpCheckFileAnswer.Succeeded results | _ -> @@ -779,7 +775,7 @@ type internal BackgroundCompiler member bc.CheckFileInProjectAllowingStaleCachedResults (parseResults: FSharpParseFileResults, fileName, fileVersion, sourceText: ISourceText, options, userOpName) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.CheckFileInProjectAllowingStaleCachedResults" @@ -790,7 +786,7 @@ type internal BackgroundCompiler |] let! cachedResults = - async { + async2 { let! builderOpt, creationDiags = getAnyBuilder (options, userOpName) match builderOpt with @@ -833,7 +829,7 @@ type internal BackgroundCompiler member bc.CheckFileInProject (parseResults: FSharpParseFileResults, fileName, fileVersion, sourceText: ISourceText, options, userOpName) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.CheckFileInProject" @@ -876,7 +872,7 @@ type internal BackgroundCompiler member bc.ParseAndCheckFileInProject (fileName: string, fileVersion, sourceText: ISourceText, options: FSharpProjectOptions, userOpName) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.ParseAndCheckFileInProject" @@ -911,7 +907,7 @@ type internal BackgroundCompiler ) GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang - let! ct = Async.CancellationToken + let! ct = Async2.CancellationToken let parseDiagnostics, parseTree, anyErrors = ParseAndCheckFile.parseFile ( @@ -945,7 +941,7 @@ type internal BackgroundCompiler } member _.NotifyFileChanged(fileName, options, userOpName) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.NotifyFileChanged" @@ -964,7 +960,7 @@ type internal BackgroundCompiler /// Fetch the check information from the background compiler (which checks w.r.t. the FileSystem API) member _.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.ParseAndCheckFileInProject" @@ -1071,7 +1067,7 @@ type internal BackgroundCompiler member _.FindReferencesInFile (fileName: string, options: FSharpProjectOptions, symbol: FSharpSymbol, canInvalidateProject: bool, userOpName: string) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.FindReferencesInFile" @@ -1099,7 +1095,7 @@ type internal BackgroundCompiler } member _.GetSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, userOpName: string) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.GetSemanticClassificationForFile" @@ -1162,7 +1158,7 @@ type internal BackgroundCompiler /// Parse and typecheck the whole project (the implementation, called recursively as project graph is evaluated) member private _.ParseAndCheckProjectImpl(options, userOpName) = - async { + async2 { let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName) @@ -1235,7 +1231,7 @@ type internal BackgroundCompiler } member _.GetAssemblyData(options, userOpName) = - async { + async2 { use _ = Activity.start "BackgroundCompiler.GetAssemblyData" @@ -1294,7 +1290,7 @@ type internal BackgroundCompiler "BackgroundCompiler.GetProjectOptionsFromScript" [| Activity.Tags.fileName, fileName; Activity.Tags.userOpName, _userOpName |] - cancellable { + async2 { // Do we add a reference to FSharp.Compiler.Interactive.Settings by default? let useFsiAuxLib = defaultArg useFsiAuxLib true let useSdkRefs = defaultArg useSdkRefs true @@ -1377,7 +1373,6 @@ type internal BackgroundCompiler return options, (diags @ diagnostics.Diagnostics) } - |> Cancellable.toAsync member bc.InvalidateConfiguration(options: FSharpProjectOptions, userOpName) = use _ = @@ -1418,9 +1413,9 @@ type internal BackgroundCompiler Activity.Tags.userOpName, userOpName |] - async { + async2 { - let! ct = Async.CancellationToken + let! ct = Async2.CancellationToken // If there was a similar entry (as there normally will have been) then re-establish an empty builder . This // is a somewhat arbitrary choice - it will have the effect of releasing memory associated with the previous // builder, but costs some time. @@ -1479,8 +1474,8 @@ type internal BackgroundCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : Async = - async { + ) : Async2 = + async2 { ignore parseResults let! _, result = this.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName) @@ -1496,7 +1491,7 @@ type internal BackgroundCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : Async = + ) : Async2 = self.CheckFileInProjectAllowingStaleCachedResults(parseResults, fileName, fileVersion, sourceText, options, userOpName) member _.ClearCache(options: seq, userOpName: string) : unit = self.ClearCache(options, userOpName) @@ -1510,7 +1505,7 @@ type internal BackgroundCompiler member _.FindReferencesInFile (fileName: string, options: FSharpProjectOptions, symbol: FSharpSymbol, canInvalidateProject: bool, userOpName: string) - : Async> = + : Async2> = self.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName) member this.FindReferencesInFile(fileName, projectSnapshot, symbol, userOpName) = @@ -1518,27 +1513,27 @@ type internal BackgroundCompiler member _.FrameworkImportsCache: FrameworkImportsCache = self.FrameworkImportsCache - member _.GetAssemblyData(options: FSharpProjectOptions, _fileName: string, userOpName: string) : Async = + member _.GetAssemblyData(options: FSharpProjectOptions, _fileName: string, userOpName: string) : Async2 = self.GetAssemblyData(options, userOpName) member _.GetAssemblyData (projectSnapshot: FSharpProjectSnapshot, _fileName: string, userOpName: string) - : Async = + : Async2 = self.GetAssemblyData(projectSnapshot.ToOptions(), userOpName) member _.GetBackgroundCheckResultsForFileInProject (fileName: string, options: FSharpProjectOptions, userOpName: string) - : Async = + : Async2 = self.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName) member _.GetBackgroundParseResultsForFileInProject (fileName: string, options: FSharpProjectOptions, userOpName: string) - : Async = + : Async2 = self.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName) member _.GetCachedCheckFileResult (builder: IncrementalBuilder, fileName: string, sourceText: ISourceText, options: FSharpProjectOptions) - : Async<(FSharpParseFileResults * FSharpCheckFileResults) option> = + : Async2<(FSharpParseFileResults * FSharpCheckFileResults) option> = self.GetCachedCheckFileResult(builder, fileName, sourceText, options) member _.GetProjectOptionsFromScript @@ -1555,7 +1550,7 @@ type internal BackgroundCompiler assumeDotNetFramework: bool option, optionsStamp: int64 option, userOpName: string - ) : Async = + ) : Async2 = self.GetProjectOptionsFromScript( fileName, sourceText, @@ -1586,8 +1581,8 @@ type internal BackgroundCompiler assumeDotNetFramework: bool option, optionsStamp: int64 option, userOpName: string - ) : Async = - async { + ) : Async2 = + async2 { let! options, diagnostics = self.GetProjectOptionsFromScript( fileName, @@ -1610,12 +1605,12 @@ type internal BackgroundCompiler member _.GetSemanticClassificationForFile (fileName: string, options: FSharpProjectOptions, userOpName: string) - : Async = + : Async2 = self.GetSemanticClassificationForFile(fileName, options, userOpName) member _.GetSemanticClassificationForFile (fileName: string, snapshot: FSharpProjectSnapshot, userOpName: string) - : Async = + : Async2 = self.GetSemanticClassificationForFile(fileName, snapshot.ToOptions(), userOpName) member _.InvalidateConfiguration(options: FSharpProjectOptions, userOpName: string) : unit = @@ -1625,35 +1620,35 @@ type internal BackgroundCompiler let options = projectSnapshot.ToOptions() self.InvalidateConfiguration(options, userOpName) - member _.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string) : Async = + member _.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string) : Async2 = self.NotifyFileChanged(fileName, options, userOpName) - member _.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName: string) : Async = + member _.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName: string) : Async2 = self.NotifyProjectCleaned(options, userOpName) member _.ParseAndCheckFileInProject (fileName: string, fileVersion: int, sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string) - : Async = + : Async2 = self.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName) member _.ParseAndCheckFileInProject (fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) - : Async = - async { + : Async2 = + async2 { let fileSnapshot = projectSnapshot.ProjectSnapshot.SourceFiles |> Seq.find (fun f -> f.FileName = fileName) - let! sourceText = fileSnapshot.GetSource() |> Async.AwaitTask + let! sourceText = fileSnapshot.GetSource() let options = projectSnapshot.ToOptions() return! self.ParseAndCheckFileInProject(fileName, 0, sourceText, options, userOpName) } - member _.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : Async = + member _.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : Async2 = self.ParseAndCheckProject(options, userOpName) - member _.ParseAndCheckProject(projectSnapshot: FSharpProjectSnapshot, userOpName: string) : Async = + member _.ParseAndCheckProject(projectSnapshot: FSharpProjectSnapshot, userOpName: string) : Async2 = self.ParseAndCheckProject(projectSnapshot.ToOptions(), userOpName) member _.ParseFile diff --git a/src/Compiler/Service/BackgroundCompiler.fsi b/src/Compiler/Service/BackgroundCompiler.fsi index 6192b23e3f9..35af38f78da 100644 --- a/src/Compiler/Service/BackgroundCompiler.fsi +++ b/src/Compiler/Service/BackgroundCompiler.fsi @@ -8,6 +8,8 @@ open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.CompilerConfig open FSharp.Compiler.Diagnostics +open Internal.Utilities.Library + type SourceTextHash = int64 type CacheStamp = int64 @@ -32,7 +34,7 @@ type internal IBackgroundCompiler = sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - Async + Async2 /// Type-check the result obtained by parsing, but only if the antecedent type checking context is available. abstract CheckFileInProjectAllowingStaleCachedResults: @@ -42,7 +44,7 @@ type internal IBackgroundCompiler = sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - Async + Async2 abstract ClearCache: options: FSharpProjectOptions seq * userOpName: string -> unit @@ -57,7 +59,7 @@ type internal IBackgroundCompiler = projectSnapshot: FSharpProjectSnapshot * symbol: FSharp.Compiler.Symbols.FSharpSymbol * userOpName: string -> - Async + Async2 abstract FindReferencesInFile: fileName: string * @@ -65,27 +67,27 @@ type internal IBackgroundCompiler = symbol: FSharp.Compiler.Symbols.FSharpSymbol * canInvalidateProject: bool * userOpName: string -> - Async + Async2 abstract GetAssemblyData: projectSnapshot: FSharpProjectSnapshot * outputFileName: string * userOpName: string -> - Async + Async2 abstract GetAssemblyData: - options: FSharpProjectOptions * outputFileName: string * userOpName: string -> Async + options: FSharpProjectOptions * outputFileName: string * userOpName: string -> Async2 /// Fetch the check information from the background compiler (which checks w.r.t. the FileSystem API) abstract GetBackgroundCheckResultsForFileInProject: fileName: string * options: FSharpProjectOptions * userOpName: string -> - Async + Async2 /// Fetch the parse information from the background compiler (which checks w.r.t. the FileSystem API) abstract GetBackgroundParseResultsForFileInProject: - fileName: string * options: FSharpProjectOptions * userOpName: string -> Async + fileName: string * options: FSharpProjectOptions * userOpName: string -> Async2 abstract GetCachedCheckFileResult: builder: IncrementalBuilder * fileName: string * sourceText: ISourceText * options: FSharpProjectOptions -> - Async<(FSharpParseFileResults * FSharpCheckFileResults) option> + Async2<(FSharpParseFileResults * FSharpCheckFileResults) option> abstract GetProjectOptionsFromScript: fileName: string * @@ -100,7 +102,7 @@ type internal IBackgroundCompiler = assumeDotNetFramework: bool option * optionsStamp: int64 option * userOpName: string -> - Async + Async2 abstract GetProjectSnapshotFromScript: fileName: string * @@ -116,27 +118,27 @@ type internal IBackgroundCompiler = assumeDotNetFramework: bool option * optionsStamp: int64 option * userOpName: string -> - Async + Async2 abstract GetSemanticClassificationForFile: fileName: string * snapshot: FSharpProjectSnapshot * userOpName: string -> - Async + Async2 abstract GetSemanticClassificationForFile: fileName: string * options: FSharpProjectOptions * userOpName: string -> - Async + Async2 abstract InvalidateConfiguration: options: FSharpProjectOptions * userOpName: string -> unit abstract InvalidateConfiguration: projectSnapshot: FSharpProjectSnapshot * userOpName: string -> unit - abstract NotifyFileChanged: fileName: string * options: FSharpProjectOptions * userOpName: string -> Async + abstract NotifyFileChanged: fileName: string * options: FSharpProjectOptions * userOpName: string -> Async2 - abstract NotifyProjectCleaned: options: FSharpProjectOptions * userOpName: string -> Async + abstract NotifyProjectCleaned: options: FSharpProjectOptions * userOpName: string -> Async2 abstract ParseAndCheckFileInProject: fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> - Async + Async2 /// Parses and checks the source file and returns untyped AST and check results. abstract ParseAndCheckFileInProject: @@ -145,17 +147,17 @@ type internal IBackgroundCompiler = sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - Async + Async2 abstract ParseAndCheckProject: - projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async + projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async2 /// Parse and typecheck the whole project. abstract ParseAndCheckProject: - options: FSharpProjectOptions * userOpName: string -> Async + options: FSharpProjectOptions * userOpName: string -> Async2 abstract ParseFile: - fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async + fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async2 abstract ParseFile: fileName: string * @@ -164,7 +166,7 @@ type internal IBackgroundCompiler = cache: bool * flatErrors: bool * userOpName: string -> - Async + Async2 /// Try to get recent approximate type check results for a file. abstract TryGetRecentCheckResultsForFile: diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 0609fd8c6ce..2a4fc660da5 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -87,8 +87,8 @@ type DelayedILModuleReader = // fast path match box this.result with | null -> - cancellable { - let! ct = Cancellable.token () + async2 { + let! ct = Async2.CancellationToken return lock this.gate (fun () -> @@ -118,7 +118,7 @@ type DelayedILModuleReader = None | _ -> Some this.result) } - | _ -> cancellable.Return(Some this.result) + | _ -> async2 { return Some this.result } [] type FSharpReferencedProject = @@ -3219,7 +3219,7 @@ module internal ParseAndCheckFile = suggestNamesForErrors: bool ) = - cancellable { + async2 { use _ = Activity.start "ParseAndCheckFile.CheckOneFile" @@ -3245,7 +3245,7 @@ module internal ParseAndCheckFile = let sink = TcResultsSinkImpl(tcGlobals, sourceText = sourceText) let! resOpt = - cancellable { + async2 { try let checkForErrors () = (parseResults.ParseHadErrors || errHandler.ErrorCount > 0) @@ -3703,7 +3703,7 @@ type FSharpCheckFileResults keepAssemblyContents: bool, suggestNamesForErrors: bool ) = - cancellable { + async2 { let! tcErrors, tcFileInfo = ParseAndCheckFile.CheckOneFile( parseResults, @@ -3943,7 +3943,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, tcConfig: TcConfig, tcGlobal let keepAssemblyContents = false member _.ParseAndCheckInteraction(sourceText: ISourceText, ?userOpName: string) = - cancellable { + async2 { let userOpName = defaultArg userOpName "Unknown" let fileName = Path.Combine(tcConfig.implicitIncludeDir, "stdin.fsx") let suggestNamesForErrors = true // Will always be true, this is just for readability @@ -3951,7 +3951,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, tcConfig: TcConfig, tcGlobal let parsingOptions = FSharpParsingOptions.FromTcConfig(tcConfig, [| fileName |], true) - let! ct = Cancellable.token () + let! ct = Async2.CancellationToken let parseErrors, parsedInput, anyErrors = ParseAndCheckFile.parseFile ( diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi index fedc323859f..285b0d5e1db 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fsi +++ b/src/Compiler/Service/FSharpCheckerResults.fsi @@ -3,10 +3,8 @@ namespace FSharp.Compiler.CodeAnalysis open System -open System.Collections.Generic open System.IO open System.Threading -open System.Threading.Tasks open Internal.Utilities.Library open FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.AbstractIL.ILBinaryReader @@ -46,7 +44,7 @@ type DelayedILModuleReader = /// Will lazily create the ILModuleReader. /// Is only evaluated once and can be called by multiple threads. - member internal TryGetILModuleReader: unit -> Cancellable + member internal TryGetILModuleReader: unit -> Async2 /// Unused in this API type public FSharpUnresolvedReferencesSet = internal FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list @@ -504,7 +502,7 @@ type public FSharpCheckFileResults = parseErrors: FSharpDiagnostic[] * keepAssemblyContents: bool * suggestNamesForErrors: bool -> - Cancellable + Async2 /// The result of calling TypeCheckResult including the possibility of abort and background compiler not caught up. and [] public FSharpCheckFileAnswer = @@ -621,7 +619,7 @@ type internal FsiInteractiveChecker = member internal ParseAndCheckInteraction: sourceText: ISourceText * ?userOpName: string -> - Cancellable + Async2 module internal FSharpCheckerResultsSettings = val defaultFSharpBinariesDir: string diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index 91a6efd472a..75b128977f9 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -656,33 +656,32 @@ and [] FSha ProjectSnapshotBase(projectConfig, referencedProjects, sourceFiles) |> FSharpProjectSnapshot - static member FromOptions(options: FSharpProjectOptions, getFileSnapshot, ?snapshotAccumulator) = + static member FromOptions(options: FSharpProjectOptions, getFileSnapshot: _ -> _ -> Async<_>, ?snapshotAccumulator) : Async<_> = let snapshotAccumulator = defaultArg snapshotAccumulator (Dictionary()) - async { + async2 { // TODO: check if options is a good key here if not (snapshotAccumulator.ContainsKey options) then let! sourceFiles = options.SourceFiles - |> Seq.map (getFileSnapshot options) + |> Seq.map (fun name -> async2 { return! getFileSnapshot options name }) |> MultipleDiagnosticsLoggers.Parallel let! referencedProjects = options.ReferencedProjects |> Seq.map (function | FSharpReferencedProject.FSharpReference(outputName, options) -> - async { + async2 { let! snapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot, snapshotAccumulator) return FSharpReferencedProjectSnapshot.FSharpReference(outputName, snapshot) } | FSharpReferencedProject.PEReference(getStamp, reader) -> - async.Return <| FSharpReferencedProjectSnapshot.PEReference(getStamp, reader) + async2 { return FSharpReferencedProjectSnapshot.PEReference(getStamp, reader) } | FSharpReferencedProject.ILModuleReference(outputName, getStamp, getReader) -> - async.Return - <| FSharpReferencedProjectSnapshot.ILModuleReference(outputName, getStamp, getReader)) + async2 { return FSharpReferencedProjectSnapshot.ILModuleReference(outputName, getStamp, getReader) }) |> MultipleDiagnosticsLoggers.Sequential @@ -720,6 +719,7 @@ and [] FSha return snapshotAccumulator[options] } + |> Async2.toAsync static member FromOptions(options: FSharpProjectOptions, documentSource: DocumentSource) = FSharpProjectSnapshot.FromOptions( diff --git a/src/Compiler/Service/FSharpSource.fs b/src/Compiler/Service/FSharpSource.fs index fdcf70c28b9..08586a596e4 100644 --- a/src/Compiler/Service/FSharpSource.fs +++ b/src/Compiler/Service/FSharpSource.fs @@ -28,7 +28,7 @@ type FSharpSource internal () = abstract TimeStamp: DateTime - abstract GetTextContainer: unit -> Async + abstract GetTextContainer: unit -> Async2 type private FSharpSourceMemoryMappedFile(filePath: string, timeStamp: DateTime, openStream: unit -> Stream) = inherit FSharpSource() @@ -38,7 +38,7 @@ type private FSharpSourceMemoryMappedFile(filePath: string, timeStamp: DateTime, override _.TimeStamp = timeStamp override _.GetTextContainer() = - openStream () |> TextContainer.Stream |> async.Return + async2 { return openStream () |> TextContainer.Stream } type private FSharpSourceByteArray(filePath: string, timeStamp: DateTime, bytes: byte[]) = inherit FSharpSource() @@ -48,8 +48,7 @@ type private FSharpSourceByteArray(filePath: string, timeStamp: DateTime, bytes: override _.TimeStamp = timeStamp override _.GetTextContainer() = - TextContainer.Stream(new MemoryStream(bytes, 0, bytes.Length, false) :> Stream) - |> async.Return + async2 { return TextContainer.Stream(new MemoryStream(bytes, 0, bytes.Length, false) :> Stream) } type private FSharpSourceFromFile(filePath: string) = inherit FSharpSource() @@ -58,9 +57,9 @@ type private FSharpSourceFromFile(filePath: string) = override _.TimeStamp = FileSystem.GetLastWriteTimeShim(filePath) - override _.GetTextContainer() = TextContainer.OnDisk |> async.Return + override _.GetTextContainer() = async2 { return TextContainer.OnDisk } -type private FSharpSourceCustom(filePath: string, getTimeStamp, getSourceText) = +type private FSharpSourceCustom(filePath: string, getTimeStamp, getSourceText: unit -> Async) = inherit FSharpSource() override _.FilePath = filePath @@ -68,7 +67,7 @@ type private FSharpSourceCustom(filePath: string, getTimeStamp, getSourceText) = override _.TimeStamp = getTimeStamp () override _.GetTextContainer() = - async { + async2 { let! sourceOpt = getSourceText () return diff --git a/src/Compiler/Service/FSharpSource.fsi b/src/Compiler/Service/FSharpSource.fsi index 6bdabbdedf1..abe31eaf7cc 100644 --- a/src/Compiler/Service/FSharpSource.fsi +++ b/src/Compiler/Service/FSharpSource.fsi @@ -5,6 +5,7 @@ namespace FSharp.Compiler.CodeAnalysis open System open System.IO open FSharp.Compiler.Text +open Internal.Utilities.Library [] type internal TextContainer = @@ -26,7 +27,7 @@ type internal FSharpSource = abstract TimeStamp: DateTime /// Gets the internal text container. Text may be on-disk, in a stream, or a source text. - abstract GetTextContainer: unit -> Async + abstract GetTextContainer: unit -> Async2 /// Creates a FSharpSource from disk. Only used internally. static member internal CreateFromFile: filePath: string -> FSharpSource diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index 6db19653f9a..4d34e62bed4 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -136,7 +136,7 @@ module IncrementalBuildSyntaxTree = ), sourceRange, fileName, [||] let parse (source: FSharpSource) = - async { + async2 { IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBEParsed fileName) use _ = Activity.start "IncrementalBuildSyntaxTree.parse" @@ -247,8 +247,8 @@ type BoundModel private ( ?tcStateOpt: GraphNode * GraphNode ) = - let getTypeCheck (syntaxTree: SyntaxTree) : Async = - async { + let getTypeCheck (syntaxTree: SyntaxTree) : Async2 = + async2 { let! input, _sourceRange, fileName, parseErrors = syntaxTree.ParseNode.GetOrComputeValue() use _ = Activity.start "BoundModel.TypeCheck" [|Activity.Tags.fileName, fileName|] @@ -272,7 +272,6 @@ type BoundModel private ( None, TcResultsSink.WithSink sink, prevTcInfo.tcState, input ) - |> Cancellable.toAsync fileChecked.Trigger fileName @@ -317,13 +316,13 @@ type BoundModel private ( | _ -> None let getTcInfo (typeCheck: GraphNode) = - async { + async2 { let! tcInfo , _, _, _, _ = typeCheck.GetOrComputeValue() return tcInfo } |> GraphNode let getTcInfoExtras (typeCheck: GraphNode) = - async { + async2 { let! _ , sink, implFile, fileName, _ = typeCheck.GetOrComputeValue() // Build symbol keys let itemKeyStore, semanticClassification = @@ -361,17 +360,17 @@ type BoundModel private ( } } |> GraphNode - let defaultTypeCheck = async { return prevTcInfo, TcResultsSinkImpl(tcGlobals), None, "default typecheck - no syntaxTree", [||] } + let defaultTypeCheck = async2 { return prevTcInfo, TcResultsSinkImpl(tcGlobals), None, "default typecheck - no syntaxTree", [||] } let typeCheckNode = syntaxTreeOpt |> Option.map getTypeCheck |> Option.defaultValue defaultTypeCheck |> GraphNode let tcInfoExtras = getTcInfoExtras typeCheckNode let diagnostics = - async { + async2 { let! _, _, _, _, diags = typeCheckNode.GetOrComputeValue() return diags } |> GraphNode let startComputingFullTypeCheck = - async { + async2 { let! _ = tcInfoExtras.GetOrComputeValue() return! diagnostics.GetOrComputeValue() } @@ -386,7 +385,7 @@ type BoundModel private ( GraphNode.FromResult tcInfo, tcInfoExtras | _ -> // start computing extras, so that typeCheckNode can be GC'd quickly - startComputingFullTypeCheck |> Async.Catch |> Async.Ignore |> Async.Start + startComputingFullTypeCheck |> Async2.Catch |> Async2.Ignore |> Async2.Start getTcInfo typeCheckNode, tcInfoExtras member val Diagnostics = diagnostics @@ -412,13 +411,13 @@ type BoundModel private ( member this.GetOrComputeTcInfoExtras = this.TcInfoExtras.GetOrComputeValue - member this.GetOrComputeTcInfoWithExtras() = async { + member this.GetOrComputeTcInfoWithExtras() = async2 { let! tcInfo = this.TcInfo.GetOrComputeValue() let! tcInfoExtras = this.TcInfoExtras.GetOrComputeValue() return tcInfo, tcInfoExtras } - member this.Next(syntaxTree) = async { + member this.Next(syntaxTree) = async2 { let! tcInfo = this.TcInfo.GetOrComputeValue() return BoundModel( @@ -437,7 +436,7 @@ type BoundModel private ( } member this.Finish(finalTcDiagnosticsRev, finalTopAttribs) = - async { + async2 { let! tcInfo = this.TcInfo.GetOrComputeValue() let finishState = { tcInfo with tcDiagnosticsRev = finalTcDiagnosticsRev; topAttribs = finalTopAttribs } return @@ -534,7 +533,7 @@ type FrameworkImportsCache(size) = match frameworkTcImportsCache.TryGet (AnyCallerThread, key) with | Some lazyWork -> lazyWork | None -> - let lazyWork = GraphNode(async { + let lazyWork = GraphNode(async2 { let tcConfigP = TcConfigProvider.Constant tcConfig return! TcImports.BuildFrameworkTcImports (tcConfigP, frameworkDLLs, nonFrameworkResolutions) }) @@ -546,7 +545,7 @@ type FrameworkImportsCache(size) = /// This function strips the "System" assemblies from the tcConfig and returns a age-cached TcImports for them. member this.Get(tcConfig: TcConfig) = - async { + async2 { // Split into installed and not installed. let frameworkDLLs, nonFrameworkResolutions, unresolved = TcAssemblyResolutions.SplitNonFoundationalResolutions(tcConfig) let node = this.GetNode(tcConfig, frameworkDLLs, nonFrameworkResolutions) @@ -581,6 +580,7 @@ type FrameworkImportsCache(size) = return tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolved } + |> Async2.toAsync /// Represents the interim state of checking an assembly [] @@ -600,21 +600,23 @@ type PartialCheckResults (boundModel: BoundModel, timeStamp: DateTime, projectTi member _.TryPeekTcInfoWithExtras() = boundModel.TryPeekTcInfoWithExtras() - member _.GetOrComputeTcInfo() = boundModel.GetOrComputeTcInfo() + member _.GetOrComputeTcInfo() = boundModel.GetOrComputeTcInfo() |> Async2.toAsync - member _.GetOrComputeTcInfoWithExtras() = boundModel.GetOrComputeTcInfoWithExtras() + member _.GetOrComputeTcInfoWithExtras() = boundModel.GetOrComputeTcInfoWithExtras() |> Async2.toAsync member _.GetOrComputeItemKeyStoreIfEnabled() = - async { + async2 { let! info = boundModel.GetOrComputeTcInfoExtras() return info.itemKeyStore } + |> Async2.toAsync member _.GetOrComputeSemanticClassificationIfEnabled() = - async { + async2 { let! info = boundModel.GetOrComputeTcInfoExtras() return info.semanticClassificationKeyStore } + |> Async2.toAsync [] module Utilities = @@ -682,14 +684,14 @@ module IncrementalBuilderHelpers = #if !NO_TYPEPROVIDERS ,importsInvalidatedByTypeProvider: Event #endif - ) : Async = + ) : Async2 = - async { + async2 { let diagnosticsLogger = CompilationDiagnosticLogger("CombineImportedAssembliesTask", tcConfig.diagnosticsOptions) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter) let! tcImports = - async { + async2 { try let! tcImports = TcImports.BuildNonFrameworkTcImports(tcConfigP, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences, dependencyProvider) #if !NO_TYPEPROVIDERS @@ -760,7 +762,7 @@ module IncrementalBuilderHelpers = /// Finish up the typechecking to produce outputs for the rest of the compilation process let FinalizeTypeCheckTask (tcConfig: TcConfig) tcGlobals partialCheck assemblyName outfile (boundModels: GraphNode seq) = - async { + async2 { let diagnosticsLogger = CompilationDiagnosticLogger("FinalizeTypeCheckTask", tcConfig.diagnosticsOptions) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck) @@ -768,13 +770,13 @@ module IncrementalBuilderHelpers = let! tcInfos = computedBoundModels - |> Seq.map (fun boundModel -> async { return! boundModel.GetOrComputeTcInfo() }) + |> Seq.map (fun boundModel -> async2 { return! boundModel.GetOrComputeTcInfo() }) |> MultipleDiagnosticsLoggers.Sequential // tcInfoExtras can be computed in parallel. This will check any previously skipped implementation files in parallel, too. let! latestImplFiles = computedBoundModels - |> Seq.map (fun boundModel -> async { + |> Seq.map (fun boundModel -> async2 { if partialCheck then return None else @@ -970,13 +972,13 @@ module IncrementalBuilderStateHelpers = type BuildStatus = Invalidated | Good let createBoundModelGraphNode (prevBoundModel: GraphNode) syntaxTree = - GraphNode(async { + GraphNode(async2 { let! prevBoundModel = prevBoundModel.GetOrComputeValue() return! prevBoundModel.Next(syntaxTree) }) let createFinalizeBoundModelGraphNode (initialState: IncrementalBuilderInitialState) (boundModels: GraphNode seq) = - GraphNode(async { + GraphNode(async2 { use _ = Activity.start "GetCheckResultsAndImplementationsForProject" [|Activity.Tags.project, initialState.outfile|] let! result = FinalizeTypeCheckTask @@ -1144,7 +1146,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc tryGetSlot state (slot - 1) let evalUpToTargetSlot (state: IncrementalBuilderState) targetSlot = - async { + async2 { if targetSlot < 0 then return Some(initialBoundModel, defaultTimeStamp) else @@ -1175,9 +1177,10 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc let mutable currentState = state - let setCurrentState state cache (ct: CancellationToken) = - async { - do! semaphore.WaitAsync(ct) |> Async.AwaitTask + let setCurrentState state cache = + async2 { + let! ct = Async2.CancellationToken + do! semaphore.WaitAsync(ct) try ct.ThrowIfCancellationRequested() currentState <- computeStampedFileNames initialState state cache @@ -1185,11 +1188,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc semaphore.Release() |> ignore } - let checkFileTimeStamps (cache: TimeStampCache) = - async { - let! ct = Async.CancellationToken - do! setCurrentState currentState cache ct - } + let checkFileTimeStamps (cache: TimeStampCache) = setCurrentState currentState cache do IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBECreated) @@ -1217,12 +1216,13 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc member _.AllDependenciesDeprecated = allDependencies member _.PopulatePartialCheckingResults () = - async { + async2 { let cache = TimeStampCache defaultTimeStamp // One per step do! checkFileTimeStamps cache let! _ = currentState.finalizedBoundModel.GetOrComputeValue() projectChecked.Trigger() } + |> Async2.toAsync member builder.GetCheckResultsBeforeFileInProjectEvenIfStale fileName: PartialCheckResults option = let slotOfFile = builder.GetSlotOfFileName fileName @@ -1259,7 +1259,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc (builder.TryGetCheckResultsBeforeFileInProject fileName).IsSome member builder.GetCheckResultsBeforeSlotInProject slotOfFile = - async { + async2 { let cache = TimeStampCache defaultTimeStamp do! checkFileTimeStamps cache let! result = evalUpToTargetSlot currentState (slotOfFile - 1) @@ -1269,9 +1269,10 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc return PartialCheckResults(boundModel, timestamp, projectTimeStamp) | None -> return! failwith "Expected results to be ready. (GetCheckResultsBeforeSlotInProject)." } + |> Async2.toAsync member builder.GetFullCheckResultsBeforeSlotInProject slotOfFile = - async { + async2 { let cache = TimeStampCache defaultTimeStamp do! checkFileTimeStamps cache let! result = evalUpToTargetSlot currentState (slotOfFile - 1) @@ -1282,6 +1283,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc return PartialCheckResults(boundModel, timestamp, projectTimeStamp) | None -> return! failwith "Expected results to be ready. (GetFullCheckResultsBeforeSlotInProject)." } + |> Async2.toAsync member builder.GetCheckResultsBeforeFileInProject fileName = let slotOfFile = builder.GetSlotOfFileName fileName @@ -1296,17 +1298,18 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc builder.GetFullCheckResultsBeforeSlotInProject slotOfFile member builder.GetFullCheckResultsAfterFileInProject fileName = - async { + async2 { let slotOfFile = builder.GetSlotOfFileName fileName + 1 let! result = builder.GetFullCheckResultsBeforeSlotInProject(slotOfFile) return result } + |> Async2.toAsync member builder.GetCheckResultsAfterLastFileInProject () = builder.GetCheckResultsBeforeSlotInProject(builder.GetSlotsCount()) member builder.GetCheckResultsAndImplementationsForProject() = - async { + async2 { let cache = TimeStampCache(defaultTimeStamp) do! checkFileTimeStamps cache let! result = currentState.finalizedBoundModel.GetOrComputeValue() @@ -1316,14 +1319,16 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc let projectTimeStamp = builder.GetLogicalTimeStampForProject(cache) return PartialCheckResults (boundModel, timestamp, projectTimeStamp), ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt } + |> Async2.toAsync member builder.GetFullCheckResultsAndImplementationsForProject() = - async { + async2 { let! result = builder.GetCheckResultsAndImplementationsForProject() let results, _, _, _ = result let! _ = results.GetOrComputeTcInfoWithExtras() // Make sure we forcefully evaluate the info return result } + |> Async2.toAsync member builder.GetLogicalTimeStampForFileInProject(filename: string) = let slot = builder.GetSlotOfFileName(filename) @@ -1363,18 +1368,18 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc let slotOfFile = builder.GetSlotOfFileName fileName let syntaxTree = currentState.slots[slotOfFile].SyntaxTree syntaxTree.ParseNode.GetOrComputeValue() - |> Async.RunSynchronously + |> Async2.runWithoutCancellation member builder.NotifyFileChanged(fileName, timeStamp) = - async { + async2 { let slotOfFile = builder.GetSlotOfFileName fileName let cache = TimeStampCache defaultTimeStamp - let! ct = Async.CancellationToken do! setCurrentState { currentState with slots = currentState.slots |> List.updateAt slotOfFile (currentState.slots[slotOfFile].Notify timeStamp) } - cache ct + cache } + |> Async2.toAsync member _.SourceFiles = fileNames |> Seq.map (fun f -> f.Source.FilePath) |> List.ofSeq @@ -1407,14 +1412,14 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc let useSimpleResolutionSwitch = "--simpleresolution" - async { + async2 { // Trap and report diagnostics from creation. let delayedLogger = CapturingDiagnosticsLogger("IncrementalBuilderCreation") use _ = new CompilationGlobalsScope(delayedLogger, BuildPhase.Parameter) let! builderOpt = - async { + async2 { try // Create the builder. diff --git a/src/Compiler/Service/IncrementalBuild.fsi b/src/Compiler/Service/IncrementalBuild.fsi index 0f8ed5582da..40be34b2044 100644 --- a/src/Compiler/Service/IncrementalBuild.fsi +++ b/src/Compiler/Service/IncrementalBuild.fsi @@ -3,7 +3,6 @@ namespace FSharp.Compiler.CodeAnalysis open System -open FSharp.Compiler open FSharp.Compiler.AbstractIL open FSharp.Compiler.CheckBasics open FSharp.Compiler.CheckDeclarations @@ -21,7 +20,7 @@ open FSharp.Compiler.Syntax open FSharp.Compiler.TcGlobals open FSharp.Compiler.Text open FSharp.Compiler.TypedTree -open FSharp.Compiler.BuildGraph +open Internal.Utilities.Library open Internal.Utilities.Collections type internal FrameworkImportsCacheKey = @@ -297,7 +296,7 @@ type internal IncrementalBuilder = captureIdentifiersWhenParsing: bool * getSource: (string -> Async) option * useChangeNotifications: bool -> - Async + Async2 /// Generalized Incremental Builder. This is exposed only for unit testing purposes. module internal IncrementalBuild = diff --git a/src/Compiler/Service/ServiceAnalysis.fs b/src/Compiler/Service/ServiceAnalysis.fs index 6455d9f0ff3..af832c338a6 100644 --- a/src/Compiler/Service/ServiceAnalysis.fs +++ b/src/Compiler/Service/ServiceAnalysis.fs @@ -301,13 +301,11 @@ module UnusedOpens = /// Get the open statements whose contents are not referred to anywhere in the symbol uses. /// Async to allow cancellation. let getUnusedOpens (checkFileResults: FSharpCheckFileResults, getSourceLineStr: int -> string) : Async = - async { - use! _holder = Cancellable.UseToken() - + async2 { if checkFileResults.OpenDeclarations.Length = 0 then return [] else - let! ct = Async.CancellationToken + let! ct = Async2.CancellationToken let symbolUses = checkFileResults.GetAllUsesOfAllSymbolsInFile(ct) let symbolUses = filterSymbolUses getSourceLineStr symbolUses let symbolUses = splitSymbolUses symbolUses @@ -318,6 +316,7 @@ module UnusedOpens = else return! filterOpenStatements symbolUses openStatements } + |> Async2.toAsync module SimplifyNames = type SimplifiableRange = { Range: range; RelativeName: string } @@ -326,9 +325,9 @@ module SimplifyNames = (plid |> List.sumBy String.length) + plid.Length let getSimplifiableNames (checkFileResults: FSharpCheckFileResults, getSourceLineStr: int -> string) = - async { + async2 { let result = ResizeArray() - let! ct = Async.CancellationToken + let! ct = Async2.CancellationToken let symbolUses = checkFileResults.GetAllUsesOfAllSymbolsInFile(ct) @@ -405,6 +404,7 @@ module SimplifyNames = return (result :> seq<_>) } + |> Async2.toAsync module UnusedDeclarations = let isPotentiallyUnusedDeclaration (symbol: FSharpSymbol) : bool = @@ -464,9 +464,10 @@ module UnusedDeclarations = |> Seq.map (fun (m, _) -> m) let getUnusedDeclarations (checkFileResults: FSharpCheckFileResults, isScriptFile: bool) = - async { - let! ct = Async.CancellationToken + async2 { + let! ct = Async2.CancellationToken let allSymbolUsesInFile = checkFileResults.GetAllUsesOfAllSymbolsInFile(ct) let unusedRanges = getUnusedDeclarationRanges allSymbolUsesInFile isScriptFile return unusedRanges } + |> Async2.toAsync diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 0c3f01d4a3a..30e615f0de0 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -217,17 +217,17 @@ module private TypeCheckingGraphProcessing = /// let processTypeCheckingGraph (graph: Graph) - (work: NodeToTypeCheck -> TcInfo -> Async>) + (work: NodeToTypeCheck -> TcInfo -> Async2>) (emptyState: TcInfo) - : Async<(int * PartialResult) list * TcInfo> = - async { + : Async2<(int * PartialResult) list * TcInfo> = + async2 { let workWrapper (getProcessedNode: NodeToTypeCheck -> ProcessedNode>) (node: NodeInfo) - : Async> = - async { + : Async2> = + async2 { let folder (state: TcInfo) (Finisher(finisher = finisher)) : TcInfo = finisher state |> snd let deps = node.Deps |> Array.except [| node.Item |] |> Array.map getProcessedNode @@ -422,7 +422,7 @@ type internal TransparentCompiler enablePartialTypeChecking, parallelReferenceResolution, captureIdentifiersWhenParsing, - getSource: (string -> Async) option, + getSource, useChangeNotifications, ?cacheSizes ) as self = @@ -579,7 +579,7 @@ type internal TransparentCompiler caches.ScriptClosure.Get( key, - async { + async2 { return ComputeScriptClosureInner fileName @@ -615,7 +615,7 @@ type internal TransparentCompiler caches.FrameworkImports.Get( key, - async { + async2 { use _ = Activity.start "ComputeFrameworkImports" [] let tcConfigP = TcConfigProvider.Constant tcConfig @@ -639,14 +639,14 @@ type internal TransparentCompiler importsInvalidatedByTypeProvider: Event ) = - async { + async2 { let diagnosticsLogger = CompilationDiagnosticLogger("CombineImportedAssembliesTask", tcConfig.diagnosticsOptions) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter) let! tcImports = - async { + async2 { try let! tcImports = TcImports.BuildNonFrameworkTcImports( @@ -751,7 +751,7 @@ type internal TransparentCompiler then { new IProjectReference with member x.EvaluateRawContents() = - async { + async2 { Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm) return! @@ -771,7 +771,7 @@ type internal TransparentCompiler | FSharpReferencedProjectSnapshot.PEReference(getStamp, delayedReader) -> { new IProjectReference with member x.EvaluateRawContents() = - cancellable { + async2 { let! ilReaderOpt = delayedReader.TryGetILModuleReader() match ilReaderOpt with @@ -784,7 +784,6 @@ type internal TransparentCompiler // continue to try to use an on-disk DLL return ProjectAssemblyDataResult.Unavailable false } - |> Cancellable.toAsync member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = delayedReader.OutputFile @@ -793,13 +792,12 @@ type internal TransparentCompiler | FSharpReferencedProjectSnapshot.ILModuleReference(nm, getStamp, getReader) -> { new IProjectReference with member x.EvaluateRawContents() = - cancellable { + async2 { let ilReader = getReader () let ilModuleDef, ilAsmRefs = ilReader.ILModuleDef, ilReader.ILAssemblyRefs let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData return ProjectAssemblyDataResult.Available data } - |> Cancellable.toAsync member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = nm @@ -807,7 +805,7 @@ type internal TransparentCompiler ] let ComputeTcConfigBuilder (projectSnapshot: ProjectSnapshot) = - async { + async2 { let useSimpleResolutionSwitch = "--simpleresolution" let commandLineArgs = projectSnapshot.CommandLineOptions let defaultFSharpBinariesDir = FSharpCheckerResultsSettings.defaultFSharpBinariesDir @@ -832,8 +830,8 @@ type internal TransparentCompiler match lastScriptFile, projectSnapshot.UseScriptResolutionRules with | Some fsxFile, true -> // assuming UseScriptResolutionRules and a single source file means we are doing this for a script - async { - let! source = fsxFile.GetSource() |> Async.AwaitTask + async2 { + let! source = fsxFile.GetSource() let! closure = ComputeScriptClosure @@ -851,7 +849,7 @@ type internal TransparentCompiler return (Some closure) } - | _ -> async { return None } + | _ -> async2 { return None } let sdkDirOverride = match loadClosureOpt with @@ -933,7 +931,7 @@ type internal TransparentCompiler caches.BootstrapInfoStatic.Get( cacheKey, - async { + async2 { use _ = Activity.start "ComputeBootstrapInfoStatic" @@ -1014,7 +1012,7 @@ type internal TransparentCompiler ) let computeBootstrapInfoInner (projectSnapshot: ProjectSnapshot) = - async { + async2 { let! tcConfigB, sourceFiles, loadClosureOpt = ComputeTcConfigBuilder projectSnapshot @@ -1090,7 +1088,7 @@ type internal TransparentCompiler caches.BootstrapInfo.Get( projectSnapshot.NoFileVersionsKey, - async { + async2 { use _ = Activity.start "ComputeBootstrapInfo" @@ -1103,7 +1101,7 @@ type internal TransparentCompiler use _ = new CompilationGlobalsScope(delayedLogger, BuildPhase.Parameter) let! bootstrapInfoOpt = - async { + async2 { try return! computeBootstrapInfoInner projectSnapshot with exn -> @@ -1136,8 +1134,8 @@ type internal TransparentCompiler // TODO: Not sure if we should cache this. For VS probably not. Maybe it can be configurable by FCS user. let LoadSource (file: FSharpFileSnapshot) isExe isLastCompiland = - async { - let! source = file.GetSource() |> Async.AwaitTask + async2 { + let! source = file.GetSource() return FSharpFileSnapshotWithSource( @@ -1150,7 +1148,7 @@ type internal TransparentCompiler } let LoadSources (bootstrapInfo: BootstrapInfo) (projectSnapshot: ProjectSnapshot) = - async { + async2 { let isExe = bootstrapInfo.TcConfig.target.IsExe let! sources = @@ -1180,7 +1178,7 @@ type internal TransparentCompiler caches.ParseFile.Get( key, - async { + async2 { use _ = Activity.start "ComputeParseFile" @@ -1224,7 +1222,7 @@ type internal TransparentCompiler |> Graph.make let computeDependencyGraph (tcConfig: TcConfig) parsedInputs (processGraph: Graph -> Graph) = - async { + async2 { let sourceFiles: FileInProject array = parsedInputs |> Seq.toArray @@ -1359,7 +1357,7 @@ type internal TransparentCompiler caches.TcIntermediate.Get( key, - async { + async2 { let file = projectSnapshot.SourceFiles[index] @@ -1431,7 +1429,7 @@ type internal TransparentCompiler prevTcInfo.tcState, input, true) - |> Cancellable.toAsync + |> Async2.toAsync //fileChecked.Trigger fileName @@ -1453,7 +1451,7 @@ type internal TransparentCompiler let processGraphNode projectSnapshot bootstrapInfo dependencyFiles collectSinks (fileNode: NodeToTypeCheck) tcInfo = // TODO: should this be node? - async { + async2 { match fileNode with | NodeToTypeCheck.PhysicalFile index -> @@ -1536,7 +1534,7 @@ type internal TransparentCompiler } let parseSourceFiles (projectSnapshot: ProjectSnapshotWithSources) tcConfig = - async { + async2 { let! parsedInputs = projectSnapshot.SourceFiles |> Seq.map (ComputeParseFile projectSnapshot tcConfig) @@ -1551,7 +1549,7 @@ type internal TransparentCompiler caches.TcLastFile.Get( projectSnapshot.FileKey fileName, - async { + async2 { let file = projectSnapshot.SourceFiles |> List.last use _ = @@ -1574,7 +1572,7 @@ type internal TransparentCompiler ) let getParseResult (projectSnapshot: ProjectSnapshot) creationDiags file (tcConfig: TcConfig) = - async { + async2 { let! parsedFile = ComputeParseFile projectSnapshot tcConfig file let parseDiagnostics = @@ -1607,9 +1605,7 @@ type internal TransparentCompiler let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: ProjectSnapshot) = caches.ParseAndCheckFileInProject.Get( projectSnapshot.FileKeyWithExtraFileSnapshotVersion fileName, - async { - use! _holder = Cancellable.UseToken() - + async2 { use _ = Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |> (!!) |] @@ -1719,7 +1715,7 @@ type internal TransparentCompiler let ComputeParseAndCheckAllFilesInProject (bootstrapInfo: BootstrapInfo) (projectSnapshot: ProjectSnapshotWithSources) = caches.ParseAndCheckAllFilesInProject.Get( projectSnapshot.FullKey, - async { + async2 { use _ = Activity.start "ComputeParseAndCheckAllFilesInProject" @@ -1769,7 +1765,7 @@ type internal TransparentCompiler let ComputeProjectExtras (bootstrapInfo: BootstrapInfo) (projectSnapshot: ProjectSnapshotWithSources) = caches.ProjectExtras.Get( projectSnapshot.SignatureKey, - async { + async2 { use _ = Activity.start "ComputeProjectExtras" @@ -1868,7 +1864,7 @@ type internal TransparentCompiler let ComputeAssemblyData (projectSnapshot: ProjectSnapshot) fileName = caches.AssemblyData.Get( projectSnapshot.SignatureKey, - async { + async2 { use _ = Activity.start "ComputeAssemblyData" @@ -1876,8 +1872,6 @@ type internal TransparentCompiler Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |> (!!) |] - use! _holder = Cancellable.UseToken() - try let availableOnDiskModifiedTime = @@ -1923,9 +1917,7 @@ type internal TransparentCompiler let ComputeParseAndCheckProject (projectSnapshot: ProjectSnapshot) = caches.ParseAndCheckProject.Get( projectSnapshot.FullKey, - async { - use! _holder = Cancellable.UseToken() - + async2 { match! ComputeBootstrapInfo projectSnapshot with | None, creationDiags -> return FSharpCheckProjectResults(projectSnapshot.ProjectFileName, None, keepAssemblyContents, creationDiags, None) @@ -1997,9 +1989,7 @@ type internal TransparentCompiler ) let tryGetSink (fileName: string) (projectSnapshot: ProjectSnapshot) = - async { - use! _holder = Cancellable.UseToken() - + async2 { match! ComputeBootstrapInfo projectSnapshot with | None, _ -> return None | Some bootstrapInfo, _creationDiags -> @@ -2014,7 +2004,7 @@ type internal TransparentCompiler let ComputeSemanticClassification (fileName: string, projectSnapshot: ProjectSnapshot) = caches.SemanticClassification.Get( projectSnapshot.FileKey fileName, - async { + async2 { use _ = Activity.start "ComputeSemanticClassification" [| Activity.Tags.fileName, fileName |> Path.GetFileName |> (!!) |] @@ -2044,7 +2034,7 @@ type internal TransparentCompiler let ComputeItemKeyStore (fileName: string, projectSnapshot: ProjectSnapshot) = caches.ItemKeyStore.Get( projectSnapshot.FileKey fileName, - async { + async2 { use _ = Activity.start "ComputeItemKeyStore" [| Activity.Tags.fileName, fileName |> Path.GetFileName |> (!!) |] @@ -2079,7 +2069,7 @@ type internal TransparentCompiler ) member _.ParseFile(fileName, projectSnapshot: ProjectSnapshot, _userOpName) = - async { + async2 { //use _ = // Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |] @@ -2103,10 +2093,10 @@ type internal TransparentCompiler member _.ParseFileWithoutProject (fileName: string, sourceText: ISourceText, options: FSharpParsingOptions, cache: bool, flatErrors: bool, userOpName: string) - : Async = + : Async2 = let parseFileAsync = - async { - let! ct = Async.CancellationToken + async2 { + let! ct = Async2.CancellationToken let diagnostics, parsedInput, anyErrors = ParseAndCheckFile.parseFile (sourceText, fileName, options, userOpName, false, flatErrors, false, ct) @@ -2165,7 +2155,7 @@ type internal TransparentCompiler member _.FindReferencesInFile(fileName: string, projectSnapshot: ProjectSnapshot, symbol: FSharpSymbol, userOpName: string) = ignore userOpName - async { + async2 { match! ComputeItemKeyStore(fileName, projectSnapshot) with | None -> return Seq.empty | Some itemKeyStore -> return itemKeyStore.FindAll symbol.Item @@ -2194,8 +2184,8 @@ type internal TransparentCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : Async = - async { + ) : Async2 = + async2 { let! snapshot = FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText, documentSource) ignore parseResults @@ -2213,8 +2203,8 @@ type internal TransparentCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : Async = - async { + ) : Async2 = + async2 { let! snapshot = FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText, documentSource) ignore parseResults @@ -2258,8 +2248,8 @@ type internal TransparentCompiler member this.FindReferencesInFile (fileName: string, options: FSharpProjectOptions, symbol: FSharpSymbol, canInvalidateProject: bool, userOpName: string) - : Async> = - async { + : Async2> = + async2 { ignore canInvalidateProject let! snapshot = FSharpProjectSnapshot.FromOptions(options, documentSource) @@ -2273,8 +2263,8 @@ type internal TransparentCompiler member _.FrameworkImportsCache: FrameworkImportsCache = backgroundCompiler.FrameworkImportsCache - member this.GetAssemblyData(options: FSharpProjectOptions, fileName, userOpName: string) : Async = - async { + member this.GetAssemblyData(options: FSharpProjectOptions, fileName, userOpName: string) : Async2 = + async2 { let! snapshot = FSharpProjectSnapshot.FromOptions(options, documentSource) return! this.GetAssemblyData(snapshot.ProjectSnapshot, fileName, userOpName) @@ -2282,13 +2272,13 @@ type internal TransparentCompiler member this.GetAssemblyData (projectSnapshot: FSharpProjectSnapshot, fileName, userOpName: string) - : Async = + : Async2 = this.GetAssemblyData(projectSnapshot.ProjectSnapshot, fileName, userOpName) member this.GetBackgroundCheckResultsForFileInProject (fileName: string, options: FSharpProjectOptions, userOpName: string) - : Async = - async { + : Async2 = + async2 { let! snapshot = FSharpProjectSnapshot.FromOptions(options, documentSource) match! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, userOpName) with @@ -2298,8 +2288,8 @@ type internal TransparentCompiler member this.GetBackgroundParseResultsForFileInProject (fileName: string, options: FSharpProjectOptions, userOpName: string) - : Async = - async { + : Async2 = + async2 { let! snapshot = FSharpProjectSnapshot.FromOptions(options, documentSource) return! this.ParseFile(fileName, snapshot.ProjectSnapshot, userOpName) @@ -2307,8 +2297,8 @@ type internal TransparentCompiler member this.GetCachedCheckFileResult (builder: IncrementalBuilder, fileName: string, sourceText: ISourceText, options: FSharpProjectOptions) - : Async<(FSharpParseFileResults * FSharpCheckFileResults) option> = - async { + : Async2<(FSharpParseFileResults * FSharpCheckFileResults) option> = + async2 { ignore builder let! snapshot = FSharpProjectSnapshot.FromOptions(options, fileName, 1, sourceText, documentSource) @@ -2332,8 +2322,8 @@ type internal TransparentCompiler assumeDotNetFramework: bool option, optionsStamp: int64 option, userOpName: string - ) : Async = - async { + ) : Async2 = + async2 { let bc = this :> IBackgroundCompiler let! snapshot, diagnostics = @@ -2372,13 +2362,13 @@ type internal TransparentCompiler assumeDotNetFramework: bool option, optionsStamp: int64 option, userOpName: string - ) : Async = + ) : Async2 = use _ = Activity.start "BackgroundCompiler.GetProjectOptionsFromScript" [| Activity.Tags.fileName, fileName; Activity.Tags.userOpName, userOpName |] - async { + async2 { // Use the same default as the background compiler. let useFsiAuxLib = defaultArg useFsiAuxLib true let useSdkRefs = defaultArg useSdkRefs true @@ -2439,7 +2429,7 @@ type internal TransparentCompiler optionsStamp // Populate the cache. - let! _ = caches.ScriptClosure.Get(loadClosureKey, async { return loadClosure }) + let! _ = caches.ScriptClosure.Get(loadClosureKey, async2 { return loadClosure }) let sourceFiles = loadClosure.SourceFiles @@ -2486,15 +2476,15 @@ type internal TransparentCompiler } member this.GetSemanticClassificationForFile(fileName: string, snapshot: FSharpProjectSnapshot, userOpName: string) = - async { + async2 { ignore userOpName return! ComputeSemanticClassification(fileName, snapshot.ProjectSnapshot) } member this.GetSemanticClassificationForFile (fileName: string, options: FSharpProjectOptions, userOpName: string) - : Async = - async { + : Async2 = + async2 { ignore userOpName let! snapshot = FSharpProjectSnapshot.FromOptions(options, documentSource) @@ -2508,16 +2498,16 @@ type internal TransparentCompiler member this.InvalidateConfiguration(projectSnapshot: FSharpProjectSnapshot, _userOpName: string) : unit = this.Caches.Clear(Set.singleton projectSnapshot.Identifier) - member this.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string) : Async = + member this.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string) : Async2 = backgroundCompiler.NotifyFileChanged(fileName, options, userOpName) - member this.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName: string) : Async = + member this.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName: string) : Async2 = backgroundCompiler.NotifyProjectCleaned(options, userOpName) member this.ParseAndCheckFileInProject (fileName: string, fileVersion: int, sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string) - : Async = - async { + : Async2 = + async2 { let! snapshot = FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText, documentSource) return! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, userOpName) @@ -2526,8 +2516,8 @@ type internal TransparentCompiler member this.ParseAndCheckFileInProject(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) = this.ParseAndCheckFileInProject(fileName, projectSnapshot.ProjectSnapshot, userOpName) - member this.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : Async = - async { + member this.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : Async2 = + async2 { ignore userOpName let! snapshot = FSharpProjectSnapshot.FromOptions(options, documentSource) @@ -2535,8 +2525,8 @@ type internal TransparentCompiler return! ComputeParseAndCheckProject snapshot.ProjectSnapshot } - member this.ParseAndCheckProject(projectSnapshot: FSharpProjectSnapshot, userOpName: string) : Async = - async { + member this.ParseAndCheckProject(projectSnapshot: FSharpProjectSnapshot, userOpName: string) : Async2 = + async2 { ignore userOpName return! ComputeParseAndCheckProject projectSnapshot.ProjectSnapshot } @@ -2546,7 +2536,7 @@ type internal TransparentCompiler member this.ParseFile (fileName: string, sourceText: ISourceText, options: FSharpParsingOptions, cache: bool, flatErrors: bool, userOpName: string) - : Async = + : Async2 = this.ParseFileWithoutProject(fileName, sourceText, options, cache, flatErrors, userOpName) member this.TryGetRecentCheckResultsForFile diff --git a/src/Compiler/Service/TransparentCompiler.fsi b/src/Compiler/Service/TransparentCompiler.fsi index 8703df0fe7f..63c167a2499 100644 --- a/src/Compiler/Service/TransparentCompiler.fsi +++ b/src/Compiler/Service/TransparentCompiler.fsi @@ -22,6 +22,7 @@ open FSharp.Compiler.TypedTree open FSharp.Compiler.CheckDeclarations open FSharp.Compiler.EditorServices open FSharp.Compiler.CodeAnalysis.ProjectSnapshot +open Internal.Utilities.Library /// Accumulated results of type checking. The minimum amount of state in order to continue type-checking following files. [] @@ -204,19 +205,19 @@ type internal TransparentCompiler = member FindReferencesInFile: fileName: string * projectSnapshot: ProjectSnapshot.ProjectSnapshot * symbol: FSharpSymbol * userOpName: string -> - Async + Async2 member GetAssemblyData: projectSnapshot: ProjectSnapshot.ProjectSnapshot * fileName: string * _userOpName: string -> - Async + Async2 member ParseAndCheckFileInProject: fileName: string * projectSnapshot: ProjectSnapshot.ProjectSnapshot * userOpName: string -> - Async + Async2 member ParseFile: fileName: string * projectSnapshot: ProjectSnapshot.ProjectSnapshot * _userOpName: 'a -> - Async + Async2 member SetCacheSize: cacheSize: CacheSizes -> unit member SetCacheSizeFactor: sizeFactor: int -> unit diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 7a013e1fd78..b6b56874257 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -273,11 +273,11 @@ type FSharpChecker let hash = sourceText.GetHashCode() |> int64 - async { + async2 { match braceMatchCache.TryGet(AnyCallerThread, (fileName, hash, options)) with | Some res -> return res | None -> - let! ct = Async.CancellationToken + let! ct = Async2.CancellationToken let res = ParseAndCheckFile.matchBraces (sourceText, fileName, options, userOpName, suggestNamesForErrors, ct) @@ -285,6 +285,7 @@ type FSharpChecker braceMatchCache.Set(AnyCallerThread, (fileName, hash, options), res) return res } + |> Async2.toAsync member ic.MatchBraces(fileName, source: string, options: FSharpProjectOptions, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" @@ -299,12 +300,15 @@ type FSharpChecker member _.ParseFile(fileName, sourceText, options, ?cache, ?userOpName: string) = let cache = defaultArg cache true let userOpName = defaultArg userOpName "Unknown" + backgroundCompiler.ParseFile(fileName, sourceText, options, cache, false, userOpName) + |> Async2.toAsync member _.ParseFile(fileName, projectSnapshot, ?userOpName) = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.ParseFile(fileName, projectSnapshot, userOpName) + |> Async2.toAsync member ic.ParseFileInProject(fileName, source: string, options, ?cache: bool, ?userOpName: string) = let parsingOptions, _ = ic.GetParsingOptionsFromProjectOptions(options) @@ -314,11 +318,13 @@ type FSharpChecker let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName) + |> Async2.toAsync member _.GetBackgroundCheckResultsForFileInProject(fileName, options, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName) + |> Async2.toAsync /// Try to get recent approximate type check results for a file. member _.TryGetRecentCheckResultsForFile(fileName: string, options: FSharpProjectOptions, ?sourceText, ?userOpName: string) = @@ -379,12 +385,13 @@ type FSharpChecker /// This function is called when a project has been cleaned, and thus type providers should be refreshed. member _.NotifyProjectCleaned(options: FSharpProjectOptions, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" - backgroundCompiler.NotifyProjectCleaned(options, userOpName) + backgroundCompiler.NotifyProjectCleaned(options, userOpName) |> Async2.toAsync member _.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.NotifyFileChanged(fileName, options, userOpName) + |> Async2.toAsync /// Typecheck a source code file, returning a handle to the results of the /// parse including the reconstructed types in the file. @@ -401,6 +408,7 @@ type FSharpChecker options, userOpName ) + |> Async2.toAsync /// Typecheck a source code file, returning a handle to the results of the /// parse including the reconstructed types in the file. @@ -416,6 +424,7 @@ type FSharpChecker let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.CheckFileInProject(parseResults, fileName, fileVersion, sourceText, options, userOpName) + |> Async2.toAsync /// Typecheck a source code file, returning a handle to the results of the /// parse including the reconstructed types in the file. @@ -425,21 +434,24 @@ type FSharpChecker let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName) + |> Async2.toAsync member _.ParseAndCheckFileInProject(fileName: string, projectSnapshot: FSharpProjectSnapshot, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.ParseAndCheckFileInProject(fileName, projectSnapshot, userOpName) + |> Async2.toAsync member _.ParseAndCheckProject(options: FSharpProjectOptions, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" - backgroundCompiler.ParseAndCheckProject(options, userOpName) + backgroundCompiler.ParseAndCheckProject(options, userOpName) |> Async2.toAsync member _.ParseAndCheckProject(projectSnapshot: FSharpProjectSnapshot, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.ParseAndCheckProject(projectSnapshot, userOpName) + |> Async2.toAsync member _.FindBackgroundReferencesInFile (fileName: string, options: FSharpProjectOptions, symbol: FSharpSymbol, ?canInvalidateProject: bool, ?fastCheck: bool, ?userOpName: string) @@ -447,7 +459,7 @@ type FSharpChecker let canInvalidateProject = defaultArg canInvalidateProject true let userOpName = defaultArg userOpName "Unknown" - async { + async2 { if fastCheck <> Some true || not captureIdentifiersWhenParsing then return! backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName) else @@ -461,11 +473,12 @@ type FSharpChecker else return Seq.empty } + |> Async2.toAsync member _.FindBackgroundReferencesInFile(fileName: string, projectSnapshot: FSharpProjectSnapshot, symbol: FSharpSymbol, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" - async { + async2 { let! parseResults = backgroundCompiler.ParseFile(fileName, projectSnapshot, userOpName) if @@ -476,16 +489,21 @@ type FSharpChecker else return Seq.empty } + |> Async2.toAsync - member _.GetBackgroundSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, ?userOpName) = + member _.GetBackgroundSemanticClassificationForFile + (fileName: string, options: FSharpProjectOptions, ?userOpName) + : Async = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.GetSemanticClassificationForFile(fileName, options, userOpName) + |> Async2.toAsync member _.GetBackgroundSemanticClassificationForFile(fileName: string, snapshot: FSharpProjectSnapshot, ?userOpName) = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.GetSemanticClassificationForFile(fileName, snapshot, userOpName) + |> Async2.toAsync /// For a given script file, get the ProjectOptions implied by the #load closure member _.GetProjectOptionsFromScript @@ -519,6 +537,7 @@ type FSharpChecker optionsStamp, userOpName ) + |> Async2.toAsync /// For a given script file, get the ProjectSnapshot implied by the #load closure member _.GetProjectSnapshotFromScript @@ -555,6 +574,7 @@ type FSharpChecker optionsStamp, userOpName ) + |> Async2.toAsync member _.GetProjectOptionsFromCommandLineArgs(projectFileName, argv, ?loadedTimeStamp, ?isInteractive, ?isEditing) = let isEditing = defaultArg isEditing false diff --git a/src/Compiler/Utilities/Async2.fs b/src/Compiler/Utilities/Async2.fs new file mode 100644 index 00000000000..109960f8be5 --- /dev/null +++ b/src/Compiler/Utilities/Async2.fs @@ -0,0 +1,629 @@ +namespace Internal.Utilities.Library + +open System +open System.Threading +open System.Threading.Tasks +open System.Runtime.CompilerServices +open System.Runtime.ExceptionServices +open FSharp.Core.CompilerServices.StateMachineHelpers +open Microsoft.FSharp.Core.CompilerServices + +#nowarn 3513 + +type IAsync2Invocation<'t> = + abstract Task: Task<'t> + abstract GetAwaiter: unit -> TaskAwaiter<'t> + +and Async2<'t> = + abstract StartImmediate: CancellationToken -> IAsync2Invocation<'t> + abstract StartBound: CancellationToken -> TaskAwaiter<'t> + abstract TailCall: CancellationToken * TaskCompletionSource<'t> voption -> unit + abstract GetAwaiter: unit -> TaskAwaiter<'t> + +module Async2Implementation = + + /// A structure that looks like an Awaiter + type Awaiter<'Awaiter, 'TResult + when 'Awaiter :> ICriticalNotifyCompletion + and 'Awaiter: (member get_IsCompleted: unit -> bool) + and 'Awaiter: (member GetResult: unit -> 'TResult)> = 'Awaiter + + type Awaitable<'Awaitable, 'Awaiter, 'TResult when 'Awaitable: (member GetAwaiter: unit -> Awaiter<'Awaiter, 'TResult>)> = 'Awaitable + + module Awaiter = + let inline isCompleted (awaiter: Awaiter<_, _>) = awaiter.get_IsCompleted () + + let inline getResult (awaiter: Awaiter<_, _>) = awaiter.GetResult() + + let inline onCompleted (awaiter: Awaiter<_, _>) continuation = awaiter.OnCompleted continuation + + let inline unsafeOnCompleted (awaiter: Awaiter<_, _>) continuation = awaiter.UnsafeOnCompleted continuation + + module Awaitable = + let inline getAwaiter (awaitable: Awaitable<_, _, _>) = awaitable.GetAwaiter() + + type DynamicState = + | Running + | SetResult + | SetException of ExceptionDispatchInfo + | Awaiting of ICriticalNotifyCompletion + | Bounce of DynamicState + | Immediate of DynamicState + + module BindContext = + let bindCount = new ThreadLocal() + + [] + let bindLimit = 100 + + let IncrementBindCount () = + bindCount.Value <- bindCount.Value + 1 + bindCount.Value >= bindLimit + + let Reset () = bindCount.Value <- 0 + + type Trampoline private () = + + let ownerThreadId = Thread.CurrentThread.ManagedThreadId + + static let holder = new ThreadLocal<_>(fun () -> Trampoline()) + + let mutable pending: Action voption = ValueNone + let mutable running = false + + let start (action: Action) = + try + BindContext.Reset() + running <- true + action.Invoke() + + while pending.IsSome do + let next = pending.Value + pending <- ValueNone + next.Invoke() + finally + running <- false + + let set action = + assert (Thread.CurrentThread.ManagedThreadId = ownerThreadId) // "Trampoline used from wrong thread" + assert pending.IsNone // "Trampoline set while already pending" + + BindContext.Reset() + + if running then + pending <- ValueSome action + else + start action + + interface ICriticalNotifyCompletion with + member _.OnCompleted continuation = set continuation + member _.UnsafeOnCompleted continuation = set continuation + + member this.Ref: ICriticalNotifyCompletion ref = ref this + + static member Current = holder.Value + + module ExceptionCache = + let store = ConditionalWeakTable() + + let inline CaptureOrRetrieve (exn: exn) = + match store.TryGetValue exn with + | true, edi when edi.SourceException = exn -> edi + | _ -> + let edi = ExceptionDispatchInfo.Capture exn + + try + store.Add(exn, edi) + with _ -> + () + + edi + + let inline Throw (exn: exn) = + let edi = CaptureOrRetrieve exn + edi.Throw() + Unchecked.defaultof<_> + + let inline GetResultOrThrow awaiter = + try + Awaiter.getResult awaiter + with exn -> + Throw exn + + [] + type Async2Data<'t> = + [] + val mutable Result: 't + + [] + val mutable MethodBuilder: AsyncTaskMethodBuilder<'t> + + [] + val mutable TailCallSource: TaskCompletionSource<'t> voption + + [] + val mutable CancellationToken: CancellationToken + + [] + val mutable IsBound: bool + + type Async2StateMachine<'TOverall> = ResumableStateMachine> + type IAsync2StateMachine<'TOverall> = IResumableStateMachine> + type Async2ResumptionFunc<'TOverall> = ResumptionFunc> + type Async2ResumptionDynamicInfo<'TOverall> = ResumptionDynamicInfo> + + type Async2Code<'TOverall, 'T> = ResumableCode, 'T> + + [] + type Async2<'t, 'm when 'm :> IAsyncStateMachine and 'm :> IAsync2StateMachine<'t>> = + [] + val mutable StateMachine: 'm + + member ts.Start(ct, tailCallSource, isBound) = + let mutable copy = ts + let mutable data = Async2Data() + data.CancellationToken <- ct + data.TailCallSource <- tailCallSource + data.IsBound <- isBound + data.MethodBuilder <- AsyncTaskMethodBuilder<'t>.Create() + copy.StateMachine.Data <- data + copy.StateMachine.Data.MethodBuilder.Start(©.StateMachine) + copy :> IAsync2Invocation<'t> + + interface IAsync2Invocation<'t> with + member ts.Task = ts.StateMachine.Data.MethodBuilder.Task + + member ts.GetAwaiter() = + ts.StateMachine.Data.MethodBuilder.Task.GetAwaiter() + + interface Async2<'t> with + member ts.StartImmediate ct = ts.Start(ct, ValueNone, false) + + member ts.StartBound ct = + ts.Start(ct, ValueNone, true).GetAwaiter() + + member ts.TailCall(ct, tc) = ts.Start(ct, tc, true) |> ignore + + member ts.GetAwaiter() = + ts.Start(CancellationToken.None, ValueNone, true).GetAwaiter() + + type Async2Dynamic<'t, 'm when 'm :> IAsyncStateMachine and 'm :> IAsync2StateMachine<'t>>(getCopy: bool -> 'm) = + member ts.GetCopy isBound = + Async2(StateMachine = getCopy isBound) :> Async2<_> + + interface Async2<'t> with + member ts.StartImmediate ct = ts.GetCopy(false).StartImmediate(ct) + + member ts.StartBound ct = ts.GetCopy(true).StartBound(ct) + + member ts.TailCall(ct, tc) = + ts.GetCopy(true).TailCall(ct, tc) |> ignore + + member ts.GetAwaiter() = ts.GetCopy(true).GetAwaiter() + + [] + module Async2Code = + let inline filterCancellation ([] catch: exn -> Async2Code<_, _>) (exn: exn) = + Async2Code(fun sm -> + match exn with + | :? OperationCanceledException as oce when + sm.Data.CancellationToken.IsCancellationRequested + || oce.CancellationToken = sm.Data.CancellationToken + -> + raise exn + | _ -> (catch exn).Invoke(&sm)) + + let inline throwIfCancellationRequested (code: Async2Code<_, _>) = + Async2Code(fun sm -> + sm.Data.CancellationToken.ThrowIfCancellationRequested() + code.Invoke(&sm)) + + let inline yieldOnBindLimit () = + Async2Code(fun sm -> + if BindContext.IncrementBindCount() then + let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) + + if not __stack_yield_fin then + sm.Data.MethodBuilder.AwaitOnCompleted(Trampoline.Current.Ref, &sm) + + __stack_yield_fin + else + true) + + let inline bindDynamic (sm: byref>, awaiter, [] continuation: _ -> Async2Code<_, _>) = + if Awaiter.isCompleted awaiter then + (Awaiter.getResult awaiter |> continuation).Invoke(&sm) + else + let resumptionFunc = + Async2ResumptionFunc(fun sm -> + let result = ExceptionCache.GetResultOrThrow awaiter + (continuation result).Invoke(&sm)) + + sm.ResumptionDynamicInfo.ResumptionFunc <- resumptionFunc + sm.ResumptionDynamicInfo.ResumptionData <- Awaiting awaiter + false + + let inline bindAwaiter (awaiter, [] continuation: 'U -> Async2Code<'Data, 'T>) : Async2Code<'Data, 'T> = + Async2Code(fun sm -> + if __useResumableCode then + if Awaiter.isCompleted awaiter then + continuation(ExceptionCache.GetResultOrThrow awaiter).Invoke(&sm) + else + let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) + + if __stack_yield_fin then + continuation(ExceptionCache.GetResultOrThrow awaiter).Invoke(&sm) + else + let mutable __stack_awaiter = awaiter + sm.Data.MethodBuilder.AwaitUnsafeOnCompleted(&__stack_awaiter, &sm) + false + else + bindDynamic (&sm, awaiter, continuation)) + + let inline bindCancellable + ([] cancellable, [] continuation: 'U -> Async2Code<'Data, 'T>) + : Async2Code<'Data, 'T> = + Async2Code<'Data, 'T>(fun sm -> bindAwaiter(cancellable sm.Data.CancellationToken, continuation).Invoke(&sm)) + + type Async2Builder() = + + member inline _.Delay(generator: unit -> Async2Code<'TOverall, 'T>) : Async2Code<'TOverall, 'T> = + ResumableCode.Delay(fun () -> generator () |> throwIfCancellationRequested) + + [] + member inline _.Zero() : Async2Code<'TOverall, unit> = ResumableCode.Zero() + + member inline _.Return(value: 'T) = + Async2Code(fun sm -> + sm.Data.Result <- value + true) + + member inline _.Combine(code1: Async2Code<'TOverall, unit>, code2: Async2Code<'TOverall, 'T>) : Async2Code<'TOverall, 'T> = + ResumableCode.Combine(code1, code2) + + member inline _.While([] condition: unit -> bool, body: Async2Code<'TOverall, unit>) : Async2Code<'TOverall, unit> = + ResumableCode.While(condition, throwIfCancellationRequested body) + + member inline _.TryWith + (body: Async2Code<'TOverall, 'T>, [] catch: exn -> Async2Code<'TOverall, 'T>) + : Async2Code<'TOverall, 'T> = + ResumableCode.TryWith(body, filterCancellation catch) + + member inline _.TryFinally + (body: Async2Code<'TOverall, 'T>, [] compensation: unit -> unit) + : Async2Code<'TOverall, 'T> = + ResumableCode.TryFinally( + body, + ResumableCode<_, _>(fun _sm -> + compensation () + true) + ) + + member inline _.Using<'Resource, 'TOverall, 'T when 'Resource :> IDisposable | null> + (resource: 'Resource, body: 'Resource -> Async2Code<'TOverall, 'T>) + : Async2Code<'TOverall, 'T> = + ResumableCode.Using(resource, body) + + member inline _.For(sequence: seq<'T>, [] body: 'T -> Async2Code<'TOverall, unit>) : Async2Code<'TOverall, unit> = + ResumableCode.For(sequence, fun x -> body x |> throwIfCancellationRequested) + + static member inline RunDynamic(code: Async2Code<'T, 'T>) : Async2<'T> = + let initialResumptionFunc = Async2ResumptionFunc<'T>(fun sm -> code.Invoke &sm) + + let maybeBounce state = + if BindContext.IncrementBindCount() then + Bounce state + else + Immediate state + + let resumptionInfo isBound = + let initialState = if isBound then maybeBounce Running else Immediate Running + + { new Async2ResumptionDynamicInfo<'T>(initialResumptionFunc, ResumptionData = initialState) with + member info.MoveNext(sm) = + + let getCurrent () = + nonNull info.ResumptionData :?> DynamicState + + let setState state = info.ResumptionData <- state + + match getCurrent () with + | Immediate state -> + setState state + info.MoveNext &sm + | Running -> + let mutable keepGoing = true + + try + if info.ResumptionFunc.Invoke(&sm) then + setState (maybeBounce SetResult) + else + keepGoing <- getCurrent () |> _.IsAwaiting + with exn -> + setState (maybeBounce <| SetException(ExceptionCache.CaptureOrRetrieve exn)) + + if keepGoing then + info.MoveNext &sm + | Awaiting awaiter -> + setState Running + let mutable awaiter = awaiter + sm.Data.MethodBuilder.AwaitUnsafeOnCompleted(&awaiter, &sm) + | Bounce next -> + setState next + sm.Data.MethodBuilder.AwaitOnCompleted(Trampoline.Current.Ref, &sm) + | SetResult -> + match sm.Data.TailCallSource with + | ValueSome tcs -> tcs.SetResult sm.Data.Result + | _ -> sm.Data.MethodBuilder.SetResult sm.Data.Result + | SetException edi -> + match sm.Data.TailCallSource with + | ValueSome tcs -> tcs.TrySetException(edi.SourceException) |> ignore + | _ -> sm.Data.MethodBuilder.SetException(edi.SourceException) + + member _.SetStateMachine(sm, state) = + sm.Data.MethodBuilder.SetStateMachine(state) + } + + Async2Dynamic<_, _>(fun isBound -> Async2StateMachine(ResumptionDynamicInfo = resumptionInfo isBound)) + + member inline _.Run(code: Async2Code<'T, 'T>) : Async2<'T> = + if __useResumableCode then + __stateMachine, _> + + (MoveNextMethodImpl<_>(fun sm -> + __resumeAt sm.ResumptionPoint + + let mutable error = ValueNone + + let __stack_go1 = not sm.Data.IsBound || yieldOnBindLimit().Invoke(&sm) + + if __stack_go1 then + try + let __stack_code_fin = code.Invoke(&sm) + + if __stack_code_fin then + let __stack_go2 = yieldOnBindLimit().Invoke(&sm) + + if __stack_go2 then + match sm.Data.TailCallSource with + | ValueSome tcs -> tcs.SetResult sm.Data.Result + | _ -> sm.Data.MethodBuilder.SetResult(sm.Data.Result) + with exn -> + error <- ValueSome(ExceptionCache.CaptureOrRetrieve exn) + + if error.IsSome then + let __stack_go2 = yieldOnBindLimit().Invoke(&sm) + + if __stack_go2 then + match sm.Data.TailCallSource with + | ValueSome tcs -> tcs.SetException(error.Value.SourceException) + | _ -> sm.Data.MethodBuilder.SetException(error.Value.SourceException))) + + (SetStateMachineMethodImpl<_>(fun sm state -> sm.Data.MethodBuilder.SetStateMachine state)) + + (AfterCode<_, _>(fun sm -> Async2<_, _>(StateMachine = sm) :> Async2<'T>)) + else + Async2Builder.RunDynamic(code) + +open Async2Implementation + +[] +module LowPriority = + type Async2Builder with + [] + member inline this.Bind(awaitable, [] continuation) = + bindAwaiter (Awaitable.getAwaiter awaitable, continuation) + + [] + member inline this.ReturnFrom(awaitable) = this.Bind(awaitable, this.Return) + + [] + member inline this.ReturnFromFinal(awaitable) = this.ReturnFrom(awaitable) + +[] +module MediumPriority = + type Async2Builder with + member inline this.Bind(expr: Async<_>, [] continuation) = + bindCancellable ((fun ct -> Async.StartAsTask(expr, cancellationToken = ct).GetAwaiter()), continuation) + + member inline this.Bind(task: Task, [] continuation) = + bindAwaiter (task.ConfigureAwait(false).GetAwaiter(), continuation) + + member inline this.Bind(task: Task<_>, [] continuation) = + bindAwaiter (task.ConfigureAwait(false).GetAwaiter(), continuation) + + member inline this.ReturnFrom(task: Task) = this.Bind(task, this.Return) + member inline this.ReturnFrom(task: Task<_>) = this.Bind(task, this.Return) + member inline this.ReturnFrom(expr: Async<_>) = this.Bind(expr, this.Return) + member inline this.ReturnFromFinal(task: Task) = this.ReturnFrom(task) + member inline this.ReturnFromFinal(task: Task<_>) = this.ReturnFrom(task) + member inline this.ReturnFromFinal(expr: Async<_>) = this.ReturnFrom(expr) + +[] +module HighPriority = + + type Async2Builder with + member inline this.Bind(code: Async2<'U>, [] continuation) : Async2Code<'Data, 'T> = + bindCancellable (code.StartBound, continuation) + + member inline this.ReturnFrom(code: Async2<'T>) : Async2Code<'T, 'T> = this.Bind(code, this.Return) + + member inline this.ReturnFromFinal(code: Async2<'T>) = + Async2Code(fun sm -> + match sm.Data.TailCallSource with + | ValueNone -> + // This is the start of a tail call chain. we need to return here when the entire chain is done. + let __stack_tcs = TaskCompletionSource<_>() + code.TailCall(sm.Data.CancellationToken, ValueSome __stack_tcs) + this.Bind(__stack_tcs.Task, this.Return).Invoke(&sm) + | ValueSome tcs -> + // We are already in a tail call chain. + let __stack_ct = sm.Data.CancellationToken + code.TailCall(__stack_ct, ValueSome tcs) + false // Return false to abandon this state machine and continue on the next one. + ) + +[] +module Async2AutoOpens = + + let async2 = Async2Builder() + +module Async2 = + + let CheckAndThrowToken = AsyncLocal() + + let startInThreadPool ct (code: Async2<_>) = + Task.Run<'t>(fun () -> + CheckAndThrowToken.Value <- ct + code.StartImmediate ct |> _.Task) + + let inline start ct (code: Async2<_>) = + + let immediate = + isNull SynchronizationContext.Current + && TaskScheduler.Current = TaskScheduler.Default + + if immediate then + let oldCt = CheckAndThrowToken.Value + + try + CheckAndThrowToken.Value <- ct + code.StartImmediate ct |> _.Task + + finally + CheckAndThrowToken.Value <- oldCt + else + startInThreadPool ct code + + let run ct (code: Async2<'t>) = + startInThreadPool ct code |> _.GetAwaiter().GetResult() + + let runWithoutCancellation code = run CancellationToken.None code + + //let queueTask ct code = + // Task.Run<'t>(fun () -> start ct code) + + let startAsTaskWithoutCancellation code = + startInThreadPool CancellationToken.None code + + let toAsync (code: Async2<'t>) = + async { + let! ct = Async.CancellationToken + let task = start ct code + return! Async.AwaitTask task + } + + let fromValue (value: 't) : Async2<'t> = async2 { return value } + + let CancellationToken = + async2.Run( + Async2Code(fun sm -> + sm.Data.Result <- sm.Data.CancellationToken + true) + ) + +type Async2 = + static member Ignore(computation: Async2<_>) : Async2 = + async2 { + let! _ = computation + return () + } + + static member Start(computation: Async2<_>, ?cancellationToken: CancellationToken) : unit = + let ct = defaultArg cancellationToken CancellationToken.None + Async2.startInThreadPool ct computation |> ignore + + static member StartAsTask(computation: Async2<_>, ?cancellationToken: CancellationToken) : Task<_> = + let ct = defaultArg cancellationToken CancellationToken.None + Async2.start ct computation + + static member RunImmediate(computation: Async2<'T>, ?cancellationToken: CancellationToken) : 'T = + let ct = defaultArg cancellationToken CancellationToken.None + Async2.start ct computation |> _.GetAwaiter().GetResult() + + static member Parallel(computations: Async2<_> seq) = + async2 { + let! ct = Async2.CancellationToken + use lcts = CancellationTokenSource.CreateLinkedTokenSource ct + + let tasks = + seq { + for c in computations do + async2 { + try + return! c + with exn -> + lcts.Cancel() + return raise exn + } + |> Async2.startInThreadPool lcts.Token + } + + return! Task.WhenAll tasks + } + + static member Sequential(computations: Async2<_> seq) = + async2 { + let results = ResizeArray() + + for c in computations do + let! r = c + results.Add r + + return results.ToArray() + } + + static member Catch(computation: Async2<'T>) : Async2> = + async2 { + try + let! res = computation + return Choice1Of2 res + with exn -> + return Choice2Of2 exn + } + + static member TryCancelled(computation: Async2<'T>, compensation) = + async2 { + let! ct = Async2.CancellationToken + let invocation = computation.StartImmediate ct + + try + return! invocation + finally + if ct.IsCancellationRequested && invocation.Task.IsCanceled then + compensation () + } + + static member StartChild(computation: Async2<'T>) : Async2> = + async2 { + let! ct = Async2.CancellationToken + return async2 { return! computation |> Async2.startInThreadPool ct } + } + + static member StartChildAsTask(computation: Async2<'T>) : Async2> = + async2 { + let! ct = Async2.CancellationToken + let task = computation |> Async2.startInThreadPool ct + return task + } + + static member AwaitWaitHandle(waitHandle: WaitHandle) : Async2 = + async2 { + let! ct = Async2.CancellationToken + + let tcs = + TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously) + + use _ = ct.Register(fun () -> tcs.TrySetCanceled() |> ignore) + + let callback = + WaitOrTimerCallback(fun _ timedOut -> tcs.TrySetResult(not timedOut) |> ignore) + + let handle = + ThreadPool.RegisterWaitForSingleObject(waitHandle, callback, null, -1, true) + + try + return! tcs.Task + finally + handle.Unregister(waitHandle) |> ignore + } diff --git a/src/Compiler/Utilities/Cancellable.fs b/src/Compiler/Utilities/Cancellable.fs index bae9c6f8299..fa70be53ebd 100644 --- a/src/Compiler/Utilities/Cancellable.fs +++ b/src/Compiler/Utilities/Cancellable.fs @@ -1,226 +1,10 @@ namespace FSharp.Compiler -open System -open System.Threading - -// This code provides two methods for handling cancellation in synchronous code: -// 1. Explicitly, by calling Cancellable.CheckAndThrow(). -// 2. Implicitly, by wrapping the code in a cancellable computation. -// The cancellable computation propagates the CancellationToken and checks for cancellation implicitly. -// When it is impractical to use the cancellable computation, such as in deeply nested functions, Cancellable.CheckAndThrow() can be used. -// It checks a CancellationToken local to the current async execution context, held in AsyncLocal. -// Before calling Cancellable.CheckAndThrow(), this token must be set. -// The token is guaranteed to be set during execution of cancellable computation. -// Otherwise, it can be passed explicitly from the ambient async computation using Cancellable.UseToken(). +open Internal.Utilities.Library [] type Cancellable = - static let tokenHolder = AsyncLocal() - - static let guard = - String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("DISABLE_CHECKANDTHROW_ASSERT")) - - static let ensureToken msg = - tokenHolder.Value - |> ValueOption.defaultWith (fun () -> if guard then failwith msg else CancellationToken.None) - - static member HasCancellationToken = tokenHolder.Value.IsSome - - static member Token = ensureToken "Token not available outside of Cancellable computation." - - static member UseToken() = - async { - let! ct = Async.CancellationToken - return Cancellable.UsingToken ct - } - - static member UsingToken(ct) = - let oldCt = tokenHolder.Value - tokenHolder.Value <- ValueSome ct - - { new IDisposable with - member _.Dispose() = tokenHolder.Value <- oldCt - } - static member CheckAndThrow() = - let token = ensureToken "CheckAndThrow invoked outside of Cancellable computation." - token.ThrowIfCancellationRequested() - - static member TryCheckAndThrow() = - match tokenHolder.Value with - | ValueNone -> () - | ValueSome token -> token.ThrowIfCancellationRequested() - -namespace Internal.Utilities.Library - -open System -open System.Threading -open FSharp.Compiler - -open FSharp.Core.CompilerServices.StateMachineHelpers - -[] -type ValueOrCancelled<'TResult> = - | Value of result: 'TResult - | Cancelled of ``exception``: OperationCanceledException - -[] -type Cancellable<'T> = Cancellable of (CancellationToken -> ValueOrCancelled<'T>) - -module Cancellable = - - let inline run (ct: CancellationToken) (Cancellable oper) = - if ct.IsCancellationRequested then - ValueOrCancelled.Cancelled(OperationCanceledException ct) - else - try - oper ct - with - | :? OperationCanceledException as e when ct.IsCancellationRequested -> ValueOrCancelled.Cancelled e - | :? OperationCanceledException as e -> InvalidOperationException("Wrong cancellation token", e) |> raise - - let fold f acc seq = - Cancellable(fun ct -> - let mutable acc = ValueOrCancelled.Value acc - - for x in seq do - match acc with - | ValueOrCancelled.Value accv -> acc <- run ct (f accv x) - | ValueOrCancelled.Cancelled _ -> () - - acc) - - let runWithoutCancellation comp = - use _ = Cancellable.UsingToken CancellationToken.None - let res = run CancellationToken.None comp - - match res with - | ValueOrCancelled.Cancelled _ -> failwith "unexpected cancellation" - | ValueOrCancelled.Value r -> r - - let toAsync c = - async { - use! _holder = Cancellable.UseToken() - - let! ct = Async.CancellationToken - - return! - Async.FromContinuations(fun (cont, _econt, ccont) -> - match run ct c with - | ValueOrCancelled.Value v -> cont v - | ValueOrCancelled.Cancelled ce -> ccont ce) - } - - let token () = Cancellable(ValueOrCancelled.Value) - -type CancellableBuilder() = - - member inline _.Delay([] f) = - Cancellable(fun ct -> - let (Cancellable g) = f () - g ct) - - member inline _.Bind(comp, [] k) = - Cancellable(fun ct -> - - __debugPoint "" - - match Cancellable.run ct comp with - | ValueOrCancelled.Value v1 -> Cancellable.run ct (k v1) - | ValueOrCancelled.Cancelled err1 -> ValueOrCancelled.Cancelled err1) - - member inline _.BindReturn(comp, [] k) = - Cancellable(fun ct -> - - __debugPoint "" - - match Cancellable.run ct comp with - | ValueOrCancelled.Value v1 -> ValueOrCancelled.Value(k v1) - | ValueOrCancelled.Cancelled err1 -> ValueOrCancelled.Cancelled err1) - - member inline _.Combine(comp1, comp2) = - Cancellable(fun ct -> - - __debugPoint "" - - match Cancellable.run ct comp1 with - | ValueOrCancelled.Value() -> Cancellable.run ct comp2 - | ValueOrCancelled.Cancelled err1 -> ValueOrCancelled.Cancelled err1) - - member inline _.TryWith(comp, [] handler) = - Cancellable(fun ct -> - - __debugPoint "" - - let compRes = - try - match Cancellable.run ct comp with - | ValueOrCancelled.Value res -> ValueOrCancelled.Value(Choice1Of2 res) - | ValueOrCancelled.Cancelled exn -> ValueOrCancelled.Cancelled exn - with err -> - ValueOrCancelled.Value(Choice2Of2 err) - - match compRes with - | ValueOrCancelled.Value res -> - match res with - | Choice1Of2 r -> ValueOrCancelled.Value r - | Choice2Of2 err -> Cancellable.run ct (handler err) - | ValueOrCancelled.Cancelled err1 -> ValueOrCancelled.Cancelled err1) - - member inline _.Using(resource: _ MaybeNull, [] comp) = - Cancellable(fun ct -> - - __debugPoint "" - - let body = comp resource - - let compRes = - try - match Cancellable.run ct body with - | ValueOrCancelled.Value res -> ValueOrCancelled.Value(Choice1Of2 res) - | ValueOrCancelled.Cancelled exn -> ValueOrCancelled.Cancelled exn - with err -> - ValueOrCancelled.Value(Choice2Of2 err) - - match compRes with - | ValueOrCancelled.Value res -> - Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions.Dispose resource - - match res with - | Choice1Of2 r -> ValueOrCancelled.Value r - | Choice2Of2 err -> raise err - | ValueOrCancelled.Cancelled err1 -> ValueOrCancelled.Cancelled err1) - - member inline _.TryFinally(comp, [] compensation) = - Cancellable(fun ct -> - - __debugPoint "" - - let compRes = - try - match Cancellable.run ct comp with - | ValueOrCancelled.Value res -> ValueOrCancelled.Value(Choice1Of2 res) - | ValueOrCancelled.Cancelled exn -> ValueOrCancelled.Cancelled exn - with err -> - ValueOrCancelled.Value(Choice2Of2 err) - - match compRes with - | ValueOrCancelled.Value res -> - compensation () - - match res with - | Choice1Of2 r -> ValueOrCancelled.Value r - | Choice2Of2 err -> raise err - | ValueOrCancelled.Cancelled err1 -> ValueOrCancelled.Cancelled err1) - - member inline _.Return v = - Cancellable(fun _ -> ValueOrCancelled.Value v) - - member inline _.ReturnFrom(v: Cancellable<'T>) = v - - member inline _.Zero() = - Cancellable(fun _ -> ValueOrCancelled.Value()) - -[] -module CancellableAutoOpens = - let cancellable = CancellableBuilder() + // If we're not inside an async computation, the ambient cancellation token will be CancellationToken.None and nothing will happen + // otherwise, if we are inside an async computation, this will throw. + Async2.CheckAndThrowToken.Value.ThrowIfCancellationRequested() diff --git a/src/Compiler/Utilities/Cancellable.fsi b/src/Compiler/Utilities/Cancellable.fsi index 0d82faa68cb..ea928cd075f 100644 --- a/src/Compiler/Utilities/Cancellable.fsi +++ b/src/Compiler/Utilities/Cancellable.fsi @@ -1,79 +1,5 @@ namespace FSharp.Compiler -open System -open System.Threading - [] type Cancellable = - static member internal UseToken: unit -> Async - - static member HasCancellationToken: bool - static member Token: CancellationToken - static member CheckAndThrow: unit -> unit - static member TryCheckAndThrow: unit -> unit - -namespace Internal.Utilities.Library - -open System -open System.Threading - -[] -type internal ValueOrCancelled<'TResult> = - | Value of result: 'TResult - | Cancelled of ``exception``: OperationCanceledException - -/// Represents a synchronous, cold-start, cancellable computation with explicit representation of a cancelled result. -/// -/// A cancellable computation may be cancelled via a CancellationToken, which is propagated implicitly. -/// If cancellation occurs, it is propagated as data rather than by raising an OperationCanceledException. -[] -type internal Cancellable<'T> = Cancellable of (CancellationToken -> ValueOrCancelled<'T>) - -module internal Cancellable = - - /// Run a cancellable computation using the given cancellation token - val inline run: ct: CancellationToken -> Cancellable<'T> -> ValueOrCancelled<'T> - - val fold: f: ('State -> 'T -> Cancellable<'State>) -> acc: 'State -> seq: seq<'T> -> Cancellable<'State> - - /// Run the computation in a mode where it may not be cancelled. The computation never results in a - /// ValueOrCancelled.Cancelled. - val runWithoutCancellation: comp: Cancellable<'T> -> 'T - - /// Bind the cancellation token associated with the computation - val token: unit -> Cancellable - - val toAsync: Cancellable<'T> -> Async<'T> - -type internal CancellableBuilder = - - new: unit -> CancellableBuilder - - member inline BindReturn: comp: Cancellable<'T> * [] k: ('T -> 'U) -> Cancellable<'U> - - member inline Bind: comp: Cancellable<'T> * [] k: ('T -> Cancellable<'U>) -> Cancellable<'U> - - member inline Combine: comp1: Cancellable * comp2: Cancellable<'T> -> Cancellable<'T> - - member inline Delay: [] f: (unit -> Cancellable<'T>) -> Cancellable<'T> - - member inline Return: v: 'T -> Cancellable<'T> - - member inline ReturnFrom: v: Cancellable<'T> -> Cancellable<'T> - - member inline TryFinally: comp: Cancellable<'T> * [] compensation: (unit -> unit) -> Cancellable<'T> - - member inline TryWith: - comp: Cancellable<'T> * [] handler: (exn -> Cancellable<'T>) -> Cancellable<'T> - - member inline Using: - resource: 'Resource MaybeNull * [] comp: ('Resource MaybeNull -> Cancellable<'T>) -> - Cancellable<'T> - when 'Resource :> IDisposable and 'Resource: not struct and 'Resource: not null - - member inline Zero: unit -> Cancellable - -[] -module internal CancellableAutoOpens = - val cancellable: CancellableBuilder diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs index 77e8f4b2137..b932c0c118e 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs @@ -3,6 +3,7 @@ module CompilerService.AsyncMemoize open System open System.Threading open Internal.Utilities.Collections +open Internal.Utilities.Library open System.Threading.Tasks open System.Diagnostics @@ -36,7 +37,9 @@ let rec awaitEvents next condition = async { match! next () with | events when condition events -> return events - | _ -> return! awaitEvents next condition + | _ -> + do! Async.Sleep 1 + return! awaitEvents next condition } let rec eventsWhen next condition = @@ -68,7 +71,7 @@ let awaitHandle h = h |> Async.AwaitWaitHandle |> Async.Ignore [] let ``Basics``() = - let computation key = async { + let computation key = async2 { do! Async.Sleep 1 return key * 2 } @@ -85,8 +88,8 @@ let ``Basics``() = memoize.Get(wrapKey 3, computation 3) memoize.Get(wrapKey 2, computation 2) } - |> Async.Parallel - |> Async.RunSynchronously + |> Async2.Parallel + |> Async2.RunImmediate let expected = [| 10; 10; 4; 10; 6; 4|] @@ -105,7 +108,7 @@ let ``We can disconnect a request from a running job`` () = let cts = new CancellationTokenSource() let canFinish = new ManualResetEvent(false) - let computation = async { + let computation = async2 { do! awaitHandle canFinish } @@ -114,7 +117,7 @@ let ``We can disconnect a request from a running job`` () = let key = 1 - let task1 = Async.StartAsTask( memoize.Get(wrapKey 1, computation), cancellationToken = cts.Token) + let task1 = Async2.StartAsTask( memoize.Get(wrapKey 1, computation), cancellationToken = cts.Token) waitUntil events (received Started) cts.Cancel() @@ -133,7 +136,7 @@ let ``We can cancel a job`` () = let cts = new CancellationTokenSource() - let computation = async { + let computation = async2 { while true do do! Async.Sleep 1000 } @@ -143,7 +146,7 @@ let ``We can cancel a job`` () = let key = 1 - let task1 = Async.StartAsTask( memoize.Get(wrapKey 1, computation), cancellationToken = cts.Token) + let task1 = Async2.StartAsTask( memoize.Get(wrapKey 1, computation), cancellationToken = cts.Token) waitUntil events (received Started) @@ -160,7 +163,7 @@ let ``We can cancel a job`` () = let ``Job is restarted if first requestor cancels`` () = let jobCanComplete = new ManualResetEvent(false) - let computation key = async { + let computation key = async2 { do! awaitHandle jobCanComplete return key * 2 } @@ -172,7 +175,7 @@ let ``Job is restarted if first requestor cancels`` () = let key = 1 - let task1 = Async.StartAsTask( memoize.Get(wrapKey key, computation key), cancellationToken = cts1.Token) + let task1 = Async2.StartAsTask( memoize.Get(wrapKey key, computation key), cancellationToken = cts1.Token) waitUntil events (received Started) cts1.Cancel() @@ -181,7 +184,7 @@ let ``Job is restarted if first requestor cancels`` () = waitUntil events (received Canceled) - let task2 = Async.StartAsTask( memoize.Get(wrapKey key, computation key)) + let task2 = Async2.StartAsTask( memoize.Get(wrapKey key, computation key)) waitUntil events (countOf Started >> (=) 2) @@ -202,7 +205,7 @@ let ``Job is actually cancelled and restarted`` () = let jobCanComplete = new ManualResetEvent(false) let mutable finishedCount = 0 - let computation = async { + let computation = async2 { do! awaitHandle jobCanComplete Interlocked.Increment &finishedCount |> ignore return 42 @@ -215,14 +218,14 @@ let ``Job is actually cancelled and restarted`` () = for i in 1 .. 10 do use cts = new CancellationTokenSource() - let task = Async.StartAsTask( memoize.Get(key, computation), cancellationToken = cts.Token) + let task = Async2.StartAsTask( memoize.Get(key, computation), cancellationToken = cts.Token) waitUntil events (received Started) cts.Cancel() assertTaskCanceled task waitUntil events (received Canceled) Assert.Equal(1, memoize.Count) - let _task2 = Async.StartAsTask( memoize.Get(key, computation)) + let _task2 = Async2.StartAsTask( memoize.Get(key, computation)) waitUntil events (received Started) @@ -237,7 +240,7 @@ let ``Job keeps running if only one requestor cancels`` () = let jobCanComplete = new ManualResetEvent(false) - let computation key = async { + let computation key = async2 { do! awaitHandle jobCanComplete return key * 2 } @@ -249,11 +252,11 @@ let ``Job keeps running if only one requestor cancels`` () = let key = 1 - let task1 = Async.StartAsTask( memoize.Get(wrapKey key, computation key)) + let task1 = Async2.StartAsTask( memoize.Get(wrapKey key, computation key)) waitUntil events (received Started) - let task2 = Async.StartAsTask( memoize.Get(wrapKey key, computation key) |> Async.Ignore, cancellationToken = cts.Token) + let task2 = Async2.StartAsTask( memoize.Get(wrapKey key, computation key) |> Async2.Ignore, cancellationToken = cts.Token) waitUntil events (countOf Requested >> (=) 2) @@ -294,7 +297,7 @@ let ``Stress test`` () = let testTimeoutMs = threads * iterations * maxDuration * 2 let intenseComputation durationMs result = - async { + async2 { if rng.NextDouble() < exceptionProbability then raise (ExpectedException()) let s = Stopwatch.StartNew() @@ -305,7 +308,7 @@ let ``Stress test`` () = } let rec sleepyComputation durationMs result = - async { + async2 { if rng.NextDouble() < (exceptionProbability / (float durationMs / float stepMs)) then raise (ExpectedException()) if durationMs > 0 then @@ -316,7 +319,7 @@ let ``Stress test`` () = } let rec mixedComputation durationMs result = - async { + async2 { if durationMs > 0 then if rng.NextDouble() < 0.5 then let! _ = intenseComputation (min stepMs durationMs) () @@ -358,7 +361,7 @@ let ``Stress test`` () = let result = key * 2 let job = cache.Get(wrapKey key, computation durationMs result) let cts = new CancellationTokenSource() - let runningJob = Async.StartAsTask(job, cancellationToken = cts.Token) + let runningJob = Async2.StartAsTask(job, cancellationToken = cts.Token) cts.CancelAfter timeoutMs Interlocked.Increment &started |> ignore try @@ -402,7 +405,7 @@ let ``Cancel running jobs with the same key`` () = let jobCanContinue = new ManualResetEvent(false) - let work = async { + let work = async2 { do! awaitHandle jobCanContinue } @@ -415,7 +418,7 @@ let ``Cancel running jobs with the same key`` () = let cts = new CancellationTokenSource() let jobsToCancel = - [ for i in 1 .. 10 -> Async.StartAsTask(cache.Get(key i , work), cancellationToken = cts.Token) ] + [ for i in 1 .. 10 -> Async2.StartAsTask(cache.Get(key i , work), cancellationToken = cts.Token) ] waitUntil events (countOf Started >> (=) 10) @@ -426,7 +429,7 @@ let ``Cancel running jobs with the same key`` () = for job in jobsToCancel do assertTaskCanceled job // Start another request. - let job = cache.Get(key 11, work) |> Async.StartAsTask + let job = cache.Get(key 11, work) |> Async2.StartAsTask // up til now the jobs should have been running unobserved let current = eventsWhen events (received Requested) @@ -461,14 +464,14 @@ let ``Preserve thread static diagnostics`` () = let job1Cache = AsyncMemoize() let job2Cache = AsyncMemoize() - let job1 (input: string) = async { + let job1 (input: string) = async2 { let! _ = Async.Sleep (rng.Next(1, 30)) let ex = DummyException("job1 error") DiagnosticsThreadStatics.DiagnosticsLogger.ErrorR(ex) return Ok input } - let job2 (input: int) = async { + let job2 (input: int) = async2 { DiagnosticsThreadStatics.DiagnosticsLogger.Warning(DummyException("job2 error 1")) @@ -535,7 +538,7 @@ let ``Preserve thread static diagnostics already completed job`` () = member _.GetVersion() = 1 member _.GetLabel() = "job1" } - let job (input: string) = async { + let job (input: string) = async2 { let ex = DummyException($"job {input} error") DiagnosticsThreadStatics.DiagnosticsLogger.ErrorR(ex) return Ok input @@ -567,7 +570,7 @@ let ``We get diagnostics from the job that failed`` () = member _.GetVersion() = 1 member _.GetLabel() = "job1" } - let job = async { + let job = async2 { let ex = DummyException($"job error") // no recovery @@ -580,7 +583,7 @@ let ``We get diagnostics from the job that failed`` () = SetThreadDiagnosticsLoggerNoUnwind logger - do! cache.Get(key, job ) |> Async.Catch |> Async.Ignore + do! cache.Get(key, job ) |> Async2.Catch |> Async2.Ignore let messages = logger.Diagnostics |> List.map fst |> List.map _.Exception.Message diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 960057baf98..7ff1436a98d 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -312,12 +312,6 @@ - - - - - - @@ -352,6 +346,12 @@ + + + + + + diff --git a/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs b/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs index 4769b4c322d..608dc2c4c7c 100644 --- a/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs @@ -17,14 +17,14 @@ module BuildGraphTests = [] let private createNode () = let o = obj () - GraphNode(async { + GraphNode(async2 { Assert.shouldBeTrue (o <> null) return 1 }), WeakReference(o) [] let ``Initialization of graph node should not have a computed value``() = - let node = GraphNode(async { return 1 }) + let node = GraphNode(async2 { return 1 }) Assert.shouldBeTrue(node.TryPeekValue().IsNone) Assert.shouldBeFalse(node.HasValue) @@ -34,23 +34,23 @@ module BuildGraphTests = let resetEventInAsync = new ManualResetEvent(false) let graphNode = - GraphNode(async { + GraphNode(async2 { resetEventInAsync.Set() |> ignore - let! _ = Async.AwaitWaitHandle(resetEvent) + let! _ = Async2.AwaitWaitHandle(resetEvent) return 1 }) let task1 = - async { + async2 { let! _ = graphNode.GetOrComputeValue() () - } |> Async.StartAsTask + } |> Async2.StartAsTask let task2 = - async { + async2 { let! _ = graphNode.GetOrComputeValue() () - } |> Async.StartAsTask + } |> Async2.StartAsTask resetEventInAsync.WaitOne() |> ignore resetEvent.Set() |> ignore @@ -67,14 +67,14 @@ module BuildGraphTests = let mutable computationCount = 0 let graphNode = - GraphNode(async { + GraphNode(async2 { computationCount <- computationCount + 1 return 1 }) - let work = Async.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() )) + let work = Async2.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() )) - Async.RunImmediate(work) + Async2.RunImmediate(work) |> ignore Assert.shouldBe 1 computationCount @@ -83,11 +83,11 @@ module BuildGraphTests = let ``Many requests to get a value asynchronously should get the correct value``() = let requests = 10000 - let graphNode = GraphNode(async { return 1 }) + let graphNode = GraphNode(async2 { return 1 }) - let work = Async.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() )) + let work = Async2.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() )) - let result = Async.RunImmediate(work) + let result = Async2.RunImmediate(work) Assert.shouldNotBeEmpty result Assert.shouldBe requests result.Length @@ -102,7 +102,7 @@ module BuildGraphTests = Assert.shouldBeTrue weak.IsAlive - Async.RunImmediate(graphNode.GetOrComputeValue()) + Async2.RunImmediate(graphNode.GetOrComputeValue()) |> ignore GC.Collect(2, GCCollectionMode.Forced, true) @@ -119,7 +119,7 @@ module BuildGraphTests = Assert.shouldBeTrue weak.IsAlive - Async.RunImmediate(Async.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() ))) + Async2.RunImmediate(Async2.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() ))) |> ignore GC.Collect(2, GCCollectionMode.Forced, true) @@ -129,21 +129,21 @@ module BuildGraphTests = [] let ``A request can cancel``() = let graphNode = - GraphNode(async { + GraphNode(async2 { return 1 }) use cts = new CancellationTokenSource() let work = - async { + async2 { cts.Cancel() return! graphNode.GetOrComputeValue() } let ex = try - Async.RunImmediate(work, cancellationToken = cts.Token) + Async2.RunImmediate(work, cancellationToken = cts.Token) |> ignore failwith "Should have canceled" with @@ -157,23 +157,23 @@ module BuildGraphTests = let resetEvent = new ManualResetEvent(false) let graphNode = - GraphNode(async { - let! _ = Async.AwaitWaitHandle(resetEvent) + GraphNode(async2 { + let! _ = Async2.AwaitWaitHandle(resetEvent) return 1 }) use cts = new CancellationTokenSource() let task = - async { + async2 { cts.Cancel() resetEvent.Set() |> ignore } - |> Async.StartAsTask + |> Async2.StartAsTask let ex = try - Async.RunImmediate(graphNode.GetOrComputeValue(), cancellationToken = cts.Token) + Async2.RunImmediate(graphNode.GetOrComputeValue(), cancellationToken = cts.Token) |> ignore failwith "Should have canceled" with @@ -191,9 +191,9 @@ module BuildGraphTests = let mutable computationCount = 0 let graphNode = - GraphNode(async { + GraphNode(async2 { computationCountBeforeSleep <- computationCountBeforeSleep + 1 - let! _ = Async.AwaitWaitHandle(resetEvent) + let! _ = Async2.AwaitWaitHandle(resetEvent) computationCount <- computationCount + 1 return 1 }) @@ -201,7 +201,7 @@ module BuildGraphTests = use cts = new CancellationTokenSource() let work = - async { + async2 { let! _ = graphNode.GetOrComputeValue() () } @@ -210,15 +210,15 @@ module BuildGraphTests = for i = 0 to requests - 1 do if i % 10 = 0 then - Async.StartAsTask(work, cancellationToken = cts.Token) + Async2.StartAsTask(work, cancellationToken = cts.Token) |> tasks.Add else - Async.StartAsTask(work) + Async2.StartAsTask(work) |> tasks.Add cts.Cancel() resetEvent.Set() |> ignore - Async.RunImmediate(work) + Async2.RunImmediate(work) |> ignore Assert.shouldBeTrue cts.IsCancellationRequested @@ -244,8 +244,8 @@ module BuildGraphTests = let rng = Random() fun n -> rng.Next n - let job phase i = async { - do! random 10 |> Async.Sleep + let job phase i = async2 { + do! random 10 |> Task.Delay Assert.Equal(phase, DiagnosticsThreadStatics.BuildPhase) DiagnosticsThreadStatics.DiagnosticsLogger.DebugDisplay() |> Assert.shouldBe $"DiagnosticsLogger(CaptureDiagnosticsConcurrently {i})" @@ -254,7 +254,7 @@ module BuildGraphTests = } let work (phase: BuildPhase) = - async { + async2 { let n = 8 let logger = CapturingDiagnosticsLogger("test NodeCode") use _ = new CompilationGlobalsScope(logger, phase) @@ -286,8 +286,8 @@ module BuildGraphTests = let pickRandomPhase _ = phases[random phases.Length] Seq.init 100 pickRandomPhase |> Seq.map work - |> Async.Parallel - |> Async.RunSynchronously + |> Async2.Parallel + |> Async2.RunImmediate exception TestException @@ -355,7 +355,7 @@ module BuildGraphTests = Assert.shouldBeTrue (msg > prevError) prevError <- msg - let work i = async { + let work i = async2 { for c in 'A' .. 'F' do do! Async.SwitchToThreadPool() errorR (ExampleException $"%03d{i}{c}") @@ -365,12 +365,12 @@ module BuildGraphTests = let logger = DiagnosticsLoggerWithCallback errorCommitted use _ = UseDiagnosticsLogger logger - tasks |> Seq.take 50 |> MultipleDiagnosticsLoggers.Parallel |> Async.Ignore |> Async.RunImmediate + tasks |> Seq.take 50 |> MultipleDiagnosticsLoggers.Parallel |> Async2.Ignore |> Async2.RunImmediate // all errors committed errorCountShouldBe 300 - tasks |> Seq.skip 50 |> MultipleDiagnosticsLoggers.Sequential |> Async.Ignore |> Async.RunImmediate + tasks |> Seq.skip 50 |> MultipleDiagnosticsLoggers.Sequential |> Async2.Ignore |> Async2.RunImmediate errorCountShouldBe 600 @@ -381,17 +381,17 @@ module BuildGraphTests = use _ = UseDiagnosticsLogger (CapturingDiagnosticsLogger "test logger") let tasks = [ - async { failwith "computation failed" } + async2 { failwith "computation failed" } for i in 1 .. 300 do - async { + async2 { errorR (ExampleException $"{Interlocked.Increment(&count)}") error (ExampleException $"{Interlocked.Increment(&count)}") } ] task { - do! tasks |> MultipleDiagnosticsLoggers.Parallel |> Async.Catch |> Async.Ignore + do! tasks |> MultipleDiagnosticsLoggers.Parallel |> Async2.Catch |> Async2.Ignore // Diagnostics from all started tasks should be collected despite the exception. errorCountShouldBe count @@ -400,7 +400,7 @@ module BuildGraphTests = [] let ``AsyncLocal diagnostics context flows correctly`` () = - let work logger = async { + let work logger = async2 { SetThreadDiagnosticsLoggerNoUnwind logger errorR TestException @@ -422,17 +422,17 @@ module BuildGraphTests = loggerShouldBe logger errorCountShouldBe 3 - let workInner = async { - do! async.Zero() + let workInner = async2 { + do! async2 { } errorR TestException loggerShouldBe logger } - let! child = workInner |> Async.StartChild - let! childTask = workInner |> Async.StartChildAsTask + let! child = workInner |> Async2.StartChild + let! childTask = workInner |> Async2.StartChildAsTask do! child - do! childTask |> Async.AwaitTask + do! childTask errorCountShouldBe 5 } @@ -441,7 +441,7 @@ module BuildGraphTests = let logger = SimpleConcurrentLogger name work logger - Seq.init 10 init |> Async.Parallel |> Async.RunSynchronously |> ignore + Seq.init 10 init |> Async2.Parallel |> Async2.runWithoutCancellation |> ignore let logger = SimpleConcurrentLogger "main" use _ = UseDiagnosticsLogger logger @@ -492,53 +492,31 @@ module BuildGraphTests = Task.WaitAll(noErrorsTask, btask, task) - Seq.init 11 (fun _ -> async { errorR TestException; loggerShouldBe logger } ) |> Async.Parallel |> Async.RunSynchronously |> ignore + Seq.init 11 (fun _ -> async2 { errorR TestException; loggerShouldBe logger } ) |> Async2.Parallel |> Async2.RunImmediate |> ignore loggerShouldBe logger errorCountShouldBe 17 - async { - - // After Async.Parallel the continuation runs in the context of the last computation that finished. + async2 { do! - [ async { + [ async2 { SetThreadDiagnosticsLoggerNoUnwind DiscardErrorsLogger } ] - |> Async.Parallel - |> Async.Ignore - loggerShouldBe DiscardErrorsLogger - - SetThreadDiagnosticsLoggerNoUnwind logger + |> Async2.Parallel + |> Async2.Ignore - // On the other hand, MultipleDiagnosticsLoggers.Parallel restores caller's context. - do! - [ async { - SetThreadDiagnosticsLoggerNoUnwind DiscardErrorsLogger } ] - |> MultipleDiagnosticsLoggers.Parallel - |> Async.Ignore loggerShouldBe logger } - |> Async.RunImmediate - - // Synchronous code will affect current context: - - // This is synchronous, caller's context is affected - async { - SetThreadDiagnosticsLoggerNoUnwind DiscardErrorsLogger - do! Async.SwitchToNewThread() - loggerShouldBe DiscardErrorsLogger - } - |> Async.RunImmediate - loggerShouldBe DiscardErrorsLogger + |> Async2.RunImmediate SetThreadDiagnosticsLoggerNoUnwind logger // This runs in async continuation, so the context is forked. - async { + async2 { do! Async.Sleep 0 SetThreadDiagnosticsLoggerNoUnwind DiscardErrorsLogger do! Async.SwitchToNewThread() loggerShouldBe DiscardErrorsLogger } - |> Async.RunImmediate + |> Async2.RunImmediate loggerShouldBe logger diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl index b7994bed3ae..e639646db42 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl @@ -2011,12 +2011,7 @@ FSharp.Compiler.AbstractIL.ILBinaryReader: FSharp.Compiler.AbstractIL.ILBinaryRe FSharp.Compiler.AbstractIL.ILBinaryReader: FSharp.Compiler.AbstractIL.ILBinaryReader+MetadataOnlyFlag FSharp.Compiler.AbstractIL.ILBinaryReader: FSharp.Compiler.AbstractIL.ILBinaryReader+ReduceMemoryFlag FSharp.Compiler.AbstractIL.ILBinaryReader: FSharp.Compiler.AbstractIL.ILBinaryReader+Shim -FSharp.Compiler.Cancellable: Boolean HasCancellationToken -FSharp.Compiler.Cancellable: Boolean get_HasCancellationToken() -FSharp.Compiler.Cancellable: System.Threading.CancellationToken Token -FSharp.Compiler.Cancellable: System.Threading.CancellationToken get_Token() FSharp.Compiler.Cancellable: Void CheckAndThrow() -FSharp.Compiler.Cancellable: Void TryCheckAndThrow() FSharp.Compiler.CodeAnalysis.DelayedILModuleReader: System.String OutputFile FSharp.Compiler.CodeAnalysis.DelayedILModuleReader: System.String get_OutputFile() FSharp.Compiler.CodeAnalysis.DelayedILModuleReader: Void .ctor(System.String, Microsoft.FSharp.Core.FSharpFunc`2[System.Threading.CancellationToken,Microsoft.FSharp.Core.FSharpOption`1[System.IO.Stream]]) @@ -12393,10 +12388,170 @@ FSharp.Compiler.Xml.XmlDoc: System.String[] GetElaboratedXmlLines() FSharp.Compiler.Xml.XmlDoc: System.String[] UnprocessedLines FSharp.Compiler.Xml.XmlDoc: System.String[] get_UnprocessedLines() FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Range) +Internal.Utilities.Library.Async2: Internal.Utilities.Library.Async2`1[Internal.Utilities.Library.Async2`1[T]] StartChild[T](Internal.Utilities.Library.Async2`1[T]) +Internal.Utilities.Library.Async2: Internal.Utilities.Library.Async2`1[Microsoft.FSharp.Core.FSharpChoice`2[T,System.Exception]] Catch[T](Internal.Utilities.Library.Async2`1[T]) +Internal.Utilities.Library.Async2: Internal.Utilities.Library.Async2`1[Microsoft.FSharp.Core.Unit] Ignore[a](Internal.Utilities.Library.Async2`1[a]) +Internal.Utilities.Library.Async2: Internal.Utilities.Library.Async2`1[System.Boolean] AwaitWaitHandle(System.Threading.WaitHandle) +Internal.Utilities.Library.Async2: Internal.Utilities.Library.Async2`1[System.Threading.Tasks.Task`1[T]] StartChildAsTask[T](Internal.Utilities.Library.Async2`1[T]) +Internal.Utilities.Library.Async2: Internal.Utilities.Library.Async2`1[T] TryCancelled[T](Internal.Utilities.Library.Async2`1[T], Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]) +Internal.Utilities.Library.Async2: Internal.Utilities.Library.Async2`1[a[]] Parallel[a](System.Collections.Generic.IEnumerable`1[Internal.Utilities.Library.Async2`1[a]]) +Internal.Utilities.Library.Async2: Internal.Utilities.Library.Async2`1[a[]] Sequential[a](System.Collections.Generic.IEnumerable`1[Internal.Utilities.Library.Async2`1[a]]) +Internal.Utilities.Library.Async2: System.Threading.Tasks.Task`1[a] StartAsTask[a](Internal.Utilities.Library.Async2`1[a], Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken]) +Internal.Utilities.Library.Async2: T RunImmediate[T](Internal.Utilities.Library.Async2`1[T], Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken]) +Internal.Utilities.Library.Async2: Void Start[a](Internal.Utilities.Library.Async2`1[a], Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken]) +Internal.Utilities.Library.Async2AutoOpens: Async2Builder async2 +Internal.Utilities.Library.Async2AutoOpens: Async2Builder get_async2() +Internal.Utilities.Library.Async2Implementation+Async2Builder: Internal.Utilities.Library.Async2`1[T] RunDynamic[T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[T],T]) +Internal.Utilities.Library.Async2Implementation+Async2Builder: Internal.Utilities.Library.Async2`1[T] Run[T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[T],T]) +Internal.Utilities.Library.Async2Implementation+Async2Builder: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],Microsoft.FSharp.Core.Unit] For[T,TOverall](System.Collections.Generic.IEnumerable`1[T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],Microsoft.FSharp.Core.Unit]]) +Internal.Utilities.Library.Async2Implementation+Async2Builder: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],Microsoft.FSharp.Core.Unit] While[TOverall](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Boolean], Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],Microsoft.FSharp.Core.Unit]) +Internal.Utilities.Library.Async2Implementation+Async2Builder: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],Microsoft.FSharp.Core.Unit] Zero[TOverall]() +Internal.Utilities.Library.Async2Implementation+Async2Builder: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T] Combine[TOverall,T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],Microsoft.FSharp.Core.Unit], Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T]) +Internal.Utilities.Library.Async2Implementation+Async2Builder: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T] Delay[TOverall,T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T]]) +Internal.Utilities.Library.Async2Implementation+Async2Builder: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T] TryFinally[TOverall,T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T], Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]) +Internal.Utilities.Library.Async2Implementation+Async2Builder: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T] TryWith[TOverall,T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T], Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T]]) +Internal.Utilities.Library.Async2Implementation+Async2Builder: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T] Using[Resource,TOverall,T](Resource, Microsoft.FSharp.Core.FSharpFunc`2[Resource,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[TOverall],T]]) +Internal.Utilities.Library.Async2Implementation+Async2Builder: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[T],a] Return[T,a](T) +Internal.Utilities.Library.Async2Implementation+Async2Builder: Void .ctor() +Internal.Utilities.Library.Async2Implementation+Async2Code: Boolean bindDynamic$W[a,b,c,d](Microsoft.FSharp.Core.FSharpFunc`2[b,c], Microsoft.FSharp.Core.FSharpFunc`2[b,System.Boolean], Microsoft.FSharp.Core.CompilerServices.ResumableStateMachine`1[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a]] ByRef, b, Microsoft.FSharp.Core.FSharpFunc`2[c,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],d]]) +Internal.Utilities.Library.Async2Implementation+Async2Code: Boolean bindDynamic[a,b,c,d](Microsoft.FSharp.Core.CompilerServices.ResumableStateMachine`1[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a]] ByRef, b, Microsoft.FSharp.Core.FSharpFunc`2[c,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],d]]) +Internal.Utilities.Library.Async2Implementation+Async2Code: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Data],T] bindAwaiter$W[a,U,Data,T](Microsoft.FSharp.Core.FSharpFunc`2[a,U], Microsoft.FSharp.Core.FSharpFunc`2[a,System.Boolean], a, Microsoft.FSharp.Core.FSharpFunc`2[U,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Data],T]]) +Internal.Utilities.Library.Async2Implementation+Async2Code: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Data],T] bindAwaiter[a,U,Data,T](a, Microsoft.FSharp.Core.FSharpFunc`2[U,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Data],T]]) +Internal.Utilities.Library.Async2Implementation+Async2Code: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Data],T] bindCancellable$W[a,U,Data,T](Microsoft.FSharp.Core.FSharpFunc`2[a,U], Microsoft.FSharp.Core.FSharpFunc`2[a,System.Boolean], Microsoft.FSharp.Core.FSharpFunc`2[System.Threading.CancellationToken,a], Microsoft.FSharp.Core.FSharpFunc`2[U,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Data],T]]) +Internal.Utilities.Library.Async2Implementation+Async2Code: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Data],T] bindCancellable[a,U,Data,T](Microsoft.FSharp.Core.FSharpFunc`2[System.Threading.CancellationToken,a], Microsoft.FSharp.Core.FSharpFunc`2[U,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Data],T]]) +Internal.Utilities.Library.Async2Implementation+Async2Code: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],b] yieldOnBindLimit[a,b]() +Internal.Utilities.Library.Async2Implementation+Async2Code: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],c] filterCancellation[a,b,c](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],b]], System.Exception) +Internal.Utilities.Library.Async2Implementation+Async2Code: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],c] throwIfCancellationRequested[a,b,c](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],b]) +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: Boolean Equals(Async2Data`1) +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: Boolean Equals(Async2Data`1, System.Collections.IEqualityComparer) +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: Boolean Equals(System.Object) +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: Boolean Equals(System.Object, System.Collections.IEqualityComparer) +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: Boolean IsBound +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: Int32 GetHashCode() +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: Int32 GetHashCode(System.Collections.IEqualityComparer) +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: Microsoft.FSharp.Core.FSharpValueOption`1[System.Threading.Tasks.TaskCompletionSource`1[t]] TailCallSource +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[t] MethodBuilder +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: System.Threading.CancellationToken CancellationToken +Internal.Utilities.Library.Async2Implementation+Async2Data`1[t]: t Result +Internal.Utilities.Library.Async2Implementation+Async2Dynamic`2[t,m]: Internal.Utilities.Library.Async2`1[t] GetCopy(Boolean) +Internal.Utilities.Library.Async2Implementation+Async2Dynamic`2[t,m]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[System.Boolean,m]) +Internal.Utilities.Library.Async2Implementation+Async2`2[t,m]: Boolean Equals(Async2`2) +Internal.Utilities.Library.Async2Implementation+Async2`2[t,m]: Boolean Equals(Async2`2, System.Collections.IEqualityComparer) +Internal.Utilities.Library.Async2Implementation+Async2`2[t,m]: Boolean Equals(System.Object) +Internal.Utilities.Library.Async2Implementation+Async2`2[t,m]: Boolean Equals(System.Object, System.Collections.IEqualityComparer) +Internal.Utilities.Library.Async2Implementation+Async2`2[t,m]: Int32 GetHashCode() +Internal.Utilities.Library.Async2Implementation+Async2`2[t,m]: Int32 GetHashCode(System.Collections.IEqualityComparer) +Internal.Utilities.Library.Async2Implementation+Async2`2[t,m]: Internal.Utilities.Library.IAsync2Invocation`1[t] Start(System.Threading.CancellationToken, Microsoft.FSharp.Core.FSharpValueOption`1[System.Threading.Tasks.TaskCompletionSource`1[t]], Boolean) +Internal.Utilities.Library.Async2Implementation+Async2`2[t,m]: m StateMachine +Internal.Utilities.Library.Async2Implementation+Awaitable: b getAwaiter$W[a,b,c](Microsoft.FSharp.Core.FSharpFunc`2[a,b], Microsoft.FSharp.Core.FSharpFunc`2[b,c], Microsoft.FSharp.Core.FSharpFunc`2[b,System.Boolean], a) +Internal.Utilities.Library.Async2Implementation+Awaitable: b getAwaiter[a,b,c](a) +Internal.Utilities.Library.Async2Implementation+Awaiter: Boolean isCompleted$W[a,b](Microsoft.FSharp.Core.FSharpFunc`2[a,b], Microsoft.FSharp.Core.FSharpFunc`2[a,System.Boolean], a) +Internal.Utilities.Library.Async2Implementation+Awaiter: Boolean isCompleted[a,b](a) +Internal.Utilities.Library.Async2Implementation+Awaiter: Void onCompleted$W[a,b](Microsoft.FSharp.Core.FSharpFunc`2[a,b], Microsoft.FSharp.Core.FSharpFunc`2[a,System.Boolean], a, System.Action) +Internal.Utilities.Library.Async2Implementation+Awaiter: Void onCompleted[a,b](a, System.Action) +Internal.Utilities.Library.Async2Implementation+Awaiter: Void unsafeOnCompleted$W[a,b](Microsoft.FSharp.Core.FSharpFunc`2[a,b], Microsoft.FSharp.Core.FSharpFunc`2[a,System.Boolean], a, System.Action) +Internal.Utilities.Library.Async2Implementation+Awaiter: Void unsafeOnCompleted[a,b](a, System.Action) +Internal.Utilities.Library.Async2Implementation+Awaiter: b getResult$W[a,b](Microsoft.FSharp.Core.FSharpFunc`2[a,b], Microsoft.FSharp.Core.FSharpFunc`2[a,System.Boolean], a) +Internal.Utilities.Library.Async2Implementation+Awaiter: b getResult[a,b](a) +Internal.Utilities.Library.Async2Implementation+BindContext: Boolean IncrementBindCount() +Internal.Utilities.Library.Async2Implementation+BindContext: Int32 bindLimit +Internal.Utilities.Library.Async2Implementation+BindContext: System.Threading.ThreadLocal`1[System.Int32] bindCount +Internal.Utilities.Library.Async2Implementation+BindContext: System.Threading.ThreadLocal`1[System.Int32] get_bindCount() +Internal.Utilities.Library.Async2Implementation+BindContext: Void Reset() +Internal.Utilities.Library.Async2Implementation+DynamicState+Awaiting: System.Runtime.CompilerServices.ICriticalNotifyCompletion Item +Internal.Utilities.Library.Async2Implementation+DynamicState+Awaiting: System.Runtime.CompilerServices.ICriticalNotifyCompletion get_Item() +Internal.Utilities.Library.Async2Implementation+DynamicState+Bounce: DynamicState Item +Internal.Utilities.Library.Async2Implementation+DynamicState+Bounce: DynamicState get_Item() +Internal.Utilities.Library.Async2Implementation+DynamicState+Immediate: DynamicState Item +Internal.Utilities.Library.Async2Implementation+DynamicState+Immediate: DynamicState get_Item() +Internal.Utilities.Library.Async2Implementation+DynamicState+SetException: System.Runtime.ExceptionServices.ExceptionDispatchInfo Item +Internal.Utilities.Library.Async2Implementation+DynamicState+SetException: System.Runtime.ExceptionServices.ExceptionDispatchInfo get_Item() +Internal.Utilities.Library.Async2Implementation+DynamicState+Tags: Int32 Awaiting +Internal.Utilities.Library.Async2Implementation+DynamicState+Tags: Int32 Bounce +Internal.Utilities.Library.Async2Implementation+DynamicState+Tags: Int32 Immediate +Internal.Utilities.Library.Async2Implementation+DynamicState+Tags: Int32 Running +Internal.Utilities.Library.Async2Implementation+DynamicState+Tags: Int32 SetException +Internal.Utilities.Library.Async2Implementation+DynamicState+Tags: Int32 SetResult +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean Equals(DynamicState) +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean Equals(DynamicState, System.Collections.IEqualityComparer) +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean Equals(System.Object) +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean Equals(System.Object, System.Collections.IEqualityComparer) +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean IsAwaiting +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean IsBounce +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean IsImmediate +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean IsRunning +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean IsSetException +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean IsSetResult +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean get_IsAwaiting() +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean get_IsBounce() +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean get_IsImmediate() +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean get_IsRunning() +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean get_IsSetException() +Internal.Utilities.Library.Async2Implementation+DynamicState: Boolean get_IsSetResult() +Internal.Utilities.Library.Async2Implementation+DynamicState: DynamicState NewAwaiting(System.Runtime.CompilerServices.ICriticalNotifyCompletion) +Internal.Utilities.Library.Async2Implementation+DynamicState: DynamicState NewBounce(DynamicState) +Internal.Utilities.Library.Async2Implementation+DynamicState: DynamicState NewImmediate(DynamicState) +Internal.Utilities.Library.Async2Implementation+DynamicState: DynamicState NewSetException(System.Runtime.ExceptionServices.ExceptionDispatchInfo) +Internal.Utilities.Library.Async2Implementation+DynamicState: DynamicState Running +Internal.Utilities.Library.Async2Implementation+DynamicState: DynamicState SetResult +Internal.Utilities.Library.Async2Implementation+DynamicState: DynamicState get_Running() +Internal.Utilities.Library.Async2Implementation+DynamicState: DynamicState get_SetResult() +Internal.Utilities.Library.Async2Implementation+DynamicState: Int32 GetHashCode() +Internal.Utilities.Library.Async2Implementation+DynamicState: Int32 GetHashCode(System.Collections.IEqualityComparer) +Internal.Utilities.Library.Async2Implementation+DynamicState: Int32 Tag +Internal.Utilities.Library.Async2Implementation+DynamicState: Int32 get_Tag() +Internal.Utilities.Library.Async2Implementation+DynamicState: Internal.Utilities.Library.Async2Implementation+DynamicState+Awaiting +Internal.Utilities.Library.Async2Implementation+DynamicState: Internal.Utilities.Library.Async2Implementation+DynamicState+Bounce +Internal.Utilities.Library.Async2Implementation+DynamicState: Internal.Utilities.Library.Async2Implementation+DynamicState+Immediate +Internal.Utilities.Library.Async2Implementation+DynamicState: Internal.Utilities.Library.Async2Implementation+DynamicState+SetException +Internal.Utilities.Library.Async2Implementation+DynamicState: Internal.Utilities.Library.Async2Implementation+DynamicState+Tags +Internal.Utilities.Library.Async2Implementation+DynamicState: System.String ToString() +Internal.Utilities.Library.Async2Implementation+ExceptionCache: System.Runtime.CompilerServices.ConditionalWeakTable`2[System.Exception,System.Runtime.ExceptionServices.ExceptionDispatchInfo] get_store() +Internal.Utilities.Library.Async2Implementation+ExceptionCache: System.Runtime.CompilerServices.ConditionalWeakTable`2[System.Exception,System.Runtime.ExceptionServices.ExceptionDispatchInfo] store +Internal.Utilities.Library.Async2Implementation+ExceptionCache: System.Runtime.ExceptionServices.ExceptionDispatchInfo CaptureOrRetrieve(System.Exception) +Internal.Utilities.Library.Async2Implementation+ExceptionCache: a Throw[a](System.Exception) +Internal.Utilities.Library.Async2Implementation+ExceptionCache: b GetResultOrThrow$W[a,b](Microsoft.FSharp.Core.FSharpFunc`2[a,b], Microsoft.FSharp.Core.FSharpFunc`2[a,System.Boolean], a) +Internal.Utilities.Library.Async2Implementation+ExceptionCache: b GetResultOrThrow[a,b](a) +Internal.Utilities.Library.Async2Implementation+Trampoline: Microsoft.FSharp.Core.FSharpRef`1[System.Runtime.CompilerServices.ICriticalNotifyCompletion] Ref +Internal.Utilities.Library.Async2Implementation+Trampoline: Microsoft.FSharp.Core.FSharpRef`1[System.Runtime.CompilerServices.ICriticalNotifyCompletion] get_Ref() +Internal.Utilities.Library.Async2Implementation+Trampoline: Trampoline Current +Internal.Utilities.Library.Async2Implementation+Trampoline: Trampoline get_Current() +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+Async2Builder +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+Async2Code +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+Async2Data`1[t] +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+Async2Dynamic`2[t,m] +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+Async2`2[t,m] +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+Awaitable +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+Awaiter +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+BindContext +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+DynamicState +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+ExceptionCache +Internal.Utilities.Library.Async2Implementation: Internal.Utilities.Library.Async2Implementation+Trampoline +Internal.Utilities.Library.Async2Module: Internal.Utilities.Library.Async2`1[System.Threading.CancellationToken] CancellationToken +Internal.Utilities.Library.Async2Module: Internal.Utilities.Library.Async2`1[System.Threading.CancellationToken] get_CancellationToken() +Internal.Utilities.Library.Async2Module: Internal.Utilities.Library.Async2`1[t] fromValue[t](t) +Internal.Utilities.Library.Async2Module: Microsoft.FSharp.Control.FSharpAsync`1[t] toAsync[t](Internal.Utilities.Library.Async2`1[t]) +Internal.Utilities.Library.Async2Module: System.Threading.AsyncLocal`1[System.Threading.CancellationToken] CheckAndThrowToken +Internal.Utilities.Library.Async2Module: System.Threading.AsyncLocal`1[System.Threading.CancellationToken] get_CheckAndThrowToken() +Internal.Utilities.Library.Async2Module: System.Threading.Tasks.Task`1[a] startAsTaskWithoutCancellation[a](Internal.Utilities.Library.Async2`1[a]) +Internal.Utilities.Library.Async2Module: System.Threading.Tasks.Task`1[a] start[a](System.Threading.CancellationToken, Internal.Utilities.Library.Async2`1[a]) +Internal.Utilities.Library.Async2Module: System.Threading.Tasks.Task`1[t] startInThreadPool[t](System.Threading.CancellationToken, Internal.Utilities.Library.Async2`1[t]) +Internal.Utilities.Library.Async2Module: a runWithoutCancellation[a](Internal.Utilities.Library.Async2`1[a]) +Internal.Utilities.Library.Async2Module: t run[t](System.Threading.CancellationToken, Internal.Utilities.Library.Async2`1[t]) +Internal.Utilities.Library.Async2`1[t]: Internal.Utilities.Library.IAsync2Invocation`1[t] StartImmediate(System.Threading.CancellationToken) +Internal.Utilities.Library.Async2`1[t]: System.Runtime.CompilerServices.TaskAwaiter`1[t] GetAwaiter() +Internal.Utilities.Library.Async2`1[t]: System.Runtime.CompilerServices.TaskAwaiter`1[t] StartBound(System.Threading.CancellationToken) +Internal.Utilities.Library.Async2`1[t]: Void TailCall(System.Threading.CancellationToken, Microsoft.FSharp.Core.FSharpValueOption`1[System.Threading.Tasks.TaskCompletionSource`1[t]]) Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] CreateDictionary(T[]) Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] GetDictionary() Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: T[] GetArray() Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T[]]) +Internal.Utilities.Library.HighPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Data],T] Async2Builder.Bind[U,Data,T](Async2Builder, Internal.Utilities.Library.Async2`1[U], Microsoft.FSharp.Core.FSharpFunc`2[U,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Data],T]]) +Internal.Utilities.Library.HighPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[T],T] Async2Builder.ReturnFrom[T](Async2Builder, Internal.Utilities.Library.Async2`1[T]) +Internal.Utilities.Library.HighPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[T],a] Async2Builder.ReturnFromFinal[T,a](Async2Builder, Internal.Utilities.Library.Async2`1[T]) +Internal.Utilities.Library.IAsync2Invocation`1[t]: System.Runtime.CompilerServices.TaskAwaiter`1[t] GetAwaiter() +Internal.Utilities.Library.IAsync2Invocation`1[t]: System.Threading.Tasks.Task`1[t] Task +Internal.Utilities.Library.IAsync2Invocation`1[t]: System.Threading.Tasks.Task`1[t] get_Task() Internal.Utilities.Library.InterruptibleLazy: T force[T](Internal.Utilities.Library.InterruptibleLazy`1[T]) Internal.Utilities.Library.InterruptibleLazy`1[T]: Boolean IsValueCreated Internal.Utilities.Library.InterruptibleLazy`1[T]: Boolean get_IsValueCreated() @@ -12404,4 +12559,19 @@ Internal.Utilities.Library.InterruptibleLazy`1[T]: Internal.Utilities.Library.In Internal.Utilities.Library.InterruptibleLazy`1[T]: T Force() Internal.Utilities.Library.InterruptibleLazy`1[T]: T Value Internal.Utilities.Library.InterruptibleLazy`1[T]: T get_Value() -Internal.Utilities.Library.InterruptibleLazy`1[T]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T]) \ No newline at end of file +Internal.Utilities.Library.InterruptibleLazy`1[T]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T]) +Internal.Utilities.Library.LowPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[c],d] Async2Builder.ReturnFrom$W[a,b,c,d](Microsoft.FSharp.Core.FSharpFunc`2[a,b], Microsoft.FSharp.Core.FSharpFunc`2[b,c], Microsoft.FSharp.Core.FSharpFunc`2[b,System.Boolean], Async2Builder, a) +Internal.Utilities.Library.LowPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[c],d] Async2Builder.ReturnFromFinal$W[a,b,c,d](Microsoft.FSharp.Core.FSharpFunc`2[a,b], Microsoft.FSharp.Core.FSharpFunc`2[b,c], Microsoft.FSharp.Core.FSharpFunc`2[b,System.Boolean], Async2Builder, a) +Internal.Utilities.Library.LowPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[c],d] Async2Builder.ReturnFromFinal[a,b,c,d](Async2Builder, a) +Internal.Utilities.Library.LowPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[c],d] Async2Builder.ReturnFrom[a,b,c,d](Async2Builder, a) +Internal.Utilities.Library.LowPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[d],e] Async2Builder.Bind$W[a,b,c,d,e](Microsoft.FSharp.Core.FSharpFunc`2[a,b], Microsoft.FSharp.Core.FSharpFunc`2[b,c], Microsoft.FSharp.Core.FSharpFunc`2[b,System.Boolean], Async2Builder, a, Microsoft.FSharp.Core.FSharpFunc`2[c,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[d],e]]) +Internal.Utilities.Library.LowPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[d],e] Async2Builder.Bind[a,b,c,d,e](Async2Builder, a, Microsoft.FSharp.Core.FSharpFunc`2[c,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[d],e]]) +Internal.Utilities.Library.MediumPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Microsoft.FSharp.Core.Unit],a] Async2Builder.ReturnFromFinal[a](Async2Builder, System.Threading.Tasks.Task) +Internal.Utilities.Library.MediumPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[Microsoft.FSharp.Core.Unit],a] Async2Builder.ReturnFrom[a](Async2Builder, System.Threading.Tasks.Task) +Internal.Utilities.Library.MediumPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],b] Async2Builder.Bind[a,b](Async2Builder, System.Threading.Tasks.Task, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],b]]) +Internal.Utilities.Library.MediumPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],b] Async2Builder.ReturnFromFinal[a,b](Async2Builder, Microsoft.FSharp.Control.FSharpAsync`1[a]) +Internal.Utilities.Library.MediumPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],b] Async2Builder.ReturnFromFinal[a,b](Async2Builder, System.Threading.Tasks.Task`1[a]) +Internal.Utilities.Library.MediumPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],b] Async2Builder.ReturnFrom[a,b](Async2Builder, Microsoft.FSharp.Control.FSharpAsync`1[a]) +Internal.Utilities.Library.MediumPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[a],b] Async2Builder.ReturnFrom[a,b](Async2Builder, System.Threading.Tasks.Task`1[a]) +Internal.Utilities.Library.MediumPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[b],c] Async2Builder.Bind[a,b,c](Async2Builder, Microsoft.FSharp.Control.FSharpAsync`1[a], Microsoft.FSharp.Core.FSharpFunc`2[a,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[b],c]]) +Internal.Utilities.Library.MediumPriority: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[b],c] Async2Builder.Bind[a,b,c](Async2Builder, System.Threading.Tasks.Task`1[a], Microsoft.FSharp.Core.FSharpFunc`2[a,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Internal.Utilities.Library.Async2Implementation+Async2Data`1[b],c]]) \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/ModuleReaderCancellationTests.fs b/tests/FSharp.Compiler.Service.Tests/ModuleReaderCancellationTests.fs index f307586cd5c..2dd72a0b93e 100644 --- a/tests/FSharp.Compiler.Service.Tests/ModuleReaderCancellationTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/ModuleReaderCancellationTests.fs @@ -150,7 +150,7 @@ let parseAndCheck path source options = | _, FSharpCheckFileAnswer.Aborted -> None | _, FSharpCheckFileAnswer.Succeeded results -> Some results - Cancellable.HasCancellationToken |> shouldEqual false + Async2.CheckAndThrowToken.Value |> shouldEqual CancellationToken.None result with :? OperationCanceledException -> @@ -173,11 +173,6 @@ open Ns1.Ns2 let t: T = T() """ - -[] -let ``CheckAndThrow is not allowed to throw outside of cancellable`` () = - Assert.Throws(fun () -> Cancellable.CheckAndThrow()) - [] let ``Type defs 01 - assembly import`` () = let source = source1 diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs index 518bf88bc74..2f6d923770b 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs @@ -11,7 +11,6 @@ open FSharp.Compiler open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.CodeAnalysis.ProjectSnapshot open FSharp.Compiler.Symbols -open FSharp.Compiler.BuildGraph open CancellableTasks @@ -20,7 +19,6 @@ open System.IO open Internal.Utilities.Collections open Newtonsoft.Json open Newtonsoft.Json.Linq -open System.Text.Json.Nodes #nowarn "57" // Experimental stuff @@ -377,7 +375,7 @@ module private CheckerExtensions = member _.GetLabel() = project.FilePath } - snapshotCache.Get( + snapshotCache.GetAsync( key, async { let! ct = Async.CancellationToken