Skip to content

Commit

Permalink
Handle special parsing of new T… & inherit T… (#16239)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
brianrourkeboll authored Nov 8, 2023
1 parent 24ef671 commit 502aeff
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 0 deletions.
36 changes: 36 additions & 0 deletions src/Compiler/Service/ServiceAnalysis.fs
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,22 @@ module UnnecessaryParentheses =
module SynExpr =
open FSharp.Compiler.SyntaxTrivia

/// See atomicExprAfterType in pars.fsy.
[<return: Struct>]
let (|AtomicExprAfterType|_|) expr =
match expr with
| SynExpr.Paren _
| SynExpr.Quote _
| SynExpr.Const _
| SynExpr.Tuple(isStruct = true)
| SynExpr.Record _
| SynExpr.AnonRecd _
| SynExpr.InterpolatedString _
| SynExpr.Null _
| SynExpr.ArrayOrList(isArray = true)
| SynExpr.ArrayOrListComputed(isArray = true) -> ValueSome AtomicExprAfterType
| _ -> ValueNone

/// Matches if the given expression represents a high-precedence
/// function application, e.g.,
///
Expand Down Expand Up @@ -1142,6 +1158,18 @@ module UnnecessaryParentheses =
| SynExpr.Paren(expr = SynExpr.App _), SyntaxNode.SynExpr (SynExpr.App _) :: SyntaxNode.SynExpr (SynExpr.JoinIn _) :: _ ->
ValueNone

// Parens are not required around a few anointed expressions after inherit:
//
// inherit T(3)
// inherit T(null)
// inherit T("")
// …
| SynExpr.Paren (expr = AtomicExprAfterType; range = range), SyntaxNode.SynMemberDefn (SynMemberDefn.ImplicitInherit _) :: _ ->
ValueSome range

// Parens are otherwise required in inherit T(x), etc.
| SynExpr.Paren _, SyntaxNode.SynMemberDefn (SynMemberDefn.ImplicitInherit _) :: _ -> ValueNone

// We can't remove parens when they're required for fluent calls:
//
// x.M(y).N z
Expand Down Expand Up @@ -1284,6 +1312,14 @@ module UnnecessaryParentheses =
| SynExpr.AddressOf _, SynExpr.Typed _
| SynExpr.JoinIn _, SynExpr.Typed _ -> ValueNone

// new T(expr)
| SynExpr.New _, AtomicExprAfterType -> ValueSome range
| SynExpr.New _, _ -> ValueNone

// { inherit T(expr); … }
| SynExpr.Record(baseInfo = Some (_, SynExpr.Paren(expr = Is inner), _, _, _)), AtomicExprAfterType -> ValueSome range
| SynExpr.Record(baseInfo = Some (_, SynExpr.Paren(expr = Is inner), _, _, _)), _ -> ValueNone

| _, SynExpr.Paren _
| _, SynExpr.Quote _
| _, SynExpr.Const _
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ let _ =
// New
"new exn(null)", "new exn null"
"new exn (null)", "new exn null"
"new ResizeArray<int>(3)", "new ResizeArray<int> 3"
"let x = 3 in new ResizeArray<int>(x)", "let x = 3 in new ResizeArray<int>(x)"
"ResizeArray<int>([3])", "ResizeArray<int> [3]"
"new ResizeArray<int>([3])", "new ResizeArray<int>([3])"
"ResizeArray<int>([|3|])", "ResizeArray<int> [|3|]"
"new ResizeArray<int>([|3|])", "new ResizeArray<int> [|3|]"

// ObjExpr
"{ new System.IDisposable with member _.Dispose () = (ignore 3) }",
Expand Down Expand Up @@ -1091,6 +1097,50 @@ let builder = Builder ()
let (+) _ _ = builder
let _ = (2 + 2) { return 5 }
"

"""
type E (message : string) =
inherit exn ($"{message}")
""",
"""
type E (message : string) =
inherit exn $"{message}"
"""

"
type E (message : string) =
inherit exn (message)
",
"
type E (message : string) =
inherit exn (message)
"

"""
type E =
inherit exn
val Message2 : string
new (str1, str2) = { inherit exn ($"{str1}"); Message2 = str2 }
""",
"""
type E =
inherit exn
val Message2 : string
new (str1, str2) = { inherit exn $"{str1}"; Message2 = str2 }
"""

"
type E =
inherit exn
val Message2 : string
new (str1, str2) = { inherit exn (str1); Message2 = str2 }
",
"
type E =
inherit exn
val Message2 : string
new (str1, str2) = { inherit exn (str1); Message2 = str2 }
"
}

[<Theory; MemberData(nameof moreComplexApps)>]
Expand Down

0 comments on commit 502aeff

Please sign in to comment.