Skip to content

Commit abffd37

Browse files
authored
Fix mixed emit-multi+/- sessions (#18465)
* Fix mixed emit-multi+/- sessions * fantomas * ilverify baseline
1 parent 172dc31 commit abffd37

File tree

9 files changed

+102
-43
lines changed

9 files changed

+102
-43
lines changed

docs/release-notes/.FSharp.Compiler.Service/9.0.300.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
* Make `[<CallerMemberName; Struct>]` combination work([PR #18444](https://github.com/dotnet/fsharp/pull/18444/))
3131
* Fix code completion considers types from own namespace non-imported ([PR #18518](https://github.com/dotnet/fsharp/issues/18518))
3232
* Code completion: fix getting qualifier expression in do statements in type decls ([PR #18524](https://github.com/dotnet/fsharp/pull/18524))
33+
* Fixed: [#18441](https://github.com/dotnet/fsharp/issues/18441) FSI multi-emit unstable. ([PR #18465](https://github.com/dotnet/fsharp/pull/18465))
3334

3435
### Added
3536
* Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241))

src/Compiler/Interactive/fsi.fs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,7 +1673,8 @@ let internal mkBoundValueTypedImpl tcGlobals m moduleName name ty =
16731673
let qname = QualifiedNameOfFile.QualifiedNameOfFile(Ident(moduleName, m))
16741674
entity, v, CheckedImplFile.CheckedImplFile(qname, [], mty, contents, false, false, StampMap.Empty, Map.empty)
16751675

1676-
let dynamicCcuName = "FSI-ASSEMBLY"
1676+
let dynamicCcuName (isEmitMulti) =
1677+
$"""FSI-ASSEMBLY{if isEmitMulti then "-MULTI" else ""}"""
16771678

16781679
/// Encapsulates the coordination of the typechecking, optimization and code generation
16791680
/// components of the F# compiler for interactively executed fragments of code.
@@ -1723,7 +1724,11 @@ type internal FsiDynamicCompiler
17231724
None
17241725
else
17251726
let assemBuilder, moduleBuilder =
1726-
mkDynamicAssemblyAndModule (dynamicCcuName, tcConfigB.optSettings.LocalOptimizationsEnabled, fsiCollectible)
1727+
mkDynamicAssemblyAndModule (
1728+
dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit),
1729+
tcConfigB.optSettings.LocalOptimizationsEnabled,
1730+
fsiCollectible
1731+
)
17271732

17281733
dynamicAssemblies.Add(assemBuilder)
17291734
Some(assemBuilder, moduleBuilder)
@@ -1813,7 +1818,7 @@ type internal FsiDynamicCompiler
18131818

18141819
let attrs =
18151820
[
1816-
tcGlobals.MakeInternalsVisibleToAttribute(dynamicCcuName)
1821+
tcGlobals.MakeInternalsVisibleToAttribute(dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit))
18171822
yield! manifest.CustomAttrs.AsList()
18181823
]
18191824

@@ -1960,7 +1965,9 @@ type internal FsiDynamicCompiler
19601965
diagnosticsLogger.AbortOnError(fsiConsoleOutput)
19611966

19621967
ReportTime tcConfig "Linking"
1963-
let ilxMainModule = CreateModuleFragment(tcConfigB, dynamicCcuName, codegenResults)
1968+
1969+
let ilxMainModule =
1970+
CreateModuleFragment(tcConfigB, dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit), codegenResults)
19641971

19651972
diagnosticsLogger.AbortOnError(fsiConsoleOutput)
19661973

@@ -2652,7 +2659,7 @@ type internal FsiDynamicCompiler
26522659

26532660
let tcEnv, asms =
26542661
try
2655-
RequireReferences(ctok, tcImports, tcState.TcEnvFromImpls, dynamicCcuName, resolutions)
2662+
RequireReferences(ctok, tcImports, tcState.TcEnvFromImpls, dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit), resolutions)
26562663
with _ ->
26572664
for (path, _, _, m) in refs do
26582665
tcConfigB.RemoveReferencedAssemblyByPath(m, path)
@@ -3025,7 +3032,7 @@ type internal FsiDynamicCompiler
30253032
let emEnv0 =
30263033
if tcConfigB.fsiMultiAssemblyEmit then
30273034
let emEnv =
3028-
ILMultiInMemoryAssemblyEmitEnv(ilGlobals, resolveAssemblyRef, dynamicCcuName)
3035+
ILMultiInMemoryAssemblyEmitEnv(ilGlobals, resolveAssemblyRef, dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit))
30293036

30303037
MultipleInMemoryAssemblies emEnv
30313038
else
@@ -3041,10 +3048,10 @@ type internal FsiDynamicCompiler
30413048
let emEnv = ILDynamicAssemblyWriter.emEnv0
30423049
SingleRefEmitAssembly(cenv, emEnv)
30433050

3044-
let tcEnv, openDecls0 =
3045-
GetInitialTcEnv(dynamicCcuName, rangeStdin0, tcConfig, tcImports, tcGlobals)
3051+
let ccuName = dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit)
30463052

