diff --git a/docs/release-notes/FSharp.Compiler.Service/8.0.200.md b/docs/release-notes/FSharp.Compiler.Service/8.0.200.md index c0d199a7864..e42b66576bf 100644 --- a/docs/release-notes/FSharp.Compiler.Service/8.0.200.md +++ b/docs/release-notes/FSharp.Compiler.Service/8.0.200.md @@ -1,2 +1,3 @@ -- Miscellaneous fixes to parens analysis - https://github.com/dotnet/fsharp/pull/16262 -- Fixes #16359 - correctly handle imports with 0 length public key tokens - https://github.com/dotnet/fsharp/pull/16363 \ No newline at end of file +- Parens analysis: miscellaneous fixes - https://github.com/dotnet/fsharp/pull/16262 +- Parens analysis: fix some parenthesization corner-cases in record expressions - https://github.com/dotnet/fsharp/pull/16370 +- Fixes #16359 - correctly handle imports with 0 length public key tokens - https://github.com/dotnet/fsharp/pull/16363 diff --git a/src/Compiler/Service/ServiceAnalysis.fs b/src/Compiler/Service/ServiceAnalysis.fs index 09dc977ec81..08852434016 100644 --- a/src/Compiler/Service/ServiceAnalysis.fs +++ b/src/Compiler/Service/ServiceAnalysis.fs @@ -1325,6 +1325,36 @@ module UnnecessaryParentheses = -> ValueNone + | SynExpr.Record(copyInfo = Some(SynExpr.Paren(expr = Is inner), _)), Dangling.Problematic _ + | SynExpr.AnonRecd(copyInfo = Some(SynExpr.Paren(expr = Is inner), _)), Dangling.Problematic _ -> ValueNone + + | SynExpr.Record(recordFields = recordFields), Dangling.Problematic _ -> + let rec loop recordFields = + match recordFields with + | [] -> ValueSome range + | SynExprRecordField(expr = Some(SynExpr.Paren(expr = Is inner)); blockSeparator = Some _) :: SynExprRecordField( + fieldName = SynLongIdent(id = id :: _), _) :: _ -> + if problematic inner.Range id.idRange then + ValueNone + else + ValueSome range + | _ :: recordFields -> loop recordFields + + loop recordFields + + | SynExpr.AnonRecd(recordFields = recordFields), Dangling.Problematic _ -> + let rec loop recordFields = + match recordFields with + | [] -> ValueSome range + | (_, Some _blockSeparator, SynExpr.Paren(expr = Is inner)) :: (SynLongIdent(id = id :: _), _, _) :: _ -> + if problematic inner.Range id.idRange then + ValueNone + else + ValueSome range + | _ :: recordFields -> loop recordFields + + loop recordFields + | SynExpr.Paren _, SynExpr.Typed _ | SynExpr.Quote _, SynExpr.Typed _ | SynExpr.AnonRecd _, SynExpr.Typed _ diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs index 27bce12bb2d..71338a6895b 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs @@ -919,6 +919,48 @@ in x // AnonRecd "id ({||})", "id {||}" + "{| A = (fun () -> ()) |}", "{| A = fun () -> () |}" + "{| A = (fun () -> ()); B = 3 |}", "{| A = (fun () -> ()); B = 3 |}" + "{| A = (let x = 3 in x); B = 3 |}", "{| A = (let x = 3 in x); B = 3 |}" + "{| (try {||} with _ -> reraise ()) with A = 4 |}", "{| (try {||} with _ -> reraise ()) with A = 4 |}" + + " + {| A = (fun () -> ()) + B = 3 |} + ", + " + {| A = fun () -> () + B = 3 |} + " + + " + {| A = (fun () -> ()); B = (fun () -> ()) + C = 3 |} + ", + " + {| A = (fun () -> ()); B = fun () -> () + C = 3 |} + " + + " + {| A = (let x = 3 in x) + B = 3 |} + ", + " + {| A = let x = 3 in x + B = 3 |} + " + + " + {| (try {||} with _ -> reraise ()) + with + A = 4 |} + ", + " + {| (try {||} with _ -> reraise ()) + with + A = 4 |} + " // ArrayOrList "id ([])", "id []" @@ -928,6 +970,49 @@ in x // Record "id ({ A = x })", "id { A = x }" + "{ A = (fun () -> ()) }", "{ A = fun () -> () }" + "{ A = (fun () -> ()); B = 3 }", "{ A = (fun () -> ()); B = 3 }" + "{ A = (let x = 3 in x); B = 3 }", "{ A = (let x = 3 in x); B = 3 }" + "{ A.B.C.D.X = (match () with () -> ()); A.B.C.D.Y = 3 }", "{ A.B.C.D.X = (match () with () -> ()); A.B.C.D.Y = 3 }" + "{ (try { A = 3 } with _ -> reraise ()) with A = 4 }", "{ (try { A = 3 } with _ -> reraise ()) with A = 4 }" + + " + { A = (fun () -> ()) + B = 3 } + ", + " + { A = fun () -> () + B = 3 } + " + + " + { A = (let x = 3 in x) + B = 3 } + ", + " + { A = let x = 3 in x + B = 3 } + " + + " + { A.B.C.D.X = (match () with () -> ()) + A.B.C.D.Y = 3 } + ", + " + { A.B.C.D.X = match () with () -> () + A.B.C.D.Y = 3 } + " + + " + { (try { A = 3 } with _ -> reraise ()) + with + A = 4 } + ", + " + { (try { A = 3 } with _ -> reraise ()) + with + A = 4 } + " // New "id (new obj())", "id (new obj())"