From 8b061f923228f279f86ea9c90b701fbf8f5fda36 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 22 May 2026 17:50:52 +0200 Subject: [PATCH 1/5] Add failing test for duplicate format specifier locations in CE (issue 16419) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/FSharp.Compiler.Service.Tests/EditorTests.fs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/FSharp.Compiler.Service.Tests/EditorTests.fs b/tests/FSharp.Compiler.Service.Tests/EditorTests.fs index 44be1a5cfef..f9c1da195fe 100644 --- a/tests/FSharp.Compiler.Service.Tests/EditorTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/EditorTests.fs @@ -541,6 +541,19 @@ let _ = debug "[LanguageService] Type checking fails for '%s' with content=%A an (4, 82, 4, 84, 1); (4, 108, 4, 110, 1)|] +[] +let ``Format specifier locations not duplicated in CE`` () = + let input = "let _ = seq { sprintf \"%d\" 1 }" + let file = "/home/user/Test.fsx" + let _parseResult, typeCheckResults = parseAndCheckScript(file, input) + + let locations = typeCheckResults.GetFormatSpecifierLocationsAndArity() + let percentD = + locations + |> Array.filter (fun (r, _) -> r.StartColumn = 23) + + Assert.Equal(1, percentD.Length) + #if ASSUME_PREVIEW_FSHARP_CORE [] let ``Printf specifiers for regular and verbatim interpolated strings`` () = From 586440034ad42627db14a49c84f752b1e67f1d6f Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 22 May 2026 18:06:51 +0200 Subject: [PATCH 2/5] Dedup format specifier locations in TcResultsSinkImpl (issue 16419) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Checking/NameResolution.fs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Compiler/Checking/NameResolution.fs b/src/Compiler/Checking/NameResolution.fs index c2ff7d12589..d4afcdadb23 100644 --- a/src/Compiler/Checking/NameResolution.fs +++ b/src/Compiler/Checking/NameResolution.fs @@ -2185,6 +2185,8 @@ type TcResultsSinkImpl(tcGlobals, ?sourceText: ISourceText) = let capturedOpenDeclarations = ResizeArray() let capturedFormatSpecifierLocations = ResizeArray<_>() + let capturedFormatSpecifierRanges = HashSet() + let capturedNameResolutionIdentifiers = HashSet { new IEqualityComparer<_> with @@ -2289,7 +2291,8 @@ type TcResultsSinkImpl(tcGlobals, ?sourceText: ISourceText) = capturedMethodGroupResolutions.Add(CapturedNameResolution(itemMethodGroup, [], occurrenceType, nenv, ad, m)) member sink.NotifyFormatSpecifierLocation(m, numArgs) = - capturedFormatSpecifierLocations.Add((m, numArgs)) + if capturedFormatSpecifierRanges.Add(m) then + capturedFormatSpecifierLocations.Add((m, numArgs)) member sink.NotifyRelatedSymbolUse(m, item, kind) = if allowedRange m then From e9164063e6562eb5df3816fd929c6c1ee6510a24 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 22 May 2026 18:58:25 +0200 Subject: [PATCH 3/5] Apply remaining changes --- .executor-pid | 1 + 1 file changed, 1 insertion(+) create mode 100644 .executor-pid diff --git a/.executor-pid b/.executor-pid new file mode 100644 index 00000000000..b8f34aa4842 --- /dev/null +++ b/.executor-pid @@ -0,0 +1 @@ +26552 \ No newline at end of file From b38520888685dce378302cf6844837ca007d7d12 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 22 May 2026 21:27:32 +0200 Subject: [PATCH 4/5] Delete .executor-pid --- .executor-pid | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .executor-pid diff --git a/.executor-pid b/.executor-pid deleted file mode 100644 index b8f34aa4842..00000000000 --- a/.executor-pid +++ /dev/null @@ -1 +0,0 @@ -26552 \ No newline at end of file From be63ef7236be21e32f7418a18861553dec82eca6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 28 May 2026 09:48:13 +0000 Subject: [PATCH 5/5] Add FCS release note for format specifier dedup fix Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/11.0.100.md | 1 + 1 file changed, 1 insertion(+) 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..8964f8cca57 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 +* Deduplicate format specifier locations in computation expressions so editor tooling no longer reports duplicate entries for the same `%` specifier. ([Issue #16419](https://github.com/dotnet/fsharp/issues/16419), [PR #19791](https://github.com/dotnet/fsharp/pull/19791)) * 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))