3047-
let ccuName = dynamicCcuName
3053+
let tcEnv, openDecls0 =
3054+
GetInitialTcEnv(ccuName, rangeStdin0, tcConfig, tcImports, tcGlobals)
30483055

30493056
let tcState =
30503057
GetInitialTcState(rangeStdin0, ccuName, tcConfig, tcGlobals, tcImports, tcEnv, openDecls0)

tests/FSharp.Compiler.ComponentTests/Scripting/Interactive.fs

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ open Xunit
77
open System
88
open FSharp.Test.Compiler
99
open FSharp.Test.ScriptHelpers
10+
open FSharp.Compiler.Interactive.Shell
11+
open FSharp.Compiler.Diagnostics
12+
open FSharp.Test.CompilerAssertHelpers
1013

1114
module ``Interactive tests`` =
1215

@@ -35,34 +38,48 @@ module ``Interactive tests`` =
3538
]
3639

3740
[<Theory>]
38-
[<InlineData(true)>]
39-
[<InlineData(false)>]
40-
let ``Evaluation of multiple sessions should succeed`` (useMultiEmit) =
41+
[<InlineData(true, true)>]
42+
[<InlineData(false, false)>]
43+
[<InlineData(false, true)>]
44+
[<InlineData(true, false)>]
45+
let ``Evaluation of multiple sessions should succeed`` (useMultiEmit1, useMultiEmit2) =
4146

42-
let args : string array = [| if useMultiEmit then "--multiemit+" else "--multiemit-"|]
43-
use sessionOne = new FSharpScript(additionalArgs=args)
44-
use sessionTwo = new FSharpScript(additionalArgs=args)
47+
// This test is to check that we can have multiple sessions and that they can access each other
4548

46-
sessionOne.Eval("""
47-
module Test1 =
49+
let AssertCanWeAccessTheOtherSession (session: FSharpScript) (script: string) (moduleName: string) (errorChoice: string) =
4850

49-
let test1 obj = sprintf "Execute - Test1.test1 - %A" obj""") |> ignore
51+
let result: Result<FsiValue option, exn> * FSharpDiagnostic[] = session.Eval(script)
52+
let expected =
53+
[ (Error 39, Line 1, Col 1, Line 1, Col 6, $"The value, namespace, type or module '{moduleName}' is not defined. Maybe you want one of the following:{errorChoice}") ]
5054

51-
let result1 = sessionOne.Eval("""Test1.test1 18""") |> getValue
55+
match result with
56+
| Result.Error _, diagnostics -> Assert.WithDiagnostics(0, diagnostics, expected)
57+
| _ -> ()
58+
59+
// Initialize
60+
let args useMultiEmit : string array = [| if useMultiEmit then "--multiemit+" else "--multiemit-"|]
61+
use sessionOne = new FSharpScript(additionalArgs = args useMultiEmit1)
62+
use sessionTwo = new FSharpScript(additionalArgs = args useMultiEmit2)
63+
use sessionThree = new FSharpScript(additionalArgs = args useMultiEmit2)
64+
65+
// First session
66+
sessionOne.Eval("""module Test1 = let test1 obj = sprintf "Execute - Test1.test1 - %A" obj""") |> ignore
67+
let result1 = sessionOne.Eval("Test1.test1 18") |> getValue
5268
let value1 = result1.Value
5369
Assert.Equal(typeof<string>, value1.ReflectionType)
5470
Assert.Equal("Execute - Test1.test1 - 18", value1.ReflectionValue :?> string)
5571

