From 6f59f9f278961d281a9f202308da55a257f97a87 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 26 May 2026 11:35:48 +0200 Subject: [PATCH 1/4] Stabilize parallel optimizer Val iteration for deterministic names (#19732) Optimize/DetupleArgs.determineTransforms and Optimize/InnerLambdasToTopLevelFuncs.CreateNewValuesForTLR walked Val sets in Val.Stamp order. Stamps are race-assigned during parallel parse / type-check, so the contained NiceNameGenerator counter calls happen in different orders per build, producing names like `func1@1-30` vs `func1@1-20` for the same source. Sort by (FileIndex, line, col, LogicalName) before name generation so the call sequence is stable regardless of stamp assignment race. Also drops the stale OptimizeInputs.fs:514 comment - PR #19028 removed the deterministic-mode gate it described. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../.FSharp.Compiler.Service/11.0.100.md | 1 + src/Compiler/Driver/OptimizeInputs.fs | 1 - src/Compiler/Optimize/DetupleArgs.fs | 13 ++++++++++++- .../Optimize/InnerLambdasToTopLevelFuncs.fs | 11 ++++++++++- 4 files changed, 23 insertions(+), 3 deletions(-) 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 7d4162f804e..d6ddd4e5601 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,5 +1,6 @@ ### Fixed +* Improve determinism under parallel optimization: `Optimize/DetupleArgs` and `Optimize/InnerLambdasToTopLevelFuncs` now walk their `Val` sets in stable source-position order before calling into `NiceNameGenerator`, so compiler-generated names like `func1@1-30` no longer vary across builds due to `Val.Stamp` assignment races during parallel parse/type-check. ([Issue #19732](https://github.com/dotnet/fsharp/issues/19732)) * Honor `--nowarn` and `--warnaserror` for warnings emitted during command-line option parsing ([Issue #19576](https://github.com/dotnet/fsharp/issues/19576), [PR #19776](https://github.com/dotnet/fsharp/pull/19776)) * Fix `[]` prefix attributes being silently dropped on class members, and fix false-positive `AllowMultiple=false` errors when `[]` and `[]` are applied to the same binding. ([Issue #17904](https://github.com/dotnet/fsharp/issues/17904), [Issue #19020](https://github.com/dotnet/fsharp/issues/19020), [PR #19738](https://github.com/dotnet/fsharp/pull/19738)) * Fix attributes on return type of unparenthesized tuple methods being silently dropped from IL. ([Issue #462](https://github.com/dotnet/fsharp/issues/462), [PR #19714](https://github.com/dotnet/fsharp/pull/19714)) diff --git a/src/Compiler/Driver/OptimizeInputs.fs b/src/Compiler/Driver/OptimizeInputs.fs index 78bca4bf979..dcbd356739a 100644 --- a/src/Compiler/Driver/OptimizeInputs.fs +++ b/src/Compiler/Driver/OptimizeInputs.fs @@ -511,7 +511,6 @@ let ApplyAllOptimizations let results, optEnvFirstLoop = match tcConfig.optSettings.processingMode with - // Parallel optimization breaks determinism - turn it off in deterministic builds. | Optimizer.OptimizationProcessingMode.Parallel -> let results, optEnvFirstPhase = ParallelOptimization.optimizeFilesInParallel optEnv phases implFiles diff --git a/src/Compiler/Optimize/DetupleArgs.fs b/src/Compiler/Optimize/DetupleArgs.fs index b0dd2d62835..0b1ca93c3c3 100644 --- a/src/Compiler/Optimize/DetupleArgs.fs +++ b/src/Compiler/Optimize/DetupleArgs.fs @@ -704,7 +704,18 @@ let determineTransforms g (z: Results) = let callPatterns = sitesCPs sites // callPatterns from sites decideTransform g z f callPatterns (m, tps, vss, retTy) // make transform (if required) - let vtransforms = Zmap.chooseL selectTransform z.Uses + // Walk z.Uses in stable source-position order so the contained call to + // NiceNameGenerator (via decideTransform) sees the same call order across + // runs, regardless of Val.Stamp values assigned during parallel parse. + // See https://github.com/dotnet/fsharp/issues/19732. + let vtransforms = + Zmap.toList z.Uses + |> List.sortWith (fun (v1: Val, _) (v2: Val, _) -> + let r1, r2 = v1.Range, v2.Range + compare + struct (r1.FileIndex, r1.StartLine, r1.StartColumn, v1.LogicalName) + struct (r2.FileIndex, r2.StartLine, r2.StartColumn, v2.LogicalName)) + |> List.choose (fun (f, sites) -> selectTransform f sites) let vtransforms = Zmap.ofList valOrder vtransforms vtransforms diff --git a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs index 885917fee37..602f39fdaad 100644 --- a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs +++ b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs @@ -844,7 +844,16 @@ let CreateNewValuesForTLR g tlrS arityM fclassM envPackM = let fHat = mkLocalNameTypeArity f.IsCompilerGenerated m fHatName fHatTy (Some fHatArity) fHat - let fs = Zset.elements tlrS + // Sort by source position + logical name so the call order into + // NiceNameGenerator is stable regardless of Val.Stamp assignment race + // during parallel type checking. See https://github.com/dotnet/fsharp/issues/19732. + let fs = + Zset.elements tlrS + |> List.sortWith (fun (v1: Val) (v2: Val) -> + let r1, r2 = v1.Range, v2.Range + compare + struct (r1.FileIndex, r1.StartLine, r1.StartColumn, v1.LogicalName) + struct (r2.FileIndex, r2.StartLine, r2.StartColumn, v2.LogicalName)) let ffHats = List.map (fun f -> f, createFHat f) fs let fHatM = Zmap.ofList valOrder ffHats fHatM From 2b39c152d58943361ad1a66a0a71a50286815bd2 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 27 May 2026 12:26:36 +0200 Subject: [PATCH 2/4] Add Val.Stamp tiebreaker to sort keys; fix release note Address multi-model review consensus: - Add Val.Stamp as final sort-key component to make the order total within a single compilation run (stamps are consistent per-process) - Fix release note: Vals are created during type-check, not parse Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/11.0.100.md | 2 +- src/Compiler/Optimize/DetupleArgs.fs | 4 ++-- src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) 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 d6ddd4e5601..2846d15819d 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,6 +1,6 @@ ### Fixed -* Improve determinism under parallel optimization: `Optimize/DetupleArgs` and `Optimize/InnerLambdasToTopLevelFuncs` now walk their `Val` sets in stable source-position order before calling into `NiceNameGenerator`, so compiler-generated names like `func1@1-30` no longer vary across builds due to `Val.Stamp` assignment races during parallel parse/type-check. ([Issue #19732](https://github.com/dotnet/fsharp/issues/19732)) +* Improve determinism under parallel optimization: `Optimize/DetupleArgs` and `Optimize/InnerLambdasToTopLevelFuncs` now walk their `Val` sets in stable source-position order before calling into `NiceNameGenerator`, so compiler-generated names no longer vary across builds due to `Val.Stamp` assignment races during parallel type-check. ([Issue #19732](https://github.com/dotnet/fsharp/issues/19732)) * Honor `--nowarn` and `--warnaserror` for warnings emitted during command-line option parsing ([Issue #19576](https://github.com/dotnet/fsharp/issues/19576), [PR #19776](https://github.com/dotnet/fsharp/pull/19776)) * Fix `[]` prefix attributes being silently dropped on class members, and fix false-positive `AllowMultiple=false` errors when `[]` and `[]` are applied to the same binding. ([Issue #17904](https://github.com/dotnet/fsharp/issues/17904), [Issue #19020](https://github.com/dotnet/fsharp/issues/19020), [PR #19738](https://github.com/dotnet/fsharp/pull/19738)) * Fix attributes on return type of unparenthesized tuple methods being silently dropped from IL. ([Issue #462](https://github.com/dotnet/fsharp/issues/462), [PR #19714](https://github.com/dotnet/fsharp/pull/19714)) diff --git a/src/Compiler/Optimize/DetupleArgs.fs b/src/Compiler/Optimize/DetupleArgs.fs index 0b1ca93c3c3..bb07e1dbfcb 100644 --- a/src/Compiler/Optimize/DetupleArgs.fs +++ b/src/Compiler/Optimize/DetupleArgs.fs @@ -713,8 +713,8 @@ let determineTransforms g (z: Results) = |> List.sortWith (fun (v1: Val, _) (v2: Val, _) -> let r1, r2 = v1.Range, v2.Range compare - struct (r1.FileIndex, r1.StartLine, r1.StartColumn, v1.LogicalName) - struct (r2.FileIndex, r2.StartLine, r2.StartColumn, v2.LogicalName)) + struct (r1.FileIndex, r1.StartLine, r1.StartColumn, v1.LogicalName, v1.Stamp) + struct (r2.FileIndex, r2.StartLine, r2.StartColumn, v2.LogicalName, v2.Stamp)) |> List.choose (fun (f, sites) -> selectTransform f sites) let vtransforms = Zmap.ofList valOrder vtransforms vtransforms diff --git a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs index 602f39fdaad..a74b4514e8b 100644 --- a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs +++ b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs @@ -852,8 +852,8 @@ let CreateNewValuesForTLR g tlrS arityM fclassM envPackM = |> List.sortWith (fun (v1: Val) (v2: Val) -> let r1, r2 = v1.Range, v2.Range compare - struct (r1.FileIndex, r1.StartLine, r1.StartColumn, v1.LogicalName) - struct (r2.FileIndex, r2.StartLine, r2.StartColumn, v2.LogicalName)) + struct (r1.FileIndex, r1.StartLine, r1.StartColumn, v1.LogicalName, v1.Stamp) + struct (r2.FileIndex, r2.StartLine, r2.StartColumn, v2.LogicalName, v2.Stamp)) let ffHats = List.map (fun f -> f, createFHat f) fs let fHatM = Zmap.ofList valOrder ffHats fHatM From 151f443376508a0f984bf873fdd09a440887fc8c Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 28 May 2026 11:00:43 +0200 Subject: [PATCH 3/4] Address self-review: extract helper, trim prose, run determinism in Release - Extract valSourceOrderKey into TypedTreeOps.ExprConstruction (.fs + .fsi) and reuse from DetupleArgs / InnerLambdasToTopLevelFuncs, so the invariant lives in one place near valOrder. - Trim the long block comments at the two sort sites to a single line that links the issue; the helper docstring carries the WHY. - Restore a brief note in OptimizeInputs.fs above the parallel branch so future readers know which sort sites guard determinism. - azure-pipelines-PR.yml: run eng/test-determinism.cmd in Release config. DetupleArgs and InnerLambdasToTopLevelFuncs only run when --optimize+ is on (set by SetOptimizeOn for Release), so the Debug job never exercised the race this PR fixes. Rename job to Determinism_Release. - Release note: add PR link. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- azure-pipelines-PR.yml | 10 +++++----- .../.FSharp.Compiler.Service/11.0.100.md | 2 +- src/Compiler/Driver/OptimizeInputs.fs | 5 +++++ src/Compiler/Optimize/DetupleArgs.fs | 11 ++--------- src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs | 10 ++-------- .../TypedTree/TypedTreeOps.ExprConstruction.fs | 9 +++++++++ .../TypedTree/TypedTreeOps.ExprConstruction.fsi | 6 ++++++ 7 files changed, 30 insertions(+), 23 deletions(-) diff --git a/azure-pipelines-PR.yml b/azure-pipelines-PR.yml index 4b76589ea7a..a0eab5042f4 100644 --- a/azure-pipelines-PR.yml +++ b/azure-pipelines-PR.yml @@ -100,7 +100,7 @@ stages: helixRepo: dotnet/fsharp jobs: # Determinism, we want to run it only in PR builds - - job: Determinism_Debug + - job: Determinism_Release condition: eq(variables['Build.Reason'], 'PullRequest') variables: - name: _SignType @@ -129,15 +129,15 @@ stages: workingDirectory: $(Build.SourcesDirectory) installationPath: $(Build.SourcesDirectory)/.dotnet - script: .\eng\common\dotnet.cmd - - script: .\eng\test-determinism.cmd -configuration Debug + - script: .\eng\test-determinism.cmd -configuration Release env: FSHARP_EXPERIMENTAL_FEATURES: $(_experimental_flag) - displayName: Determinism tests with Debug configuration + displayName: Determinism tests with Release configuration - task: PublishPipelineArtifact@1 displayName: Publish Determinism Logs inputs: - targetPath: '$(Build.SourcesDirectory)/artifacts/log/Debug' - artifactName: 'Determinism_Debug Attempt $(System.JobAttempt) Logs' + targetPath: '$(Build.SourcesDirectory)/artifacts/log/Release' + artifactName: 'Determinism_Release Attempt $(System.JobAttempt) Logs' continueOnError: true condition: not(succeeded()) 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 2846d15819d..2f9cee50159 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,6 +1,6 @@ ### Fixed -* Improve determinism under parallel optimization: `Optimize/DetupleArgs` and `Optimize/InnerLambdasToTopLevelFuncs` now walk their `Val` sets in stable source-position order before calling into `NiceNameGenerator`, so compiler-generated names no longer vary across builds due to `Val.Stamp` assignment races during parallel type-check. ([Issue #19732](https://github.com/dotnet/fsharp/issues/19732)) +* Improve determinism under parallel optimization: `Optimize/DetupleArgs` and `Optimize/InnerLambdasToTopLevelFuncs` now walk their `Val` sets in stable source-position order before calling into `NiceNameGenerator`, so compiler-generated names no longer vary across builds due to `Val.Stamp` assignment races during parallel type-check. ([Issue #19732](https://github.com/dotnet/fsharp/issues/19732), [PR #19810](https://github.com/dotnet/fsharp/pull/19810)) * Honor `--nowarn` and `--warnaserror` for warnings emitted during command-line option parsing ([Issue #19576](https://github.com/dotnet/fsharp/issues/19576), [PR #19776](https://github.com/dotnet/fsharp/pull/19776)) * Fix `[]` prefix attributes being silently dropped on class members, and fix false-positive `AllowMultiple=false` errors when `[]` and `[]` are applied to the same binding. ([Issue #17904](https://github.com/dotnet/fsharp/issues/17904), [Issue #19020](https://github.com/dotnet/fsharp/issues/19020), [PR #19738](https://github.com/dotnet/fsharp/pull/19738)) * Fix attributes on return type of unparenthesized tuple methods being silently dropped from IL. ([Issue #462](https://github.com/dotnet/fsharp/issues/462), [PR #19714](https://github.com/dotnet/fsharp/pull/19714)) diff --git a/src/Compiler/Driver/OptimizeInputs.fs b/src/Compiler/Driver/OptimizeInputs.fs index dcbd356739a..a9bedca3b70 100644 --- a/src/Compiler/Driver/OptimizeInputs.fs +++ b/src/Compiler/Driver/OptimizeInputs.fs @@ -512,6 +512,11 @@ let ApplyAllOptimizations let results, optEnvFirstLoop = match tcConfig.optSettings.processingMode with | Optimizer.OptimizationProcessingMode.Parallel -> + // Determinism under Parallel mode relies on the per-pass sorts in + // DetupleArgs.determineTransforms and InnerLambdasToTopLevelFuncs.CreateNewValuesForTLR + // (via valSourceOrderKey). Any new pass calling NiceNameGenerator from a + // parallel optimizer phase must sort its Val collection the same way. + // See https://github.com/dotnet/fsharp/issues/19732. let results, optEnvFirstPhase = ParallelOptimization.optimizeFilesInParallel optEnv phases implFiles diff --git a/src/Compiler/Optimize/DetupleArgs.fs b/src/Compiler/Optimize/DetupleArgs.fs index bb07e1dbfcb..70276a1e9e2 100644 --- a/src/Compiler/Optimize/DetupleArgs.fs +++ b/src/Compiler/Optimize/DetupleArgs.fs @@ -704,17 +704,10 @@ let determineTransforms g (z: Results) = let callPatterns = sitesCPs sites // callPatterns from sites decideTransform g z f callPatterns (m, tps, vss, retTy) // make transform (if required) - // Walk z.Uses in stable source-position order so the contained call to - // NiceNameGenerator (via decideTransform) sees the same call order across - // runs, regardless of Val.Stamp values assigned during parallel parse. - // See https://github.com/dotnet/fsharp/issues/19732. + // See https://github.com/dotnet/fsharp/issues/19732 for why we sort here. let vtransforms = Zmap.toList z.Uses - |> List.sortWith (fun (v1: Val, _) (v2: Val, _) -> - let r1, r2 = v1.Range, v2.Range - compare - struct (r1.FileIndex, r1.StartLine, r1.StartColumn, v1.LogicalName, v1.Stamp) - struct (r2.FileIndex, r2.StartLine, r2.StartColumn, v2.LogicalName, v2.Stamp)) + |> List.sortWith (fun (v1, _) (v2, _) -> compare (valSourceOrderKey v1) (valSourceOrderKey v2)) |> List.choose (fun (f, sites) -> selectTransform f sites) let vtransforms = Zmap.ofList valOrder vtransforms vtransforms diff --git a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs index a74b4514e8b..c3dd66777f6 100644 --- a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs +++ b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs @@ -844,16 +844,10 @@ let CreateNewValuesForTLR g tlrS arityM fclassM envPackM = let fHat = mkLocalNameTypeArity f.IsCompilerGenerated m fHatName fHatTy (Some fHatArity) fHat - // Sort by source position + logical name so the call order into - // NiceNameGenerator is stable regardless of Val.Stamp assignment race - // during parallel type checking. See https://github.com/dotnet/fsharp/issues/19732. + // See https://github.com/dotnet/fsharp/issues/19732 for why we sort here. let fs = Zset.elements tlrS - |> List.sortWith (fun (v1: Val) (v2: Val) -> - let r1, r2 = v1.Range, v2.Range - compare - struct (r1.FileIndex, r1.StartLine, r1.StartColumn, v1.LogicalName, v1.Stamp) - struct (r2.FileIndex, r2.StartLine, r2.StartColumn, v2.LogicalName, v2.Stamp)) + |> List.sortWith (fun v1 v2 -> compare (valSourceOrderKey v1) (valSourceOrderKey v2)) let ffHats = List.map (fun f -> f, createFHat f) fs let fHatM = Zmap.ofList valOrder ffHats fHatM diff --git a/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fs b/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fs index 00761538123..83401b7a9ae 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fs @@ -44,6 +44,15 @@ module internal ExprConstruction = member _.Compare(v1, v2) = compareBy v1 v2 _.Stamp } + // Source-position-derived order key for Vals. Used to walk Val collections + // in a stable, build-independent order before calling NiceNameGenerator + // from parallel optimizer passes. Stamp is the final tiebreaker for + // synthetic Vals at the same location; stamps are fixed within a single + // process so the order is total. See https://github.com/dotnet/fsharp/issues/19732. + let valSourceOrderKey (v: Val) = + let r = v.Range + struct (r.FileIndex, r.StartLine, r.StartColumn, v.LogicalName, v.Stamp) + let tyconOrder = { new IComparer with member _.Compare(tycon1, tycon2) = compareBy tycon1 tycon2 _.Stamp diff --git a/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fsi b/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fsi index 36942be52f1..09a00276dfe 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fsi +++ b/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fsi @@ -22,6 +22,12 @@ module internal ExprConstruction = /// An ordering for value definitions, based on stamp val valOrder: IComparer + /// Stable, source-position-derived key for ordering Vals. + /// Use this before calling NiceNameGenerator from parallel optimizer passes + /// so the generated names do not depend on Val.Stamp assignment race. + /// See https://github.com/dotnet/fsharp/issues/19732. + val valSourceOrderKey: Val -> struct (int * int * int * string * int64) + /// An ordering for type definitions, based on stamp val tyconOrder: IComparer From 2e5233f1b4e418ac2095deb7eb5ac5f91a6a74c2 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 28 May 2026 11:01:52 +0200 Subject: [PATCH 4/4] [VERIFY-ONLY] revert optimizer sort - should make Release determinism CI fail Temporary commit to validate that running eng/test-determinism.cmd in Release configuration actually catches the Val.Stamp-iteration race introduced by parallel optimization. Do NOT merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Optimize/DetupleArgs.fs | 5 +---- src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Compiler/Optimize/DetupleArgs.fs b/src/Compiler/Optimize/DetupleArgs.fs index 70276a1e9e2..e583d16c101 100644 --- a/src/Compiler/Optimize/DetupleArgs.fs +++ b/src/Compiler/Optimize/DetupleArgs.fs @@ -704,11 +704,8 @@ let determineTransforms g (z: Results) = let callPatterns = sitesCPs sites // callPatterns from sites decideTransform g z f callPatterns (m, tps, vss, retTy) // make transform (if required) - // See https://github.com/dotnet/fsharp/issues/19732 for why we sort here. let vtransforms = - Zmap.toList z.Uses - |> List.sortWith (fun (v1, _) (v2, _) -> compare (valSourceOrderKey v1) (valSourceOrderKey v2)) - |> List.choose (fun (f, sites) -> selectTransform f sites) + Zmap.chooseL selectTransform z.Uses let vtransforms = Zmap.ofList valOrder vtransforms vtransforms diff --git a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs index c3dd66777f6..885917fee37 100644 --- a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs +++ b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs @@ -844,10 +844,7 @@ let CreateNewValuesForTLR g tlrS arityM fclassM envPackM = let fHat = mkLocalNameTypeArity f.IsCompilerGenerated m fHatName fHatTy (Some fHatArity) fHat - // See https://github.com/dotnet/fsharp/issues/19732 for why we sort here. - let fs = - Zset.elements tlrS - |> List.sortWith (fun v1 v2 -> compare (valSourceOrderKey v1) (valSourceOrderKey v2)) + let fs = Zset.elements tlrS let ffHats = List.map (fun f -> f, createFHat f) fs let fHatM = Zmap.ofList valOrder ffHats fHatM