Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/Compiler/Facilities/BuildGraph.fs
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,14 @@ module GraphNode =
| None -> ()

[<Sealed>]
type GraphNode<'T>(retryCompute: bool, computation: NodeCode<'T>) =
type GraphNode<'T> private (retryCompute: bool, computation: NodeCode<'T>, cachedResult: Task<'T>, cachedResultNode: NodeCode<'T>) =

let gate = obj ()
let mutable computation = computation
let mutable requestCount = 0

let mutable cachedResult: Task<'T> = Unchecked.defaultof<_>
let mutable cachedResultNode: NodeCode<'T> = Unchecked.defaultof<_>
let mutable cachedResult: Task<'T> = cachedResult
let mutable cachedResultNode: NodeCode<'T> = cachedResultNode

let isCachedResultNodeNotNull () =
not (obj.ReferenceEquals(cachedResultNode, null))
Expand Down Expand Up @@ -429,4 +429,9 @@ type GraphNode<'T>(retryCompute: bool, computation: NodeCode<'T>) =

member _.IsComputing = requestCount > 0

static member FromResult(result: 'T) =
let nodeResult = node.Return result
GraphNode(true, nodeResult, Task.FromResult(result), nodeResult)

new(retryCompute: bool, computation) = GraphNode(retryCompute, computation, Unchecked.defaultof<_>, Unchecked.defaultof<_>)
new(computation) = GraphNode(retryCompute = true, computation = computation)
3 changes: 3 additions & 0 deletions src/Compiler/Facilities/BuildGraph.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ type internal GraphNode<'T> =
/// By default, 'retryCompute' is 'true'.
new: computation: NodeCode<'T> -> GraphNode<'T>

/// Creates a GraphNode with given result already cached.
static member FromResult: 'T -> 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.
Expand Down
6 changes: 3 additions & 3 deletions src/Compiler/Service/IncrementalBuild.fs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ type TcInfoNode =
static member FromState(state: TcInfoState) =
let tcInfo = state.TcInfo
let tcInfoExtras = state.TcInfoExtras
TcInfoNode(GraphNode(node.Return tcInfo), GraphNode(node.Return (tcInfo, defaultArg tcInfoExtras emptyTcInfoExtras)))
TcInfoNode(GraphNode.FromResult tcInfo, GraphNode.FromResult (tcInfo, defaultArg tcInfoExtras emptyTcInfoExtras))

/// Bound model of an underlying syntax and typed tree.
[<Sealed>]
Expand Down Expand Up @@ -1098,7 +1098,7 @@ module IncrementalBuilderStateHelpers =
| ValueSome(boundModel) when initialState.enablePartialTypeChecking && boundModel.BackingSignature.IsSome ->
let newBoundModel = boundModel.ClearTcInfoExtras()
{ state with
boundModels = state.boundModels.SetItem(slot, GraphNode(node.Return newBoundModel))
boundModels = state.boundModels.SetItem(slot, GraphNode.FromResult newBoundModel)
stampedFileNames = state.stampedFileNames.SetItem(slot, stamp)
}
| _ ->
Expand Down Expand Up @@ -1165,7 +1165,7 @@ type IncrementalBuilderState with
let referencedAssemblies = initialState.referencedAssemblies

let cache = TimeStampCache(defaultTimeStamp)
let initialBoundModel = GraphNode(node.Return initialBoundModel)
let initialBoundModel = GraphNode.FromResult initialBoundModel
let boundModels = ImmutableArrayBuilder.create fileNames.Length

for slot = 0 to fileNames.Length - 1 do
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Service/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ type BackgroundCompiler
let createBuilderNode (options, userOpName, ct: CancellationToken) =
lock gate (fun () ->
if ct.IsCancellationRequested then
GraphNode(node.Return(None, [||]))
GraphNode.FromResult(None, [||])
else
let getBuilderNode = GraphNode(CreateOneIncrementalBuilder(options, userOpName))
incrementalBuildersCache.Set(AnyCallerThread, options, getBuilderNode)
Expand Down
7 changes: 7 additions & 0 deletions tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,10 @@ module BuildGraphTests =
tasks
|> Seq.iter (fun x ->
try x.Wait(1000) |> ignore with | :? TimeoutException -> reraise() | _ -> ())

[<Fact>]
let ``GraphNode created from an already computed result will return it in tryPeekValue`` () =
let graphNode = GraphNode.FromResult 1

Assert.shouldBeTrue graphNode.HasValue
Assert.shouldBe (ValueSome 1) (graphNode.TryPeekValue())