56-
sessionTwo.Eval("""
57-
module Test2 =
58-
59-
let test2 obj = sprintf "Execute - Test2.test2 - %A" obj""") |> ignore
60-
72+
// Second session
73+
sessionTwo.Eval("""module Test2 = let test2 obj = sprintf "Execute - Test2.test2 - %A" obj""") |> ignore
6174
let result2 = sessionTwo.Eval("""Test2.test2 27""") |> getValue
6275
let value2 = result2.Value
6376
Assert.Equal(typeof<string>, value2.ReflectionType)
6477
Assert.Equal("Execute - Test2.test2 - 27", value2.ReflectionValue :?> string)
6578

79+
// Can I access the other session
80+
AssertCanWeAccessTheOtherSession sessionOne "Test2.test2 19" "Test2" "\nTest1\nText" // Session 1 can't access values from session 2
81+
AssertCanWeAccessTheOtherSession sessionTwo "Test1.test1 13" "Test1" "\nTest2\nText" // Session 2 can't access values from session 1
82+
6683
module ``External FSI tests`` =
6784
[<Fact>]
6885
let ``Eval object value``() =

tests/FSharp.Test.Utilities/Compiler.fs

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,20 +1671,47 @@ Actual:
16711671
let private withResultIgnoreNativeRange (expectedResult: ErrorInfo ) (result: CompilationResult) : CompilationResult =
16721672
withResultsIgnoreNativeRange [expectedResult] result
16731673

1674-
let withDiagnostics (expected: (ErrorType * Line * Col * Line * Col * string) list) (result: CompilationResult) : CompilationResult =
1675-
let expectedResults: ErrorInfo list =
1676-
[ for e in expected do
1677-
let (error, Line startLine, Col startCol, Line endLine, Col endCol, message) = e
1678-
{ Error = error
1679-
Range =
1680-
{ StartLine = startLine
1681-
StartColumn = startCol
1682-
EndLine = endLine
1683-
EndColumn = endCol }
1684-
NativeRange = Unchecked.defaultof<_>
1685-
SubCategory = ""
1686-
Message = message } ]
1687-
withResultsIgnoreNativeRange expectedResults result
1674+
let private convertExpectedsToErrorInfos(expected: (ErrorType * Line * Col * Line * Col * string) list): ErrorInfo list = [
1675+
for e in expected do
1676+
let (error, Line startLine, Col startCol, Line endLine, Col endCol, message) = e
1677+
{
1678+
Error = error
1679+
Range = {
1680+
StartLine = startLine
1681+
StartColumn = startCol
1682+
EndLine = endLine
1683+
EndColumn = endCol
1684+
}
1685+
NativeRange = Unchecked.defaultof<_>
1686+
SubCategory = ""
1687+
Message = message
1688+
}
1689+
]
1690+
1691+
let private convertDiagnosticsToErrorInfos (diagnostics: FSharpDiagnostic[]) : ErrorInfo list =
1692+
diagnostics
1693+
|> Array.map (fun diagnostic ->
1694+
let errorType =
1695+
match diagnostic.Severity with
1696+
| FSharpDiagnosticSeverity.Error -> Error diagnostic.ErrorNumber
1697+
| FSharpDiagnosticSeverity.Warning -> Warning diagnostic.ErrorNumber
1698+
| FSharpDiagnosticSeverity.Info -> Information diagnostic.ErrorNumber
1699+
| FSharpDiagnosticSeverity.Hidden -> Hidden diagnostic.ErrorNumber
1700+
{
1701+
Error = errorType
1702+
Range = {
1703+
StartLine = diagnostic.StartLine
1704+
StartColumn = diagnostic.StartColumn
1705+
EndLine = diagnostic.EndLine
1706+
EndColumn = diagnostic.EndColumn
1707+
}
1708+
NativeRange = diagnostic.Range
1709+
Message = diagnostic.Message
1710+
SubCategory = diagnostic.Subcategory
1711+
}) |> Array.toList
1712+
1713+
let withDiagnostics expected (result: CompilationResult) : CompilationResult =
1714+
withResultsIgnoreNativeRange (convertExpectedsToErrorInfos expected) result
16881715

