Skip to content

Commit

Permalink
Cleanups
Browse files Browse the repository at this point in the history
  • Loading branch information
TheAngryByrd committed Mar 28, 2023
1 parent 46814f8 commit c5fb1f3
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 100 deletions.
125 changes: 73 additions & 52 deletions src/FsAutoComplete.Core/AdaptiveExtensions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -471,40 +471,46 @@ module AsyncAVal =
/// </summary>
let ofTask (value: Task<'a>) = ConstantVal(value) :> asyncaval<_>

// let ofCancelableTask (value: AdaptiveCancellableTask<'a>) = ConstantVal(value) :> asyncaval<_>

// let ofCancellableTask (value : CancellableTask<'a>) =
// ConstantVal (
// let cts = new CancellationTokenSource ()
// let cancel () =
// cts.Cancel()
// cts.Dispose()
// let real = task {
// try
// return! value cts.Token
// finally
// cts.Dispose()
// }
// AdaptiveCancellableTask(cancel, real)
// )
// :> asyncaval<_>


// let ofAsync (value : Async<'a>) =
// ConstantVal (
// let cts = new CancellationTokenSource ()
// let cancel () =
// cts.Cancel()
// cts.Dispose()
// let real = task {
// try
// return! Async.StartImmediateAsTask(value, cts.Token)
// finally
// cts.Dispose()
// }
// AdaptiveCancellableTask(cancel, real)
// )
// :> asyncaval<_>
let ofCancellableTask (value: CancellableTask<'a>) =
ConstantVal(
let cts = new CancellationTokenSource()

let cancel () =
cts.Cancel()
cts.Dispose()

let real =
task {
try
return! value cts.Token
finally
cts.Dispose()
}

AdaptiveCancellableTask(cancel, real)
)
:> asyncaval<_>


let ofAsync (value: Async<'a>) =
ConstantVal(
let cts = new CancellationTokenSource()

let cancel () =
cts.Cancel()
cts.Dispose()

let real =
task {
try
return! Async.StartImmediateAsTask(value, cts.Token)
finally
cts.Dispose()
}

AdaptiveCancellableTask(cancel, real)
)
:> asyncaval<_>


/// <summary>
Expand Down Expand Up @@ -553,6 +559,37 @@ module AsyncAVal =
:> asyncaval<_>


/// <summary>
/// Returns a new async adaptive value that adaptively applies the mapping fun tion to the given
/// adaptive inputs.
/// </summary>
let mapAsync (mapping: 'a -> Async<'b>) (input: asyncaval<'a>) =
let mutable cache: option<RefCountingTaskCreator<'b>> = None

{ new AbstractVal<'b>() with
member x.Compute t =
if x.OutOfDate || Option.isNone cache then
let ref =
RefCountingTaskCreator(
cancellableTask {
let! ct = CancellableTask.getCancellationToken ()
let it = input.GetValue t
let s = ct.Register(fun () -> it.Cancel())

try
let! i = it
return! mapping i
finally
s.Dispose()
}
)

cache <- Some ref
ref.New()
else
cache.Value.New() }
:> asyncaval<_>


/// <summary>
/// Returns a new async adaptive value that adaptively applies the mapping fun tion to the given
Expand Down Expand Up @@ -704,37 +741,21 @@ type AsyncAValBuilder() =
member inline x.BindReturn(value: asyncaval<'T1>, [<InlineIfLambda>] mapping: 'T1 -> CancellationToken -> Task<'T2>) =
AsyncAVal.map mapping value


// member inline x.BindReturn(value: asyncaval<'T1>, [<InlineIfLambda>] mapping: 'T1 * CancellationToken -> Task<'T2>) =
// AsyncAVal.map (fun data ctok -> mapping(data,ctok)) value
member inline x.BindReturn(value: asyncaval<'T1>, [<InlineIfLambda>] mapping: 'T1 -> Async<'T2>) =
AsyncAVal.mapAsync mapping value

member inline x.BindReturn(value: asyncaval<'T1>, [<InlineIfLambda>] mapping: 'T1 -> Task<'T2>) =
AsyncAVal.map (fun data _ -> mapping data) value

// member inline x.Bind2Return(v1 : aval<'T1>, v2 : aval<'T2>, mapping: 'T1 * 'T2 -> 'T3) =
// AVal.map2 (fun a b -> mapping(a,b)) v1 v2

// member inline x.Bind3Return(v1 : aval<'T1>, v2: aval<'T2>, v3: aval<'T3>, mapping: 'T1 * 'T2 * 'T3 -> 'T4) =
// AVal.map3 (fun a b c -> mapping(a, b, c)) v1 v2 v3

member inline x.Bind(value: asyncaval<'T1>, [<InlineIfLambda>] mapping: 'T1 -> CancellationToken -> asyncaval<'T2>) =
AsyncAVal.bind (mapping) value

// member inline x.Bind(value: asyncaval<'T1>, [<InlineIfLambda>] mapping: 'T1 * CancellationToken -> asyncaval<'T2>) =
// AsyncAVal.bind (fun data ctok -> mapping(data,ctok)) value




member inline x.Bind(value: asyncaval<'T1>, [<InlineIfLambda>] mapping: 'T1 -> asyncaval<'T2>) =
AsyncAVal.bind (fun data _ -> mapping data) value

// member inline x.Bind2(v1: aval<'T1>, v2: aval<'T2>, mapping: 'T1 * 'T2 -> aval<'T3>) =
// AVal.bind2 (fun a b -> mapping(a,b)) v1 v2

// member inline x.Bind3(v1: aval<'T1>, v2: aval<'T2>, v3: aval<'T3>, mapping: 'T1 * 'T2 * 'T3 -> aval<'T4>) =
// AVal.bind3 (fun a b c -> mapping(a, b, c)) v1 v2 v3

member inline x.Return(value: 'T) = AsyncAVal.constant value

member inline x.ReturnFrom(value: asyncaval<'T>) = value
Expand Down
16 changes: 12 additions & 4 deletions src/FsAutoComplete.Core/CompilerServiceInterface.fs
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,21 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize) =
checker.InvalidateAll()
checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()

member __.ParseFile(fn: string<LocalPath>, source, fpo) =
/// <summary>Parses a source code for a file and caches the results. Returns an AST that can be traversed for various features.</summary>
/// <param name="filePath"> The path for the file. The file name is used as a module name for implicit top level modules (e.g. in scripts).</param>
/// <param name="source">The source to be parsed.</param>
/// <param name="options">Parsing options for the project or script.</param>
/// <returns></returns>
member __.ParseFile(filePath: string<LocalPath>, source: ISourceText, options: FSharpParsingOptions) =
async {
checkerLogger.info (Log.setMessage "ParseFile - {file}" >> Log.addContextDestructured "file" fn)
checkerLogger.info (
Log.setMessage "ParseFile - {file}"
>> Log.addContextDestructured "file" filePath
)

let path = UMX.untag fn
let path = UMX.untag filePath
do! Async.SwitchToNewThread()
return! checker.ParseFile(path, source, fpo)
return! checker.ParseFile(path, source, options)
}

/// <summary>Parse and check a source code file, returning a handle to the results</summary>
Expand Down
1 change: 0 additions & 1 deletion src/FsAutoComplete.Core/Utils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,6 @@ module Async =
Math.Max(1.0, Math.Floor((float System.Environment.ProcessorCount) * 0.75))

Async.Parallel(computations, int maxConcurrency)
// Async.Parallel(computations)

[<RequireQualifiedAccess>]
module Array =
Expand Down
2 changes: 1 addition & 1 deletion src/FsAutoComplete/LspHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ module Conversions =
not keep

topLevel.Nested
|> Array.choose (fun n -> if shouldKeep n then Some(map n) else None)
|> Array.Parallel.choose (fun n -> if shouldKeep n then Some(map n) else None)

let getLine (lines: string[]) (pos: Lsp.Position) = lines.[pos.Line]

Expand Down
84 changes: 42 additions & 42 deletions src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
let handleCommandEvents (n: NotificationEvent, ct: CancellationToken) =
try
async {

try
match n with
| NotificationEvent.FileParsed fn ->
Expand Down Expand Up @@ -935,34 +936,44 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
FSharp.Compiler.IO.FileSystemAutoOpens.FileSystem <-
FileSystem(FSharp.Compiler.IO.FileSystemAutoOpens.FileSystem, filesystemShim)

/// <summary>Parses a source code for a file and caches the results. Returns an AST that can be traversed for various features.</summary>
/// <param name="checker">The FSharpCompilerServiceChecker.</param>
/// <param name="source">The source to be parsed.</param>
/// <param name="parseOpts">Parsing options for the project or script</param>
/// <param name="options">The options for the project or script.</param>
/// <returns></returns>
let parseFile (checker: FSharpCompilerServiceChecker) (source: VolatileFile) parseOpts options =
async {
let! result = checker.ParseFile(source.FileName, source.Lines, parseOpts)

let! ct = Async.CancellationToken
fileParsed.Trigger(result, options, ct)
return result
}


/// <summary>Parses all files in the workspace. This is mostly used to trigger finding tests.</summary>
let parseAllFiles () =
asyncAVal {
let! projects = loadedProjectOptions
and! (checker: FSharpCompilerServiceChecker) = checker


return
fun (ct: CancellationToken) ->
projects
|> Array.ofList
|> Array.Parallel.collect (fun p ->
let parseOpts = Utils.projectOptionsToParseOptions p
p.SourceFiles |> Array.map (fun s -> p, parseOpts, s))
|> Array.Parallel.map (fun (opts, parseOpts, fileName) ->
let fileName = UMX.tag fileName

asyncResult {
let! file = forceFindOpenFileOrRead fileName
let! parseResult = checker.ParseFile(fileName, file.Lines, parseOpts)
let! ct = Async.CancellationToken
fileParsed.Trigger(parseResult, opts, ct)
return parseResult
}
|> Async.map Result.toOption)
|> Async.parallel75
|> Async.map (Array.Parallel.choose id)
|> Async.startImmediateAsTask ct
projects
|> Array.ofList
|> Array.Parallel.collect (fun p ->
let parseOpts = Utils.projectOptionsToParseOptions p
p.SourceFiles |> Array.map (fun s -> p, parseOpts, s))
|> Array.Parallel.map (fun (opts, parseOpts, fileName) ->
let fileName = UMX.tag fileName

asyncResult {
let! file = forceFindOpenFileOrRead fileName
return! parseFile checker file parseOpts opts
}
|> Async.map Result.toOption)
|> Async.parallel75
|> Async.map (Array.Parallel.choose id)

}

Expand Down Expand Up @@ -990,7 +1001,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
opts |> scriptFileProjectOptions.Trigger
return opts
}
// return Unchecked.defaultof<_>

return file, Option.toList projs
else
let! projs =
Expand Down Expand Up @@ -1049,7 +1060,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
let getAutoCompleteNamespacesByDeclName name =
autoCompleteNamespaces |> AMap.tryFind name

let analyzeFile config (filePath: string<LocalPath>, version, source, tyRes: ParseAndCheckResults) =
let analyzeFile config (filePath: string<LocalPath>, version, source: NamedText, tyRes: ParseAndCheckResults) =
let checkUnusedOpens =
async {
try
Expand Down Expand Up @@ -1079,7 +1090,8 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
let checkSimplifiedNames =
async {
try
let getSourceLine lineNo = source.GetLineString(lineNo - 1)
let getSourceLine lineNo =
(source: ISourceText).GetLineString(lineNo - 1)

let! ct = Async.CancellationToken
let! simplified = SimplifyNames.getSimplifiableNames (tyRes.GetCheckResults, getSourceLine)
Expand Down Expand Up @@ -1110,6 +1122,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
Version = version } }
}


/// <summary>Gets Parse and Check results of a given file while also handling other concerns like Progress, Logging, Eventing.</summary>
/// <param name="checker">The FSharpCompilerServiceChecker.</param>
/// <param name="file">The name of the file in the project whose source to find a typecheck.</param>
Expand Down Expand Up @@ -1206,9 +1219,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar

match! forceFindOpenFileOrRead filePath with
// Don't cache for autocompletions as we really only want to cache "Opened" files.
| Ok(fileInfo) ->
do! Async.SwitchToNewThread()
return! parseAndCheckFile checker fileInfo opts config false |> Async.Ignore
| Ok(fileInfo) -> return! parseAndCheckFile checker fileInfo opts config false |> Async.Ignore
| _ -> ()
with e ->

Expand All @@ -1233,15 +1244,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar

let parseOpts = Utils.projectOptionsToParseOptions opts

let! result =
checker.ParseFile(file, info.Lines, parseOpts)
return!
parseFile checker info parseOpts opts
|> Async.withCancellation cts.Token
|> fun work -> Async.StartImmediateAsTask(work, ctok)

fileParsed.Trigger(result, opts, cts.Token)
return result
|> Async.startImmediateAsTask ctok
}

})


Expand Down Expand Up @@ -1331,14 +1338,13 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
|> Result.ofOption (fun () -> $"No typecheck results for {filePath}")
|> async.Return

return!
return
tryGetLastCheckResultForFile filePath
|> AsyncResult.orElseWith (fun _ -> forceGetRecentTypeCheckResults filePath)
|> AsyncResult.orElseWith (fun _ -> forceGetTypeCheckResults filePath)
|> Async.map (fun r ->
Async.Start(forceGetTypeCheckResults filePath |> Async.Ignore)
r)
|> Async.StartImmediateAsTask
}
|> AsyncAVal.forceAsync

Expand Down Expand Up @@ -1740,9 +1746,6 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
percentage = percentage 0 checksToPerform.Length
)

let maxConcurrency =
Math.Max(1.0, Math.Floor((float System.Environment.ProcessorCount) * 0.75))

do! checksToPerform |> Async.parallel75 |> Async.Ignore<unit array>

}
Expand Down Expand Up @@ -4763,9 +4766,6 @@ module AdaptiveFSharpLspServer =
|> Map.add "fsproj/removeFile" (serverRequestHandling (fun s p -> s.FsProjRemoveFile(p)))

let adaptiveServer lspClient =
// match System.Threading.ThreadPool.GetMinThreads() with
// | _, completionPortThreads ->
// ThreadPool.SetMinThreads(System.Environment.ProcessorCount * 4, completionPortThreads) |> ignore
let loader = workspaceLoaderFactory toolsPath
new AdaptiveFSharpLspServer(loader, lspClient) :> IFSharpLspServer

Expand Down

0 comments on commit c5fb1f3

Please sign in to comment.