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
13 changes: 2 additions & 11 deletions azure-pipelines-PR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,17 +124,8 @@ stages:
- script: .\eng\common\dotnet.cmd
- script: .\eng\test-determinism.cmd -configuration Release
displayName: Determinism tests (race detector — same flags both builds)
# Hard gate: any non-determinism between two same-flags Release builds fails CI.
# The single known-racy binary, FSharp.Compiler.Service.dll, is excluded via the
# skipList in eng/test-determinism.ps1 — its residual parallel-optimizer
# newUnique() closure-name race (func2@1-N suffix permutation) is tracked in
# #19928 and fixed by #19929 (always-defer + source-stable closure naming).
# #19810 fixes the structural/heap-order races (#1-7), which are deterministic.
# #19929 removes the skip and restores full coverage once the closure race lands.
# The seq-vs-par leg is intentionally NOT here. It catches a deeper architectural
# issue with parallel optimizer's newUnique() race leaking into closure type names —
# see #19928 / #19929. Same-flags Release-mode determinism (the original #19732 ask)
# fixes the structural races here; the residual closure-name race is fixed in #19929.
- script: .\eng\test-determinism.cmd -configuration Release -mode seq-vs-par
displayName: Determinism tests (1-shot diff — sequential vs parallel)
- task: PublishPipelineArtifact@1
displayName: Publish Determinism Logs
inputs:
Expand Down
7 changes: 7 additions & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.100.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
### Fixed

