diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index e6b2775961..187806bfe9 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -3115,6 +3115,9 @@ type internal FsiDynamicCompiler member _.ValueBound = valueBoundEvent.Publish + member _.PeekNextFragmentPath() = + FsiDynamicModulePrefix + $"%04d{fragmentId + 1}" + //---------------------------------------------------------------------------- // ctrl-c handling //---------------------------------------------------------------------------- @@ -4484,13 +4487,25 @@ type FsiInteractionProcessor let names = names |> List.filter (fun name -> name.StartsWithOrdinal(stem)) names - member _.ParseAndCheckInteraction(legacyReferenceResolver, istate, text: string) = + member _.ParseAndCheckInteraction(legacyReferenceResolver, istate, text: string, ?keepAssemblyContents: bool) = let tcConfig = TcConfig.Create(tcConfigB, validate = false) + let asmName = + match keepAssemblyContents with + | Some true -> Some(fsiDynamicCompiler.PeekNextFragmentPath()) + | _ -> None + let fsiInteractiveChecker = - FsiInteractiveChecker(legacyReferenceResolver, tcConfig, istate.tcGlobals, istate.tcImports, istate.tcState) + FsiInteractiveChecker( + legacyReferenceResolver, + tcConfig, + istate.tcGlobals, + istate.tcImports, + istate.tcState, + ?keepAssemblyContents = keepAssemblyContents + ) - fsiInteractiveChecker.ParseAndCheckInteraction(SourceText.ofString text) + fsiInteractiveChecker.ParseAndCheckInteraction(SourceText.ofString text, ?asmName = asmName) //---------------------------------------------------------------------------- // Server mode: @@ -4842,8 +4857,13 @@ type FsiEvaluationSession fsiInteractionProcessor.CompletionsForPartialLID(fsiInteractionProcessor.CurrentState, longIdent) |> Seq.ofList - member _.ParseAndCheckInteraction(code) = - fsiInteractionProcessor.ParseAndCheckInteraction(legacyReferenceResolver, fsiInteractionProcessor.CurrentState, code) + member _.ParseAndCheckInteraction(code, ?keepAssemblyContents) = + fsiInteractionProcessor.ParseAndCheckInteraction( + legacyReferenceResolver, + fsiInteractionProcessor.CurrentState, + code, + ?keepAssemblyContents = keepAssemblyContents + ) |> Cancellable.runWithoutCancellation member _.InteractiveChecker = checker diff --git a/src/Compiler/Interactive/fsi.fsi b/src/Compiler/Interactive/fsi.fsi index eebef0e63d..14bda032a7 100644 --- a/src/Compiler/Interactive/fsi.fsi +++ b/src/Compiler/Interactive/fsi.fsi @@ -276,13 +276,20 @@ type FsiEvaluationSession = /// This event is triggered after parsing and checking, either via input from 'stdin', or via a call to EvalInteraction. member PartialAssemblySignatureUpdated: IEvent - /// Typecheck the given script fragment in the type checking context implied by the current state - /// of F# Interactive. The results can be used to access intellisense, perform resolutions, - /// check brace matching and other information. + /// + /// Typecheck the given script fragment in the type checking context implied by the current state + /// of F# Interactive. The results can be used to access intellisense, perform resolutions, + /// check brace matching and other information. Accessing assembly contents need 'keepAssemblyContents' + /// set to 'true'. + /// + /// Operations may be run concurrently with other requests to the InteractiveChecker. + /// /// - /// Operations may be run concurrently with other requests to the InteractiveChecker. + /// Source code of the interaction to check. + /// Keep the checked contents of the interaction. member ParseAndCheckInteraction: - code: string -> FSharpParseFileResults * FSharpCheckFileResults * FSharpCheckProjectResults + code: string * ?keepAssemblyContents: bool -> + FSharpParseFileResults * FSharpCheckFileResults * FSharpCheckProjectResults /// The single, global interactive checker to use in conjunction with other operations /// on the FsiEvaluationSession. diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 873d688c17..ca4284e004 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -3986,14 +3986,16 @@ type FSharpCheckProjectResults override _.ToString() = "FSharpCheckProjectResults(" + projectFileName + ")" -type FsiInteractiveChecker(legacyReferenceResolver, tcConfig: TcConfig, tcGlobals: TcGlobals, tcImports: TcImports, tcState) = +type FsiInteractiveChecker + (legacyReferenceResolver, tcConfig: TcConfig, tcGlobals: TcGlobals, tcImports: TcImports, tcState, ?keepAssemblyContents: bool) = - let keepAssemblyContents = false + let keepAssemblyContents = defaultArg keepAssemblyContents false - member _.ParseAndCheckInteraction(sourceText: ISourceText, ?userOpName: string) = + member _.ParseAndCheckInteraction(sourceText: ISourceText, ?userOpName: string, ?asmName: string) = cancellable { let userOpName = defaultArg userOpName "Unknown" - let fileName = Path.Combine(tcConfig.implicitIncludeDir, "stdin.fsx") + let asmName = defaultArg asmName "stdin" + let fileName = Path.Combine(tcConfig.implicitIncludeDir, asmName + ".fsx") let suggestNamesForErrors = true // Will always be true, this is just for readability // Note: projectSourceFiles is only used to compute isLastCompiland, and is ignored if Build.IsScript(mainInputFileName) is true (which it is in this case). let parsingOptions = @@ -4083,6 +4085,12 @@ type FsiInteractiveChecker(legacyReferenceResolver, tcConfig: TcConfig, tcGlobal let typeCheckResults = FSharpCheckFileResults(fileName, errors, Some tcFileInfo, dependencyFiles, None, false) + let checkedImplFiles = + if keepAssemblyContents then + tcFileInfo.ImplementationFile |> Option.map List.singleton + else + None + let details = (tcGlobals, tcImports, @@ -4091,9 +4099,9 @@ type FsiInteractiveChecker(legacyReferenceResolver, tcConfig: TcConfig, tcGlobal Choice2Of2(tcFileInfo.ScopeSymbolUses |> Seq.singleton |> async.Return), None, (fun () -> None), - mkSimpleAssemblyRef "stdin", + mkSimpleAssemblyRef asmName, tcState.TcEnvFromImpls.AccessRights, - None, + checkedImplFiles, dependencyFiles, Some projectOptions) diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi index 7417aacb82..227826a997 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fsi +++ b/src/Compiler/Service/FSharpCheckerResults.fsi @@ -620,11 +620,16 @@ module internal ParseAndCheckFile = // Used internally to provide intellisense over F# Interactive. type internal FsiInteractiveChecker = internal new: - LegacyReferenceResolver * tcConfig: TcConfig * tcGlobals: TcGlobals * tcImports: TcImports * tcState: TcState -> + LegacyReferenceResolver * + tcConfig: TcConfig * + tcGlobals: TcGlobals * + tcImports: TcImports * + tcState: TcState * + ?keepAssemblyContents: bool -> FsiInteractiveChecker member internal ParseAndCheckInteraction: - sourceText: ISourceText * ?userOpName: string -> + sourceText: ISourceText * ?userOpName: string * ?asmName: string -> Cancellable module internal FSharpCheckerResultsSettings = 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 e98b4ec609..928a099152 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 @@ -4986,7 +4986,7 @@ FSharp.Compiler.Interactive.Shell+FsiEvaluationSession: System.Tuple`2[Microsoft FSharp.Compiler.Interactive.Shell+FsiEvaluationSession: System.Tuple`2[Microsoft.FSharp.Core.FSharpChoice`2[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Interactive.Shell+FsiValue],System.Exception],FSharp.Compiler.Diagnostics.FSharpDiagnostic[]] EvalInteractionNonThrowing(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken]) FSharp.Compiler.Interactive.Shell+FsiEvaluationSession: System.Tuple`2[Microsoft.FSharp.Core.FSharpChoice`2[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Interactive.Shell+FsiValue],System.Exception],FSharp.Compiler.Diagnostics.FSharpDiagnostic[]] EvalInteractionNonThrowing(System.String, System.String, Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken]) FSharp.Compiler.Interactive.Shell+FsiEvaluationSession: System.Tuple`2[Microsoft.FSharp.Core.FSharpChoice`2[Microsoft.FSharp.Core.Unit,System.Exception],FSharp.Compiler.Diagnostics.FSharpDiagnostic[]] EvalScriptNonThrowing(System.String) -FSharp.Compiler.Interactive.Shell+FsiEvaluationSession: System.Tuple`3[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults] ParseAndCheckInteraction(System.String) +FSharp.Compiler.Interactive.Shell+FsiEvaluationSession: System.Tuple`3[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults] ParseAndCheckInteraction(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) FSharp.Compiler.Interactive.Shell+FsiEvaluationSession: Void AddBoundValue(System.String, System.Object) FSharp.Compiler.Interactive.Shell+FsiEvaluationSession: Void EvalInteraction(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken]) FSharp.Compiler.Interactive.Shell+FsiEvaluationSession: Void EvalInteraction(System.String, System.String, Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken])