@@ -456,6 +456,8 @@ module UnusedDeclarations =
456456module UnnecessaryParentheses =
457457 open System
458458
459+ let (| Ident |) ( ident : Ident ) = ident.idText
460+
459461 /// Represents an expression's precedence, or,
460462 /// for a few few types of expression whose exact
461463 /// kind can be significant, the expression's exact kind.
@@ -873,11 +875,27 @@ module UnnecessaryParentheses =
873875 | SynExpr.DotIndexedGet( objectExpr = SynExpr.Paren( expr = Is inner)) -> ValueSome( Dot, Left)
874876 | _ -> ValueNone
875877
878+ /// Matches a SynExpr.App nested in a sequence of dot-gets.
879+ ///
880+ /// x.M.N().O
881+ [<return : Struct>]
882+ let (| NestedApp | _ |) expr =
883+ let rec loop =
884+ function
885+ | SynExpr.DotGet ( expr = expr)
886+ | SynExpr.DotIndexedGet ( objectExpr = expr) -> loop expr
887+ | SynExpr.App _ -> ValueSome NestedApp
888+ | _ -> ValueNone
889+
890+ loop expr
891+
876892 /// Returns the given expression's precedence, if applicable.
877893 [<return : Struct>]
878894 let (| InnerBinaryExpr | _ |) expr : Precedence voption =
879895 match expr with
880896 | SynExpr.Tuple( isStruct = false ) -> ValueSome Comma
897+ | SynExpr.DotGet( expr = NestedApp)
898+ | SynExpr.DotIndexedGet( objectExpr = NestedApp) -> ValueSome Apply
881899 | SynExpr.DotGet _
882900 | SynExpr.DotIndexedGet _ -> ValueSome Dot
883901 | PrefixApp prec -> ValueSome prec
@@ -936,6 +954,13 @@ module UnnecessaryParentheses =
936954 | SynExpr.IfThenElse _ as expr -> Some expr
937955 | _ -> None)
938956
957+ /// Matches a dangling sequential expression.
958+ [<return : Struct>]
959+ let (| Sequential | _ |) =
960+ dangling ( function
961+ | SynExpr.Sequential _ as expr -> Some expr
962+ | _ -> None)
963+
939964 /// Matches a dangling try-with or try-finally construct.
940965 [<return : Struct>]
941966 let (| Try | _ |) =
@@ -1192,6 +1217,19 @@ module UnnecessaryParentheses =
11921217 SyntaxNode.SynExpr ( SynExpr.App _) :: SyntaxNode.SynExpr ( SynExpr.App( argExpr = SynExpr.ArrayOrListComputed( isArray = false ))) :: _ ->
11931218 ValueNone
11941219
1220+ // Parens must stay around binary equals expressions in argument
1221+ // position lest they be interpreted as named argument assignments:
1222+ //
1223+ // o.M((x = y))
1224+ // o.N((x = y), z)
1225+ | SynExpr.Paren( expr = SynExpr.Paren( expr = InfixApp ( Eq, _))),
1226+ SyntaxNode.SynExpr ( SynExpr.App( funcExpr = SynExpr.LongIdent _)) :: _
1227+ | SynExpr.Paren( expr = InfixApp ( Eq, _)),
1228+ SyntaxNode.SynExpr ( SynExpr.Paren _) :: SyntaxNode.SynExpr ( SynExpr.App( funcExpr = SynExpr.LongIdent _)) :: _
1229+ | SynExpr.Paren( expr = InfixApp ( Eq, _)),
1230+ SyntaxNode.SynExpr ( SynExpr.Tuple( isStruct = false )) :: SyntaxNode.SynExpr ( SynExpr.Paren _) :: SyntaxNode.SynExpr ( SynExpr.App( funcExpr = SynExpr.LongIdent _)) :: _ ->
1231+ ValueNone
1232+
11951233 // The :: operator is parsed differently from other symbolic infix operators,
11961234 // so we need to give it special treatment.
11971235
@@ -1249,6 +1287,8 @@ module UnnecessaryParentheses =
12491287 match outer, inner with
12501288 | ConfusableWithTypeApp, _ -> ValueNone
12511289
1290+ | SynExpr.IfThenElse _, Dangling.Sequential _ -> ValueNone
1291+
12521292 | SynExpr.IfThenElse ( trivia = trivia), Dangling.IfThen ifThenElse when
12531293 problematic ifThenElse.Range trivia.ThenKeyword
12541294 || trivia.ElseKeyword |> Option.exists ( problematic ifThenElse.Range)
@@ -1258,15 +1298,44 @@ module UnnecessaryParentheses =
12581298 | SynExpr.TryFinally ( trivia = trivia), Dangling.Try tryExpr when problematic tryExpr.Range trivia.FinallyKeyword ->
12591299 ValueNone
12601300
1261- | ( SynExpr.Match ( clauses = clauses) | SynExpr.MatchLambda ( matchClauses = clauses) | SynExpr.MatchBang ( clauses = clauses)),
1262- Dangling.Match matchOrTry when anyProblematic matchOrTry.Range clauses -> ValueNone
1301+ | SynExpr.Match ( clauses = clauses; trivia = { WithKeyword = withKeyword }), Dangling.Match matchOrTry when
1302+ problematic matchOrTry.Range withKeyword
1303+ || anyProblematic matchOrTry.Range clauses
1304+ ->
1305+ ValueNone
1306+
1307+ | SynExpr.MatchBang ( clauses = clauses; trivia = { WithKeyword = withKeyword }), Dangling.Match matchOrTry when
1308+ problematic matchOrTry.Range withKeyword
1309+ || anyProblematic matchOrTry.Range clauses
1310+ ->
1311+ ValueNone
1312+
1313+ | SynExpr.MatchLambda ( matchClauses = clauses), Dangling.Match matchOrTry when anyProblematic matchOrTry.Range clauses ->
1314+ ValueNone
12631315
12641316 | SynExpr.TryWith ( withCases = clauses; trivia = trivia), Dangling.Match matchOrTry when
1265- anyProblematic matchOrTry.Range clauses
1266- || problematic matchOrTry.Range trivia.WithKeyword
1317+ problematic matchOrTry.Range trivia.WithKeyword
1318+ || anyProblematic matchOrTry.Range clauses
12671319 ->
12681320 ValueNone
12691321
1322+ | SynExpr.Sequential( expr1 = SynExpr.Paren( expr = Is inner)), Dangling.Problematic _ -> ValueNone
1323+
1324+ | SynExpr.Paren _, SynExpr.Typed _
1325+ | SynExpr.Quote _, SynExpr.Typed _
1326+ | SynExpr.AnonRecd _, SynExpr.Typed _
1327+ | SynExpr.Record _, SynExpr.Typed _
1328+ | SynExpr.While( doExpr = SynExpr.Paren( expr = Is inner)), SynExpr.Typed _
1329+ | SynExpr.WhileBang( doExpr = SynExpr.Paren( expr = Is inner)), SynExpr.Typed _
1330+ | SynExpr.For( doBody = Is inner), SynExpr.Typed _
1331+ | SynExpr.ForEach( bodyExpr = Is inner), SynExpr.Typed _
1332+ | SynExpr.Match _, SynExpr.Typed _
1333+ | SynExpr.Do _, SynExpr.Typed _
1334+ | SynExpr.LetOrUse( body = Is inner), SynExpr.Typed _
1335+ | SynExpr.TryWith _, SynExpr.Typed _
1336+ | SynExpr.TryFinally _, SynExpr.Typed _ -> ValueSome range
1337+ | _, SynExpr.Typed _ -> ValueNone
1338+
12701339 | OuterBinaryExpr inner ( outerPrecedence, side), InnerBinaryExpr innerPrecedence ->
12711340 let ambiguous =
12721341 match Precedence.compare outerPrecedence innerPrecedence with
@@ -1295,31 +1364,6 @@ module UnnecessaryParentheses =
12951364 | OuterBinaryExpr inner (_, Right), ( SynExpr.Sequential _ | SynExpr.LetOrUse( trivia = { InKeyword = None })) -> ValueNone
12961365 | OuterBinaryExpr inner (_, Right), inner -> if dangling inner then ValueNone else ValueSome range
12971366
1298- | SynExpr.Typed _, SynExpr.Typed _
1299- | SynExpr.WhileBang( whileExpr = SynExpr.Paren( expr = Is inner)), SynExpr.Typed _
1300- | SynExpr.While( whileExpr = SynExpr.Paren( expr = Is inner)), SynExpr.Typed _
1301- | SynExpr.For( identBody = Is inner), SynExpr.Typed _
1302- | SynExpr.For( toBody = Is inner), SynExpr.Typed _
1303- | SynExpr.ForEach( enumExpr = Is inner), SynExpr.Typed _
1304- | SynExpr.ArrayOrList _, SynExpr.Typed _
1305- | SynExpr.ArrayOrListComputed _, SynExpr.Typed _
1306- | SynExpr.IndexRange _, SynExpr.Typed _
1307- | SynExpr.IndexFromEnd _, SynExpr.Typed _
1308- | SynExpr.ComputationExpr _, SynExpr.Typed _
1309- | SynExpr.Lambda _, SynExpr.Typed _
1310- | SynExpr.Assert _, SynExpr.Typed _
1311- | SynExpr.App _, SynExpr.Typed _
1312- | SynExpr.Lazy _, SynExpr.Typed _
1313- | SynExpr.LongIdentSet _, SynExpr.Typed _
1314- | SynExpr.DotSet _, SynExpr.Typed _
1315- | SynExpr.Set _, SynExpr.Typed _
1316- | SynExpr.DotIndexedSet _, SynExpr.Typed _
1317- | SynExpr.NamedIndexedPropertySet _, SynExpr.Typed _
1318- | SynExpr.Upcast _, SynExpr.Typed _
1319- | SynExpr.Downcast _, SynExpr.Typed _
1320- | SynExpr.AddressOf _, SynExpr.Typed _
1321- | SynExpr.JoinIn _, SynExpr.Typed _ -> ValueNone
1322-
13231367 // new T(expr)
13241368 | SynExpr.New _, AtomicExprAfterType -> ValueSome range
13251369 | SynExpr.New _, _ -> ValueNone
@@ -1331,7 +1375,6 @@ module UnnecessaryParentheses =
13311375 | _, SynExpr.Paren _
13321376 | _, SynExpr.Quote _
13331377 | _, SynExpr.Const _
1334- | _, SynExpr.Typed _
13351378 | _, SynExpr.Tuple( isStruct = true )
13361379 | _, SynExpr.AnonRecd _
13371380 | _, SynExpr.ArrayOrList _
@@ -1378,29 +1421,51 @@ module UnnecessaryParentheses =
13781421 | _ -> ValueNone
13791422
13801423 module SynPat =
1424+ [<return : Struct>]
1425+ let (| AnyTyped | _ |) pats =
1426+ if
1427+ pats
1428+ |> List.exists ( function
1429+ | SynPat.Typed _ -> true
1430+ | _ -> false )
1431+ then
1432+ ValueSome AnyTyped
1433+ else
1434+ ValueNone
1435+
13811436 /// If the given pattern is a parenthesized pattern and the parentheses
13821437 /// are unnecessary in the given context, returns the unnecessary parentheses' range.
13831438 let unnecessaryParentheses pat path =
1439+ let (| Last |) = List.last
1440+
13841441 match pat, path with
13851442 // Parens are needed in:
13861443 //
13871444 // let (Pattern …) = …
1445+ // let (x: …, y…) = …
1446+ // let (x: …), (y: …) = …
13881447 // let! (x: …) = …
13891448 // and! (x: …) = …
13901449 // use! (x: …) = …
13911450 // _.member M(x: …) = …
13921451 // match … with (x: …) -> …
1452+ // match … with (x, y: …) -> …
13931453 // function (x: …) -> …
13941454 // fun (x, y, …) -> …
13951455 // fun (x: …) -> …
13961456 // fun (Pattern …) -> …
1397- | SynPat.Paren _, SyntaxNode.SynExpr ( SynExpr.LetOrUseBang( pat = SynPat.Paren( pat = SynPat.Typed _))) :: _
1398- | SynPat.Paren _, SyntaxNode.SynMatchClause ( SynMatchClause( pat = SynPat.Paren( pat = SynPat.Typed _))) :: _
1399- | SynPat.Paren( pat = SynPat.LongIdent _), SyntaxNode.SynBinding _ :: _
1400- | SynPat.Paren( pat = SynPat.LongIdent _), SyntaxNode.SynExpr ( SynExpr.Lambda _) :: _
1401- | SynPat.Paren _, SyntaxNode.SynExpr ( SynExpr.Lambda( args = SynSimplePats.SimplePats( pats = _ :: _ :: _))) :: _
1402- | SynPat.Paren _, SyntaxNode.SynExpr ( SynExpr.Lambda( args = SynSimplePats.SimplePats( pats = [ SynSimplePat.Typed _ ]))) :: _ ->
1403- ValueNone
1457+ | SynPat.Paren ( SynPat.Typed _, _), SyntaxNode.SynExpr ( SynExpr.LetOrUseBang _) :: _
1458+ | SynPat.Paren ( SynPat.Typed _, _), SyntaxNode.SynPat ( SynPat.Tuple _) :: SyntaxNode.SynExpr ( SynExpr.LetOrUseBang _) :: _
1459+ | SynPat.Paren ( SynPat.Tuple ( isStruct = false ; elementPats = AnyTyped), _), SyntaxNode.SynExpr ( SynExpr.LetOrUseBang _) :: _
1460+ | SynPat.Paren ( SynPat.Typed _, _), SyntaxNode.SynMatchClause _ :: _
1461+ | SynPat.Paren ( SynPat.Typed _, _), SyntaxNode.SynPat ( SynPat.Tuple _) :: SyntaxNode.SynMatchClause _ :: _
1462+ | SynPat.Paren ( SynPat.Tuple ( isStruct = false ; elementPats = Last ( SynPat.Typed _)), _), SyntaxNode.SynMatchClause _ :: _
1463+ | SynPat.Paren ( SynPat.Typed _, _), SyntaxNode.SynPat ( SynPat.Tuple _) :: SyntaxNode.SynBinding _ :: _
1464+ | SynPat.Paren ( SynPat.Tuple ( isStruct = false ; elementPats = AnyTyped), _), SyntaxNode.SynBinding _ :: _
1465+ | SynPat.Paren ( SynPat.LongIdent _, _), SyntaxNode.SynBinding _ :: _
1466+ | SynPat.Paren ( SynPat.LongIdent _, _), SyntaxNode.SynExpr ( SynExpr.Lambda _) :: _
1467+ | SynPat.Paren ( SynPat.Tuple( isStruct = false ), _), SyntaxNode.SynExpr ( SynExpr.Lambda( parsedData = Some _)) :: _
1468+ | SynPat.Paren ( SynPat.Typed _, _), SyntaxNode.SynExpr ( SynExpr.Lambda( parsedData = Some _)) :: _ -> ValueNone
14041469
14051470 // () is parsed as this in certain cases…
14061471 //
@@ -1415,6 +1480,24 @@ module UnnecessaryParentheses =
14151480 | SynPat.Paren ( SynPat.Const ( SynConst.Unit, _), _), SyntaxNode.SynExpr ( SynExpr.LetOrUseBang _) :: _
14161481 | SynPat.Paren ( SynPat.Const ( SynConst.Unit, _), _), SyntaxNode.SynMatchClause _ :: _ -> ValueNone
14171482
1483+ // (()) is required when overriding a generic member
1484+ // where unit is the generic type argument:
1485+ //
1486+ // type C<'T> = abstract M : 'T -> unit
1487+ // let _ = { new C<unit> with override _.M (()) = () }
1488+ | SynPat.Paren ( SynPat.Paren ( SynPat.Const ( SynConst.Unit, _), _), _),
1489+ SyntaxNode.SynPat ( SynPat.LongIdent _) :: SyntaxNode.SynBinding _ :: _
1490+ | SynPat.Paren ( SynPat.Const ( SynConst.Unit, _), _),
1491+ SyntaxNode.SynPat ( SynPat.Paren _) :: SyntaxNode.SynPat ( SynPat.LongIdent _) :: SyntaxNode.SynBinding _ :: _ -> ValueNone
1492+
1493+ // Parens are required for the first of multiple additional constructors.
1494+ // We simply require them always.
1495+ //
1496+ // type T … =
1497+ // new (x) = …
1498+ // new (x, y) = …
1499+ | SynPat.Paren _, SyntaxNode.SynPat ( SynPat.LongIdent( longDotId = SynLongIdent( id = [ Ident " new" ]))) :: _ -> ValueNone
1500+
14181501 // Parens are otherwise never needed in these cases:
14191502 //
14201503 // let (x: …) = …
@@ -1437,7 +1520,9 @@ module UnnecessaryParentheses =
14371520 | SynPat.Paren ( inner, range), SyntaxNode.SynPat outer :: _ ->
14381521 match outer, inner with
14391522 // (x :: xs) :: ys
1440- | SynPat.ListCons( lhsPat = SynPat.Paren( pat = Is inner)), SynPat.ListCons _ -> ValueNone
1523+ // (x, xs) :: ys
1524+ | SynPat.ListCons( lhsPat = SynPat.Paren( pat = Is inner)), SynPat.ListCons _
1525+ | SynPat.ListCons( lhsPat = SynPat.Paren( pat = Is inner)), SynPat.Tuple( isStruct = false ) -> ValueNone
14411526
14421527 // A as (B | C)
14431528 // A as (B & C)
0 commit comments