* Fix state machine lowering dropping the side-effectful receiver of an unused unit-typed member access (e.g. inside `task { (effectful()).UnitProp }`). ([Issue #13099](https://github.com/dotnet/fsharp/issues/13099), [PR #19885](https://github.com/dotnet/fsharp/pull/19885))
* `--deterministic` Release builds now produce byte-identical `FSharp.Compiler.Service.dll` under `--parallelcompilation+` and `--parallelcompilation-`, so it is restored to the determinism gate (now also checked sequential-vs-parallel). Code generation runs the same deferred per-file drain in both modes, with type/member/field emit-order keys and generated names derived from the file being emitted rather than thread-scheduling order. ([Issue #19928](https://github.com/dotnet/fsharp/issues/19928), [PR #19929](https://github.com/dotnet/fsharp/pull/19929))
* Fix `[<CompiledName>]` silently producing duplicate IL entries (FS0192/FS2014) when applied to a multi-value let-binding (e.g. `let a, b = 1, 2`); now emits FS0755 at type-check time. ([Issue #6131](https://github.com/dotnet/fsharp/issues/6131), [PR #19924](https://github.com/dotnet/fsharp/pull/19924))
* Fix missing FS1182 ("unused binding") warning for unused `let` function bindings inside class types. ([Issue #13849](https://github.com/dotnet/fsharp/issues/13849), [PR #19805](https://github.com/dotnet/fsharp/pull/19805))
* Fix inner mutually-recursive `let rec ... and ...` functions under `--realsig+` not being lifted to top-level static methods (TLR), causing `FSharpFunc` closure allocations and loss of `tail.` opcodes — the large struct-mutual-recursion perf regression reported in [Issue #17607](https://github.com/dotnet/fsharp/issues/17607). ([PR #19882](https://github.com/dotnet/fsharp/pull/19882))
* 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))
Expand Down Expand Up @@ -35,6 +38,7 @@
* Fix inner mutually-recursive `let rec ... and ...` functions under `--realsig+` not being lifted to top-level static methods (TLR), causing `FSharpFunc` closure allocations and loss of `tail.` opcodes — the large struct-mutual-recursion perf regression reported in [Issue #17607](https://github.com/dotnet/fsharp/issues/17607). ([PR #19882](https://github.com/dotnet/fsharp/pull/19882))
* 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 `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 Expand Up @@ -78,6 +82,7 @@
* Fix O(n) `TypeStructure.GetHashCode` performance regression causing sustained high CPU in IDE mode with generative type providers. ([Issue #18925](https://github.com/dotnet/fsharp/issues/18925), [PR #19369](https://github.com/dotnet/fsharp/pull/19369))
* Fix TypeLoadException when creating delegate with voidptr parameter. (Issue [#11132](https://github.com/dotnet/fsharp/issues/11132), [PR #19338](https://github.com/dotnet/fsharp/pull/19338))
* Suppress tail calls when localloc (NativePtr.stackalloc) is used. (Issue [#13447](https://github.com/dotnet/fsharp/issues/13447), [PR #19338](https://github.com/dotnet/fsharp/pull/19338))
* Fix stack overflow when graph-checking long statement sequences on platforms with large stack frames (e.g. Mono ppc64le), by flattening `SynExpr.Sequential` chains in `FileContentMapping`. ([Issue #19988](https://github.com/dotnet/fsharp/issues/19988), [PR #20028](https://github.com/dotnet/fsharp/pull/20028))
* Fix TypeLoadException in Release builds with inline constraints. (Issue [#14492](https://github.com/dotnet/fsharp/issues/14492), [PR #19338](https://github.com/dotnet/fsharp/pull/19338))
* Fix nativeptr in interfaces leads to TypeLoadException. (Issue [#14508](https://github.com/dotnet/fsharp/issues/14508), [PR #19338](https://github.com/dotnet/fsharp/pull/19338))
* Fix box instruction for literal upcasts. (Issue [#18319](https://github.com/dotnet/fsharp/issues/18319), [PR #19338](https://github.com/dotnet/fsharp/pull/19338))
Expand Down Expand Up @@ -121,6 +126,7 @@
* Reference assembly MVIDs are now deterministic across compiler invocations. Previously, `--refout` / `<ProduceReferenceAssembly>true</ProduceReferenceAssembly>` produced a different MVID every build because the implied signature hash used .NET's randomized `String.GetHashCode()`. ([Issue #19751](https://github.com/dotnet/fsharp/issues/19751), [PR #19801](https://github.com/dotnet/fsharp/pull/19801))
* Parser: recover on unfinished if and binary expressions
([PR #19724](https://github.com/dotnet/fsharp/pull/19724))
* Fix `SynExpr.shouldBeParenthesizedInContext` to report parentheses as required around `SynExpr.Sequential` expressions used as record or anonymous-record field values, so the IDE "remove unnecessary parentheses" analyzer no longer breaks code like `{| A = ((); B = 3) |}`. ([Issue #17826](https://github.com/dotnet/fsharp/issues/17826), [PR #19850](https://github.com/dotnet/fsharp/pull/19850))
* Warn FS3888 when a compiler-semantic attribute on a value/member or type/module is present in the `.fs` but missing from the `.fsi`. Such attributes were previously ignored at the consumer side. Under the `ErrorOnMissingSignatureAttribute` preview language feature, FS3888 is an error. ([Issue #19560](https://github.com/dotnet/fsharp/issues/19560), [PR #19880](https://github.com/dotnet/fsharp/pull/19880))
* Emit debug points at a stack-empty position ([PR #19877](https://github.com/dotnet/fsharp/pull/19877))
* Fix spurious XmlDoc warnings (unknown parameter / no documentation for parameter) under `--warnon:3390` when a get/set property documents the full parameter set across both accessors. ([Issue #13684](https://github.com/dotnet/fsharp/issues/13684), [PR #19884](https://github.com/dotnet/fsharp/pull/19884))
Expand All @@ -132,6 +138,7 @@
* Warn FS3888 when a compiler-semantic attribute on a value/member or type/module is present in the `.fs` but missing from the `.fsi`. Such attributes were previously ignored at the consumer side. Under the `ErrorOnMissingSignatureAttribute` preview language feature, FS3888 is an error. ([Issue #19560](https://github.com/dotnet/fsharp/issues/19560), [PR #19880](https://github.com/dotnet/fsharp/pull/19880))
* Emit debug points at a stack-empty position ([PR #19877](https://github.com/dotnet/fsharp/pull/19877))
* Fix spurious XmlDoc warnings (unknown parameter / no documentation for parameter) under `--warnon:3390` when a get/set property documents the full parameter set across both accessors. ([Issue #13684](https://github.com/dotnet/fsharp/issues/13684), [PR #19884](https://github.com/dotnet/fsharp/pull/19884))
* Fix Go to Metadata rendering of IL literal (`const`) fields - they now appear with `[<Literal>]` and their constant value, e.g. `System.Char.MaxValue` no longer shows as a plain `static val`. ([Issue #11526](https://github.com/dotnet/fsharp/issues/11526), [PR #19922](https://github.com/dotnet/fsharp/pull/19922))
* FSI multi-assembly emit (`--multiemit+`) now attaches `System.Diagnostics.DebuggableAttribute(DisableOptimizations|Default)` to each submission's manifest when local optimizations are disabled (`--optimize-`), matching the single-emit and regular-compiler behavior so debuggers see submissions as unoptimized. ([Issue #14572](https://github.com/dotnet/fsharp/issues/14572), [PR #19921](https://github.com/dotnet/fsharp/pull/19921))
* Stop F# Interactive from mutating script arguments that follow `--`. Abbreviated flags like `-d`, `-r`, `-I` after the `--` separator are no longer colon-joined with their next token in `fsi.CommandLineArgs`. ([Issue #10819](https://github.com/dotnet/fsharp/issues/10819), [PR #19926](https://github.com/dotnet/fsharp/pull/19926))
* Fix Go-to-Definition for provided constructors that lack `TypeProviderDefinitionLocationAttribute`. Navigation now falls back to the declaring type instead of silently failing. ([Issue #5538](https://github.com/dotnet/fsharp/issues/5538), [PR #19917](https://github.com/dotnet/fsharp/pull/19917))
Expand Down
4 changes: 3 additions & 1 deletion eng/restore-internal-tools.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
steps:
- task: NuGetAuthenticate@1
displayName: Authenticate devdiv/dotnet-core-internal-tooling feed (WIF)
inputs:
nuGetServiceConnections: 'devdiv/dotnet-core-internal-tooling'
azureDevOpsServiceConnection: dnceng-devdiv-dotnet-core-internal-tooling-feed-rw-wif
feedUrl: https://pkgs.dev.azure.com/devdiv/_packaging/dotnet-core-internal-tooling/nuget/v3/index.json
forceReinstallCredentialProvider: true

- script: $(Build.SourcesDirectory)\eng\RestoreInternal.cmd
Expand Down
27 changes: 10 additions & 17 deletions eng/test-determinism.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,11 @@ if ($help) {
}

# List of binary names that should be skipped because they have a known issue that
# makes them non-deterministic.
#
# FSharp.Compiler.Service.dll: closure type names carry a "-N" suffix whose counter is
# allocated in parallel-emit order. The closure 'uniq' values come from a racy
# Interlocked.Increment, so two same-flags parallel builds can allocate the suffixes in a
# different order (e.g. func2@1-23 vs func2@1-17), drifting the #Strings heap layout.
# This is the residual closure-name race tracked by
# https://github.com/dotnet/fsharp/issues/19928 and fixed by #19929 (always-defer +
# source-stable closure naming). Skip this one binary until that fix lands so the gate
# can stay STRICT for every other binary instead of being globally suppressed.
$script:skipList = @("FSharp.Compiler.Service.dll")
# makes them non-deterministic. Empty: the closure type-name race that made
# FSharp.Compiler.Service.dll non-deterministic (#19928) is fixed - closure names now bucket
# by the file being emitted, not by the closure's own (inlined or synthetic) source file - so
# the gate stays STRICT for every binary.
$script:skipList = @()
function Run-Build([string]$rootDir, [string]$increment, [string]$additionalFscFlags = "") {

$logFileName = $increment
Expand Down Expand Up @@ -199,13 +193,12 @@ function Test-MapContents($dataMap) {
throw "Didn't find the expected count of binaries"
}

# Test for some well known binaries.
# NOTE: FSharp.Compiler.Service.dll is intentionally NOT listed here — it is excluded via
# $script:skipList above (known parallel closure-name race, #19928/#19929) so it never enters
# the map. Re-add it here once #19929 removes the skip. FSharp.Core.dll remains as the anchor
# guaranteeing we actually examined real compiler output.
# Test for some well known binaries. FSharp.Compiler.Service.dll is the large multi-file
# output that exercised the closure-name race (#19928); FSharp.Core.dll anchors that we
# actually examined real compiler output.
$list = @(
"FSharp.Core.dll")
"FSharp.Core.dll",
"FSharp.Compiler.Service.dll")

foreach ($fileName in $list) {
$found = $false
Expand Down
19 changes: 19 additions & 0 deletions src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,25 @@ let MakeAndPublishVal (cenv: cenv) env (altActualParent, inSig, declKind, valRec
vspec

let MakeAndPublishVals (cenv: cenv) env (altActualParent, inSig, declKind, valRecInfo, valSchemes, attrs, xmlDoc, literalValue) =
let g = cenv.g

// [<CompiledName>] on a binding that publishes more than one val (e.g. tuple,
// record, list, cons, `let x as y = ...` destructures, multi-case active patterns)
// would silently propagate the same compiled name to every introduced value and
// produce duplicate IL entries (FS0192/FS2014) during codegen. Catch it here where
// the post-generalization val count is authoritative. See dotnet/fsharp#6131.
if Map.count valSchemes > 1 then
match attrs with
| ValAttribString g WellKnownValAttributes.CompiledNameAttribute _ ->
let m =
match Map.toList valSchemes with
| [] -> range0
| (_, ValScheme(id = id)) :: rest ->
(id.idRange, rest)
||> List.fold (fun acc (_, ValScheme(id = id)) -> unionRanges acc id.idRange)
errorR(Error(FSComp.SR.tcCompiledNameAttributeMisused(), m))
| _ -> ()

Map.foldBack
(fun name (valscheme: ValScheme) values ->
Map.add name (MakeAndPublishVal cenv env (altActualParent, inSig, declKind, valRecInfo, valscheme, attrs, xmlDoc, literalValue, false), valscheme.GeneralizedType) values)
Expand Down
8 changes: 7 additions & 1 deletion src/Compiler/Checking/NicePrint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,8 @@ module PrintIL =
let s = d.ToString ("g12", CultureInfo.InvariantCulture)
let s = ensureFloat s
s |> (tagNumericLiteral >> Some)
| _ -> None
| ILFieldInit.String s -> ("\"" + s + "\"") |> (tagStringLiteral >> Some)
| ILFieldInit.Null -> "null" |> (tagKeyword >> Some)
| None -> None
match textOpt with
| None -> WordL.equals ^^ (comment "value unavailable")
Expand Down Expand Up @@ -1972,6 +1973,11 @@ module TastDefinitionPrinting =
let nameL = ConvertLogicalNameToDisplayLayout (tagField >> wordL) finfo.FieldName
let typL = layoutType denv (finfo.FieldType(infoReader.amap, m))
let fieldL = staticL ^^ WordL.keywordVal ^^ (nameL |> addColonL) ^^ typL
let isLiteral = finfo.LiteralValue.IsSome
let fieldL =
if isLiteral then fieldL ^^ PrintIL.layoutILFieldInit finfo.LiteralValue
else fieldL
let fieldL = fieldL |> PrintTypes.layoutAttribs denv None isLiteral TyparKind.Type []
layoutXmlDocOfILFieldInfo denv infoReader finfo fieldL

let layoutEventInfo denv (infoReader: InfoReader) m (einfo: EventInfo) =
Expand Down
Loading