@@ -22,6 +22,7 @@ open Microsoft.VisualStudio.Shell.Interop
2222open Microsoft.VisualStudio .LanguageServices .Implementation .TaskList
2323open Microsoft.CodeAnalysis .ExternalAccess .FSharp .LanguageServices
2424open Microsoft.VisualStudio .FSharp .Interactive .Session
25+ open System.Runtime .CompilerServices
2526
2627[<AutoOpen>]
2728module private FSharpProjectOptionsHelpers =
@@ -65,7 +66,16 @@ module private FSharpProjectOptionsHelpers =
6566 let doesProjectIdDiffer = p1.ProjectId <> p2.ProjectId
6667 let p1 = oldProject.Solution.GetProject( p1.ProjectId)
6768 let p2 = newProject.Solution.GetProject( p2.ProjectId)
68- doesProjectIdDiffer || p1.Version <> p2.Version
69+ doesProjectIdDiffer ||
70+ (
71+ // For F# projects, just check the version until we have a better in-memory model for them.
72+ if p1.Language = LanguageNames.FSharp then
73+ p1.Version <> p2.Version
74+ else
75+ let v1 = p1.GetDependentVersionAsync( ct) .Result
76+ let v2 = p2.GetDependentVersionAsync( ct) .Result
77+ v1 <> v2
78+ )
6979 )
7080
7181 let isProjectInvalidated ( oldProject : Project ) ( newProject : Project ) ( settings : EditorOptions ) ct =
@@ -94,6 +104,26 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor
94104 let cache = ConcurrentDictionary< ProjectId, Project * FSharpParsingOptions * FSharpProjectOptions>()
95105 let singleFileCache = ConcurrentDictionary< DocumentId, VersionStamp * FSharpParsingOptions * FSharpProjectOptions>()
96106
107+ // This is used to not constantly emit the same compilation.
108+ let weakPEReferences = ConditionalWeakTable< Compilation, FSharpReferencedProject>()
109+
110+ let createPEReference ( referencedProject : Project ) ( comp : Compilation ) ct =
111+ match weakPEReferences.TryGetValue comp with
112+ | true , fsRefProj -> fsRefProj
113+ | _ ->
114+ let fsRefProj =
115+ FSharpReferencedProject.CreatePortableExecutable(
116+ referencedProject.OutputFilePath,
117+ DateTime.UtcNow,
118+ let ms = new MemoryStream() // do not dispose the stream as it will be owned on the reference.
119+ let emitOptions = Emit.EmitOptions( metadataOnly = true , includePrivateMembers = false , tolerateErrors = true )
120+ comp.Emit( ms, options = emitOptions, cancellationToken = ct) |> ignore
121+ ms.Position <- 0 L
122+ ms
123+ )
124+ weakPEReferences.Add( comp, fsRefProj)
125+ fsRefProj
126+
97127 let rec tryComputeOptionsByFile ( document : Document ) ( ct : CancellationToken ) userOpName =
98128 async {
99129 let! fileStamp = document.GetTextVersionAsync( ct) |> Async.AwaitTask
@@ -170,7 +200,11 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor
170200 if referencedProject.Language = FSharpConstants.FSharpLanguageName then
171201 match ! tryComputeOptions referencedProject ct with
172202 | None -> canBail <- true
173- | Some(_, projectOptions) -> referencedProjects.Add( referencedProject.OutputFilePath, projectOptions)
203+ | Some(_, projectOptions) -> referencedProjects.Add( FSharpReferencedProject.CreateFSharp( referencedProject.OutputFilePath, projectOptions))
204+ else
205+ let! comp = referencedProject.GetCompilationAsync( ct) |> Async.AwaitTask
206+ let peRef = createPEReference referencedProject comp ct
207+ referencedProjects.Add( peRef)
174208
175209 if canBail then
176210 return None
0 commit comments