16891716
let withSingleDiagnostic (expected: (ErrorType * Line * Col * Line * Col * string)) (result: CompilationResult) : CompilationResult =
16901717
withDiagnostics [expected] result
@@ -1695,6 +1722,10 @@ Actual:
16951722
let withError (expectedError: ErrorInfo) (result: CompilationResult) : CompilationResult =
16961723
withErrors [expectedError] result
16971724

1725+
type Assert =
1726+
static member WithDiagnostics(libAdjust, result, expected) =
1727+
assertErrors "Results" libAdjust (convertDiagnosticsToErrorInfos result) (convertExpectedsToErrorInfos expected)
1728+
16981729
module StructuredResultsAsserts =
16991730
type SimpleErrorInfo =
17001731
{ Error: ErrorType

tests/FSharp.Test.Utilities/CompilerAssert.fs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ module CompilerAssertHelpers =
466466
yield source.WithFileName(destFileName)
467467
]
468468
rawCompile outputFilePath isExe options targetFramework sources
469-
469+
470470
let assertErrors libAdjust ignoreWarnings (errors: FSharpDiagnostic []) expectedErrors =
471471
let errorMessage (error: FSharpDiagnostic) =
472472
let errN, range, message = error.ErrorNumber, error.Range, error.Message
@@ -694,6 +694,9 @@ Updated automatically, please check diffs in your pull request, changes must be
694694
compileCompilation ignoreWarnings cmpl (fun ((errors, _, _), _) ->
695695
assertErrors 0 ignoreWarnings errors expectedErrors)
696696

697+
static member assertWithErrors(libAdjust, ignoreWarnings, errors, expectedErrors) =
698+
assertErrors libAdjust, ignoreWarnings, errors, expectedErrors
699+
697700
static member Compile(cmpl: Compilation, ?ignoreWarnings) =
698701
CompilerAssert.CompileWithErrors(cmpl, [||], defaultArg ignoreWarnings false)
699702

tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
[IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack.
2222
[IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack.
2323
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack.
24-
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3502-805::Invoke([S.P.CoreLib]System.Tuple`3<char[],int32,int32>)][offset 0x000001E5][found Char] Unexpected type on the stack.
24+
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3509-805::Invoke([S.P.CoreLib]System.Tuple`3<char[],int32,int32>)][offset 0x000001E5][found Char] Unexpected type on the stack.
2525
[IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type.
2626
[IL]: Error [StackUnexpected]: : <StartupCode$FSharp-Compiler-Service>.$FSharpCheckerResults+dataTipOfReferences@2225::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack.
2727
[IL]: Error [StackUnexpected]: : <StartupCode$FSharp-Compiler-Service>.$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<System.Tuple`3<FSharp.Compiler.Parser+token,int32,int32>,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack.

tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
[IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack.
2929
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000039][found Char] Unexpected type on the stack.
3030
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack.
31-
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3502-805::Invoke([S.P.CoreLib]System.Tuple`3<char[],int32,int32>)][offset 0x000001E5][found Char] Unexpected type on the stack.
31+
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3509-805::Invoke([S.P.CoreLib]System.Tuple`3<char[],int32,int32>)][offset 0x000001E5][found Char] Unexpected type on the stack.
3232
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x0000001B][found Char] Unexpected type on the stack.
3333
[IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type.
3434
[IL]: Error [StackUnexpected]: : <StartupCode$FSharp-Compiler-Service>.$FSharpCheckerResults+dataTipOfReferences@2225::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack.

tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
[IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack.
2222
[IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack.
2323
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack.
24-
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3502-849::Invoke([S.P.CoreLib]System.Tuple`3<char[],int32,int32>)][offset 0x000001C7][found Char] Unexpected type on the stack.
24+
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3509-849::Invoke([S.P.CoreLib]System.Tuple`3<char[],int32,int32>)][offset 0x000001C7][found Char] Unexpected type on the stack.
2525
[IL]: Error [StackUnexpected]: : <StartupCode$FSharp-Compiler-Service>.$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2225::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack.
2626
[IL]: Error [StackUnexpected]: : <StartupCode$FSharp-Compiler-Service>.$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<System.Tuple`3<FSharp.Compiler.Parser+token,int32,int32>,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack.
2727
[IL]: Error [StackUnexpected]: : <StartupCode$FSharp-Compiler-Service>.$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<System.Tuple`3<FSharp.Compiler.Parser+token,int32,int32>,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack.

0 commit comments

Comments
 (0)