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
4 changes: 1 addition & 3 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.100.md
Original file line number Diff line number Diff line change
@@ -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 `[<ReflectedDefinition(true)>]` 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))
Expand Down Expand Up @@ -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))
Expand Down
6 changes: 5 additions & 1 deletion src/Compiler/Interactive/fsi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions tests/FSharp.Compiler.ComponentTests/Scripting/Interactive.fs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,40 @@ asm.GetCustomAttributes(typeof<System.Diagnostics.DebuggableAttribute>, 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)

[<Fact>]
let ``multi-emit PDB artifact is absent with --debug-`` () =
assertPdbArtifact "--debug-" false

[<Fact>]
let ``multi-emit PDB artifact is present with --debug+`` () =
assertPdbArtifact "--debug+" true

// https://github.com/dotnet/fsharp/issues/14454
[<FSharp.Test.FactForNETCOREAPP>]
let ``Issue 14454 - IAsyncDisposable use in task CE`` () =
Expand Down
Loading