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 ff1c9aae2d..91284f9890 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)) * Reject non-function bindings for single-case and partial active pattern names with FS1209, matching the existing multi-case behavior. ([PR #19763](https://github.com/dotnet/fsharp/pull/19763)) * Fix FS0421 "The address of the variable cannot be used at this point" incorrectly raised for the discard pattern `let _ = &expr` when `let x = &expr` compiles. ([Issue #18841](https://github.com/dotnet/fsharp/issues/18841), [PR #19811](https://github.com/dotnet/fsharp/pull/19811)) * 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)) diff --git a/src/Compiler/Checking/NameResolution.fs b/src/Compiler/Checking/NameResolution.fs index 898dc78aa7..36eedebfbe 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 diff --git a/tests/FSharp.Compiler.Service.Tests/EditorTests.fs b/tests/FSharp.Compiler.Service.Tests/EditorTests.fs index 44be1a5cfe..f9c1da195f 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`` () =