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 42793d2688..8aa2e5006d 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -7,7 +7,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), [PR #16743](https://github.com/dotnet/fsharp/pull/16743)) * 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), [PR #16588](https://github.com/dotnet/fsharp/pull/16588), [PR #16643](https://github.com/dotnet/fsharp/pull/16643)) -* Various parenthesization API fixes. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578), [PR #16666](https://github.com/dotnet/fsharp/pull/16666), [PR #16901](https://github.com/dotnet/fsharp/pull/16901)) +* Various parenthesization API fixes. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578), [PR #16666](https://github.com/dotnet/fsharp/pull/16666), [PR #16901](https://github.com/dotnet/fsharp/pull/16901), [PR #16973](https://github.com/dotnet/fsharp/pull/16973)) * Keep parens for problematic exprs (`if`, `match`, etc.) in `$"{(…):N0}"`, `$"{(…),-3}"`, etc. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578)) * Fix crash in DOTNET_SYSTEM_GLOBALIZATION_INVARIANT mode [#PR 16471](https://github.com/dotnet/fsharp/pull/16471)) * Fix16572 - Fixed the preview feature enabling Is properties for union case did not work correctly with let .rec and .fsi files ([PR #16657](https://github.com/dotnet/fsharp/pull/16657)) diff --git a/src/Compiler/Service/SynExpr.fs b/src/Compiler/Service/SynExpr.fs index db284ac36f..46bf646a21 100644 --- a/src/Compiler/Service/SynExpr.fs +++ b/src/Compiler/Service/SynExpr.fs @@ -657,7 +657,41 @@ module SynExpr = // return ( // x // ) - | _, SyntaxNode.SynExpr outer :: _ when containsSensitiveIndentation outer.Range.StartColumn expr.Range -> true + | _, SyntaxNode.SynExpr(SynExpr.YieldOrReturn _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.YieldOrReturnFrom _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.Assert _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.Lazy _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.App(argExpr = SynExpr.Paren(expr = Is expr)) as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.LetOrUse _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.LetOrUseBang _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.TryWith _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.TryFinally _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.For _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.ForEach _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.IfThenElse _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.New _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.Set(rhsExpr = SynExpr.Paren(expr = Is expr)) as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.DotIndexedSet(valueExpr = SynExpr.Paren(expr = Is expr)) as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.DotNamedIndexedPropertySet(rhsExpr = SynExpr.Paren(expr = Is expr)) as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.DotSet(rhsExpr = SynExpr.Paren(expr = Is expr)) as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.LibraryOnlyUnionCaseFieldSet(rhsExpr = SynExpr.Paren(expr = Is expr)) as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.LongIdentSet(expr = SynExpr.Paren(expr = Is expr)) as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.NamedIndexedPropertySet(expr2 = SynExpr.Paren(expr = Is expr)) as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.InferredUpcast _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.InferredDowncast _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.Match _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.MatchBang _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.While _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.WhileBang _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.Do _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.DoBang _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.Fixed _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.Record _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.AnonRecd _ as outer) :: _ + | _, SyntaxNode.SynExpr(SynExpr.InterpolatedString _ as outer) :: _ when + containsSensitiveIndentation outer.Range.StartColumn expr.Range + -> + true // Check for nested matches, e.g., // diff --git a/tests/FSharp.Compiler.Service.Tests/SynExprTests.fs b/tests/FSharp.Compiler.Service.Tests/SynExprTests.fs index 1e402a1d25..e0e664377b 100644 --- a/tests/FSharp.Compiler.Service.Tests/SynExprTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/SynExprTests.fs @@ -86,3 +86,37 @@ let shouldBeParenthesizedInContext (expected: Parenthesization list) src = | _ -> actual) CollectionAssert.AreEqual(expected, actual) + +[] +[] +[ ignore")>] +[] +[ ignore +")>] +[ ignore +")>] +let ``shouldBeParenthesizedInContext handles an unparenthesized hypothetical`` src = + let ast = getParseResults src + + let getSourceLineStr = + let lines = src.ReplaceLineEndings().Split '\n' + Line.toZ >> Array.get lines + + let expr, path = + (None, ast) + ||> ParsedInput.foldWhile (fun acc path node -> + match node with + | SyntaxNode.SynExpr (SynExpr.Const(SynConst.Int32 9, _) as expr) -> Some(Some(expr, path)) + | _ -> Some acc) + |> Option.defaultWith (fun () -> invalidOp "Expected a 9 but did not find one.") + + Assert.False(SynExpr.shouldBeParenthesizedInContext getSourceLineStr path expr)