Skip to content

Commit 502aeff

Browse files
Handle special parsing of new T… & inherit T… (#16239)
* Handle special parsing of `new T…` & `inherit T…` * Ctor applications are handled differently in the parser after the `new` and `inherit` keywords than they are elsewhere: only a subset of expressions are allowed as an argument (as specified in `atomicExprAfterType` in pars.fsy). This means that any expression outside of that blessed subset must be parenthesized, even if the exact same ctor application would not require parentheses without `new` or `inherit`. * Fantomas * Arrays only * Fantomas * Clean up comments
1 parent 24ef671 commit 502aeff

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

src/Compiler/Service/ServiceAnalysis.fs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,22 @@ module UnnecessaryParentheses =
692692
module SynExpr =
693693
open FSharp.Compiler.SyntaxTrivia
694694

695+
/// See atomicExprAfterType in pars.fsy.
696+
[<return: Struct>]
697+
let (|AtomicExprAfterType|_|) expr =
698+
match expr with
699+
| SynExpr.Paren _
700+
| SynExpr.Quote _
701+
| SynExpr.Const _
702+
| SynExpr.Tuple(isStruct = true)
703+
| SynExpr.Record _
704+
| SynExpr.AnonRecd _
705+
| SynExpr.InterpolatedString _
706+
| SynExpr.Null _
707+
| SynExpr.ArrayOrList(isArray = true)
708+
| SynExpr.ArrayOrListComputed(isArray = true) -> ValueSome AtomicExprAfterType
709+
| _ -> ValueNone
710+
695711
/// Matches if the given expression represents a high-precedence
696712
/// function application, e.g.,
697713
///
@@ -1142,6 +1158,18 @@ module UnnecessaryParentheses =
11421158
| SynExpr.Paren(expr = SynExpr.App _), SyntaxNode.SynExpr (SynExpr.App _) :: SyntaxNode.SynExpr (SynExpr.JoinIn _) :: _ ->
11431159
ValueNone
11441160

1161+
// Parens are not required around a few anointed expressions after inherit:
1162+
//
1163+
// inherit T(3)
1164+
// inherit T(null)
1165+
// inherit T("")
1166+
// …
1167+
| SynExpr.Paren (expr = AtomicExprAfterType; range = range), SyntaxNode.SynMemberDefn (SynMemberDefn.ImplicitInherit _) :: _ ->
1168+
ValueSome range
1169+
1170+
// Parens are otherwise required in inherit T(x), etc.
1171+
| SynExpr.Paren _, SyntaxNode.SynMemberDefn (SynMemberDefn.ImplicitInherit _) :: _ -> ValueNone
1172+
11451173
// We can't remove parens when they're required for fluent calls:
11461174
//
11471175
// x.M(y).N z
@@ -1284,6 +1312,14 @@ module UnnecessaryParentheses =
12841312
| SynExpr.AddressOf _, SynExpr.Typed _
12851313
| SynExpr.JoinIn _, SynExpr.Typed _ -> ValueNone
12861314

1315+
// new T(expr)
1316+
| SynExpr.New _, AtomicExprAfterType -> ValueSome range
1317+
| SynExpr.New _, _ -> ValueNone
1318+
1319+
// { inherit T(expr); … }
1320+
| SynExpr.Record(baseInfo = Some (_, SynExpr.Paren(expr = Is inner), _, _, _)), AtomicExprAfterType -> ValueSome range
1321+
| SynExpr.Record(baseInfo = Some (_, SynExpr.Paren(expr = Is inner), _, _, _)), _ -> ValueNone
1322+
12871323
| _, SynExpr.Paren _
12881324
| _, SynExpr.Quote _
12891325
| _, SynExpr.Const _

vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ let _ =
127127
// New
128128
"new exn(null)", "new exn null"
129129
"new exn (null)", "new exn null"
130+
"new ResizeArray<int>(3)", "new ResizeArray<int> 3"
131+
"let x = 3 in new ResizeArray<int>(x)", "let x = 3 in new ResizeArray<int>(x)"
132+
"ResizeArray<int>([3])", "ResizeArray<int> [3]"
133+
"new ResizeArray<int>([3])", "new ResizeArray<int>([3])"
134+
"ResizeArray<int>([|3|])", "ResizeArray<int> [|3|]"
135+
"new ResizeArray<int>([|3|])", "new ResizeArray<int> [|3|]"
130136

131137
// ObjExpr
132138
"{ new System.IDisposable with member _.Dispose () = (ignore 3) }",
@@ -1091,6 +1097,50 @@ let builder = Builder ()
10911097
let (+) _ _ = builder
10921098
let _ = (2 + 2) { return 5 }
10931099
"
1100+
1101+
"""
1102+
type E (message : string) =
1103+
inherit exn ($"{message}")
1104+
""",
1105+
"""
1106+
type E (message : string) =
1107+
inherit exn $"{message}"
1108+
"""
1109+
1110+
"
1111+
type E (message : string) =
1112+
inherit exn (message)
1113+
",
1114+
"
1115+
type E (message : string) =
1116+
inherit exn (message)
1117+
"
1118+
1119+
"""
1120+
type E =
1121+
inherit exn
1122+
val Message2 : string
1123+
new (str1, str2) = { inherit exn ($"{str1}"); Message2 = str2 }
1124+
""",
1125+
"""
1126+
type E =
1127+
inherit exn
1128+
val Message2 : string
1129+
new (str1, str2) = { inherit exn $"{str1}"; Message2 = str2 }
1130+
"""
1131+
1132+
"
1133+
type E =
1134+
inherit exn
1135+
val Message2 : string
1136+
new (str1, str2) = { inherit exn (str1); Message2 = str2 }
1137+
",
1138+
"
1139+
type E =
1140+
inherit exn
1141+
val Message2 : string
1142+
new (str1, str2) = { inherit exn (str1); Message2 = str2 }
1143+
"
10941144
}
10951145

10961146
[<Theory; MemberData(nameof moreComplexApps)>]

0 commit comments

Comments
 (0)