diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index 35128d40ad0..455e5a788d3 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -3,6 +3,7 @@ * Code generated files with > 64K methods and generated symbols crash when loaded. Use infered sequence points for debugging. ([Issue #16399](https://github.com/dotnet/fsharp/issues/16399), [#PR 16514](https://github.com/dotnet/fsharp/pull/16514)) * `nameof Module` expressions and patterns are processed to link files in `--test:GraphBasedChecking`. ([PR #16550](https://github.com/dotnet/fsharp/pull/16550)) * Graph Based Checking doesn't throw on invalid parsed input so it can be used for IDE scenarios ([PR #16575](https://github.com/dotnet/fsharp/pull/16575)) +* Keep parens for problematic exprs (`if`, `match`, etc.) in `$"{(…):N0}"`, `$"{(…),-3}"`, etc. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578)) ### Added diff --git a/src/Compiler/Service/SynExpr.fs b/src/Compiler/Service/SynExpr.fs index 0df9a1a1c17..41dbd4d4d18 100644 --- a/src/Compiler/Service/SynExpr.fs +++ b/src/Compiler/Service/SynExpr.fs @@ -423,7 +423,9 @@ module SynExpr = | SynExpr.MatchLambda(matchClauses = Last(SynMatchClause(resultExpr = expr))) | SynExpr.MatchBang(clauses = Last(SynMatchClause(resultExpr = expr))) | SynExpr.TryWith(withCases = Last(SynMatchClause(resultExpr = expr))) - | SynExpr.TryFinally(finallyExpr = expr) -> loop expr + | SynExpr.TryFinally(finallyExpr = expr) + | SynExpr.Do(expr = expr) + | SynExpr.DoBang(expr = expr) -> loop expr | _ -> ValueNone loop @@ -810,6 +812,12 @@ module SynExpr = -> true + | SynExpr.InterpolatedString(contents = contents), (SynExpr.Tuple(isStruct = false) | Dangling.Problematic _) -> + contents + |> List.exists (function + | SynInterpolatedStringPart.FillExpr(qualifiers = Some _) -> true + | _ -> false) + | SynExpr.Record(copyInfo = Some(SynExpr.Paren(expr = Is inner), _)), Dangling.Problematic _ | SynExpr.AnonRecd(copyInfo = Some(SynExpr.Paren(expr = Is inner), _)), Dangling.Problematic _ -> true diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs index 69d6456e378..cd3bbdd2bfc 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs @@ -800,6 +800,24 @@ in x "$\"{(id 3)}\"", "$\"{id 3}\"" "$\"{(x)}\"", "$\"{x}\"" + "$\"{(if true then 1 else 0)}\"", "$\"{if true then 1 else 0}\"" + "$\"{(if true then 1 else 0):N0}\"", "$\"{(if true then 1 else 0):N0}\"" + "$\"{(if true then 1 else 0),-3}\"", "$\"{(if true then 1 else 0),-3}\"" + "$\"{(match () with () -> 1):N0}\"", "$\"{(match () with () -> 1):N0}\"" + "$\"{(match () with () -> 1),-3}\"", "$\"{(match () with () -> 1),-3}\"" + "$\"{(try () with _ -> 1):N0}\"", "$\"{(try () with _ -> 1):N0}\"" + "$\"{(try () with _ -> 1),-3}\"", "$\"{(try () with _ -> 1),-3}\"" + "$\"{(try 1 finally ()):N0}\"", "$\"{(try 1 finally ()):N0}\"" + "$\"{(try 1 finally ()),-3}\"", "$\"{(try 1 finally ()),-3}\"" + "$\"{(let x = 3 in x):N0}\"", "$\"{(let x = 3 in x):N0}\"" + "$\"{(let x = 3 in x),-3}\"", "$\"{(let x = 3 in x),-3}\"" + "$\"{(do (); 3):N0}\"", "$\"{(do (); 3):N0}\"" + "$\"{(do (); 3),-3}\"", "$\"{(do (); 3),-3}\"" + "$\"{(x <- 3):N0}\"", "$\"{(x <- 3):N0}\"" + "$\"{(x <- 3),-3}\"", "$\"{(x <- 3),-3}\"" + "$\"{(1, 2):N0}\"", "$\"{(1, 2):N0}\"" + "$\"{(1, 2),-3}\"", "$\"{(1, 2),-3}\"" + """ $"{(3 + LanguagePrimitives.GenericZero):N0}" """,