diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index e0ac30372fe..f02f04c8dcf 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,9 +1,8 @@ ### Fixed +* Fix FSI `--multiemit+ --debug-` unnecessarily generating and loading portable PDB data for every submission. ([Issue #17306](https://github.com/dotnet/fsharp/issues/17306), [PR #20394](https://github.com/dotnet/fsharp/pull/20394), [downstream report](https://github.com/bryanedds/Nu/issues/1090)) * Fix reference-assembly MVID collisions when a public member is renamed in an early file of a large (>~32 file) project under `--optimize-`. The per-file signature hashes were folded with a left-shift-by-one combiner over a 32-bit `Hash`, which truncated the contribution of any file more than ~32 positions from the end of the compile order, so MSBuild's `CopyRefAssembly` saw an unchanged MVID and kept a stale reference assembly (surfacing as `FS0039` downstream). The combiner is now an FNV-1a multiply mix over a 64-bit `Hash`. ([Issue #20389](https://github.com/dotnet/fsharp/issues/20389)) * Fix internal error FS0192 "Iterate2D" when a `[]` parameter auto-quotes an argument that captures a not-yet-generalized use of an inferred generically-recursive function. The auto-quoted (`Expr.WithValue`) copy now keeps a fresh link to the recursive-value use so it receives the same inferred type arguments as the executable expression at the letrec point. ([Issue #20379](https://github.com/dotnet/fsharp/issues/20379)) -* Fix `StackOverflowException` when checking a long `seq { ... }` body. The `expr; expr; ...` spine of a sequence expression was recursed without a stack guard, and the post-inference `CheckNoReraise` walked the resulting right-nested `Seq.append`/`Seq.delay` tree with unguarded free-variable options, so a few hundred (Debug) to a few thousand (Release) implicit-yield elements overflowed a 1 MB thread-pool thread in the IDE. `tcSequenceExprBodyAsSequenceOrStatement` now runs under `cenv.stackGuard` and `CheckNoReraise` uses `CollectLocalsWithStackGuard`. -* Fix `StackOverflowException` when checking a long `seq { ... }` body. The `expr; expr; ...` spine of a sequence expression was recursed without a stack guard, and the post-inference `CheckNoReraise` walked the resulting right-nested `Seq.append`/`Seq.delay` tree with unguarded free-variable options, so a few hundred (Debug) to a few thousand (Release) implicit-yield elements overflowed a 1 MB thread-pool thread in the IDE. `tcSequenceExprBodyAsSequenceOrStatement` now runs under `cenv.stackGuard` and `CheckNoReraise` uses `CollectLocalsWithStackGuard`. ([PR #20480](https://github.com/dotnet/fsharp/pull/20480)) * Fix `StackOverflowException` when checking a long `seq { ... }` body. ([PR #20480](https://github.com/dotnet/fsharp/pull/20480)) * Fix `NativePtr.stackalloc` nested in a larger expression (e.g. a call argument or the right of an assignment) producing an assembly that throws `InvalidProgramException` at load. ([Issue #8083](https://github.com/dotnet/fsharp/issues/8083), [PR #20302](https://github.com/dotnet/fsharp/pull/20302)) * Fix internal error "Unexpected generalized type variables when compiling an active pattern" when an active pattern is used in a `let` binding whose right-hand side is a generic value, e.g. `let (T) = id`. Such a binding is now checked like the equivalent `match` and is not generalized. ([Issue #16856](https://github.com/dotnet/fsharp/issues/16856), [PR #20383](https://github.com/dotnet/fsharp/pull/20383)) @@ -44,7 +43,6 @@ * Fix `TypeLoadException` ("Specialize tried to implicitly override a method with weaker type parameter constraints") and the related CLR crash with constrained inline calls by stripping constraints from closure-class typars in `EraseClosures.convIlxClosureDef`. ([Issue #14492](https://github.com/dotnet/fsharp/issues/14492), [Issue #19075](https://github.com/dotnet/fsharp/issues/19075), [PR #19882](https://github.com/dotnet/fsharp/pull/19882)) * Fix FS0073 during code generation when closure generic arguments contain an unsolved type variable. ([PR #20229](https://github.com/dotnet/fsharp/pull/20229)) * Fix `FieldAccessException` at runtime when the optimizer relocates a read of a `protected` (family) base-class field into a method outside the field's family (e.g. a trivial member inlined into module/startup code under `--optimize+`). Protected (family) IL field access is no longer hoisted out of its declaring family by inlining or method-splitting. ([Issue #19963](https://github.com/dotnet/fsharp/issues/19963), [PR #19964](https://github.com/dotnet/fsharp/pull/19964)) - * Suppress hover/symbol resolution for wildcard `_` patterns inside `member _.…` bodies that incorrectly showed `val _: T` tooltip. ([PR #19760](https://github.com/dotnet/fsharp/pull/19760)) * Report `seq { }` implicit-yield diagnostics and format specifier locations once instead of twice: the classification pass that decides whether the body is a statement or a yielded element no longer double-reports to the sink or diagnostics. ([Issue #16419](https://github.com/dotnet/fsharp/issues/16419), [PR #19791](https://github.com/dotnet/fsharp/pull/19791), [PR #19895](https://github.com/dotnet/fsharp/pull/19895)) * Stabilize codegen order under `--parallelcompilation+` so `--deterministic` Release builds produce byte-identical IL across rebuilds: optimizer Val iteration, IlxGen type/method/field/event emit order, anonymous-record extra-binding drain, and `FileIndex` assignment now follow source position rather than thread-scheduling order. ([Issue #19732](https://github.com/dotnet/fsharp/issues/19732), [PR #19810](https://github.com/dotnet/fsharp/pull/19810)) diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 436d0a0c777..ce2ec781e91 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -1949,7 +1949,11 @@ type internal FsiDynamicCompiler { ilg = tcGlobals.ilg outfile = $"{multiAssemblyName}-{dynamicAssemblyId}.dll" - pdbfile = Some(Path.Combine(scriptingSymbolsPath, $"{multiAssemblyName}-{dynamicAssemblyId}.pdb")) + pdbfile = + if tcConfig.debuginfo then + Some(Path.Combine(scriptingSymbolsPath, $"{multiAssemblyName}-{dynamicAssemblyId}.pdb")) + else + None emitTailcalls = tcConfig.emitTailcalls deterministic = tcConfig.deterministic portablePDB = true diff --git a/tests/FSharp.Compiler.ComponentTests/Scripting/Interactive.fs b/tests/FSharp.Compiler.ComponentTests/Scripting/Interactive.fs index cb797572366..da5ef2a3e2b 100644 --- a/tests/FSharp.Compiler.ComponentTests/Scripting/Interactive.fs +++ b/tests/FSharp.Compiler.ComponentTests/Scripting/Interactive.fs @@ -359,6 +359,40 @@ asm.GetCustomAttributes(typeof, false) Assert.Equal(1, flags.Length) + module PortablePdb = + + let private getPrivateField (instance: obj) fieldName ownerName = + let flags = System.Reflection.BindingFlags.Instance ||| System.Reflection.BindingFlags.NonPublic + let field = instance.GetType().GetField(fieldName, flags) + Assert.True(not (isNull field), $"Could not find private field '{fieldName}' on {ownerName}") + field.GetValue(instance) + + let private assertPdbArtifact debugOption expectPdb = + let args: string array = [| "--multiemit+"; debugOption |] + use session = new FSharpScript(additionalArgs = args) + + let dynamicCompiler = getPrivateField session.Fsi "fsiDynamicCompiler" "FsiEvaluationSession" + let symbolsPath = getPrivateField dynamicCompiler "scriptingSymbolsPath" "FsiDynamicCompiler" :?> string + let _, errors = session.Eval("let submittedValue = 1") + + Assert.Empty(errors) + Assert.True(System.IO.Directory.Exists(symbolsPath), $"FSI symbol directory does not exist: {symbolsPath}") + + let pdbFiles = System.IO.Directory.GetFiles(symbolsPath, "*.pdb") + + if expectPdb then + Assert.NotEmpty(pdbFiles) + else + Assert.Empty(pdbFiles) + + [] + let ``multi-emit PDB artifact is absent with --debug-`` () = + assertPdbArtifact "--debug-" false + + [] + let ``multi-emit PDB artifact is present with --debug+`` () = + assertPdbArtifact "--debug+" true + // https://github.com/dotnet/fsharp/issues/14454 [] let ``Issue 14454 - IAsyncDisposable use in task CE`` () =