Skip to content

Commit 4d5e5e2

Browse files
authored
Capture then + expr in new node (#3075)
* Update FCS to 050271d631956a4e0d0484a583d38236b727a46d, introduce new node to capture then + expr. * Add changelog entry.
1 parent fe0c0b7 commit 4d5e5e2

File tree

7 files changed

+88
-26
lines changed

7 files changed

+88
-26
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## 6.3.2 - 2024-04-12
4+
5+
### Changed
6+
* Update FCS to 'Add SynExprSequentialTrivia', commit 050271d631956a4e0d0484a583d38236b727a46d [#3075](https://github.com/fsprojects/fantomas/pull/3075)
7+
8+
### Fixed
9+
* Fantomas corrupts an explicit constructor with then clause. [#3074](https://github.com/fsprojects/fantomas/issues/3074)
10+
311
## 6.3.1 - 2024-03-30
412

513
### Fixed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Some common use cases include:
4646

4747
<!-- Versions -->
4848
<PropertyGroup>
49-
<FCSCommitHash>1da032a64321c77782e8d125afd3bf29863c3d9c</FCSCommitHash>
49+
<FCSCommitHash>050271d631956a4e0d0484a583d38236b727a46d</FCSCommitHash>
5050
</PropertyGroup>
5151

5252
<PropertyGroup>

src/Fantomas.Core.Tests/ASTTransformerTests.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ let ``avoid stack-overflow in long array/list, 2485`` () =
2727
true,
2828
mkStringExpr (),
2929
childExpr,
30-
Range.Zero
30+
Range.Zero,
31+
SynExprSequentialTrivia.Zero
3132
))
3233

3334
SynExpr.ArrayOrListComputed(true, mkArray 0 (mkStringExpr ()), Range.Zero)

src/Fantomas.Core.Tests/ConstructorTests.fs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,40 @@ type StateMachine
165165
=
166166
StateMachine()
167167
"""
168+
169+
[<Test>]
170+
let ``explicit constructor with then keyword, 3074`` () =
171+
formatSourceString
172+
"""
173+
type CreateBuildingViewModel =
174+
new (items) as vm
175+
=
176+
let p = ""
177+
{
178+
inherit ResizeArray(seq {
179+
yield p
180+
yield! items
181+
})
182+
}
183+
then
184+
vm.program <- p
185+
"""
186+
config
187+
|> prepend newline
188+
|> should
189+
equal
190+
"""
191+
type CreateBuildingViewModel =
192+
new(items) as vm =
193+
let p = ""
194+
195+
{ inherit
196+
ResizeArray(
197+
seq {
198+
yield p
199+
yield! items
200+
}
201+
) }
202+
203+
then vm.program <- p
204+
"""

src/Fantomas.Core/ASTTransformer.fs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,18 @@ let mkAttributes (creationAide: CreationAide) (al: SynAttributeList list) : Mult
213213
let range = attributeLists |> List.map (fun al -> al.Range) |> combineRanges
214214
Some(MultipleAttributeListNode(attributeLists, range))
215215

216+
/// Only used to get items of SynExpr.ArrayOrListComputed
217+
/// We can safely assume the SequentialTrivia.SeparatorRange is not going to be `then`.
216218
let (|Sequentials|_|) e =
217219
let rec visit (e: SynExpr) (finalContinuation: SynExpr list -> SynExpr list) : SynExpr list =
218220
match e with
219-
| SynExpr.Sequential(_, _, e1, e2, _) -> visit e2 (fun xs -> e1 :: xs |> finalContinuation)
221+
| SynExpr.Sequential(expr1 = e1; expr2 = e2) ->
222+
223+
visit e2 (fun xs -> e1 :: xs |> finalContinuation)
220224
| e -> finalContinuation [ e ]
221225

222226
match e with
223-
| SynExpr.Sequential(_, _, e1, e2, _) ->
227+
| SynExpr.Sequential(expr1 = e1; expr2 = e2) ->
224228
let xs = visit e2 id
225229
Some(e1 :: xs)
226230
| _ -> None
@@ -332,12 +336,25 @@ let rec collectComputationExpressionStatements
332336

333337
collectComputationExpressionStatements creationAide body (fun bodyStatements ->
334338
[ letOrUseBang; yield! andBangs; yield! bodyStatements ] |> finalContinuation)
335-
| SynExpr.Sequential(_, _, e1, e2, _) ->
339+
| SynExpr.Sequential(expr1 = e1; expr2 = e2; trivia = trivia) ->
336340
let continuations
337341
: ((ComputationExpressionStatement list -> ComputationExpressionStatement list)
338342
-> ComputationExpressionStatement list) list =
339-
[ collectComputationExpressionStatements creationAide e1
340-
collectComputationExpressionStatements creationAide e2 ]
343+
let c2 =
344+
match trivia.SeparatorRange with
345+
// detect then keyword in explicit constructor
346+
| Some mThen when mThen.StartColumn + 4 = mThen.EndColumn ->
347+
let thenNode = stn "then" mThen
348+
let expr = mkExpr creationAide e2
349+
let m = unionRanges mThen e2.Range
350+
let node = ExprExplicitConstructorThenExpr(thenNode, expr, m)
351+
352+
fun finalContinuation ->
353+
finalContinuation
354+
[ ComputationExpressionStatement.OtherStatement(Expr.ExplicitConstructorThenExpr node) ]
355+
| _ -> collectComputationExpressionStatements creationAide e2
356+
357+
[ collectComputationExpressionStatements creationAide e1; c2 ]
341358

342359
let finalContinuation (nodes: ComputationExpressionStatement list list) : ComputationExpressionStatement list =
343360
List.collect id nodes |> finalContinuation
@@ -2732,10 +2749,7 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
27322749
accessibility = ao)
27332750
expr = expr
27342751
trivia = { EqualsRange = Some mEq })) when (newIdent.idText = "new") ->
2735-
let exprNode, thenExprNode =
2736-
match expr with
2737-
| SynExpr.Sequential(_, false, e1, e2, _) -> mkExpr creationAide e1, Some(mkExpr creationAide e2)
2738-
| e -> mkExpr creationAide e, None
2752+
let exprNode = mkExpr creationAide expr
27392753

27402754
MemberDefnExplicitCtorNode(
27412755
mkXmlDoc px,
@@ -2746,7 +2760,6 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
27462760
Option.map mkIdent ido,
27472761
stn "=" mEq,
27482762
exprNode,
2749-
thenExprNode,
27502763
memberDefinitionRange
27512764
)
27522765
|> MemberDefn.ExplicitCtor

src/Fantomas.Core/CodePrinter.fs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,10 @@ let genExpr (e: Expr) =
15721572
+> genSingleTextNode node.End
15731573

15741574
expressionFitsOnRestOfLine short long |> genNode node
1575+
| Expr.ExplicitConstructorThenExpr node ->
1576+
genSingleTextNode node.Then
1577+
+> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr node.Expr)
1578+
|> genNode node
15751579

15761580
let genQuoteExpr (node: ExprQuoteNode) =
15771581
genSingleTextNode node.OpenToken
@@ -3786,15 +3790,7 @@ let genMemberDefn (md: MemberDefn) =
37863790
+> autoIndentAndNlnIfExpressionExceedsPageWidth (genLongParenPatParameter node.Pattern)
37873791
+> optSingle (fun alias -> sepSpace +> !- "as" +> sepSpace +> genSingleTextNode alias) node.Alias)
37883792
(fun isMultiline ctx ->
3789-
let genExpr =
3790-
genExpr node.Expr
3791-
+> optSingle
3792-
(fun thenExpr ->
3793-
sepNln
3794-
+> !- "then"
3795-
+> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr thenExpr))
3796-
node.ThenExpr
3797-
3793+
let genExpr = genExpr node.Expr
37983794
let short = genSingleTextNode node.Equals +> sepSpace +> genExpr
37993795

38003796
let long ctx =
@@ -3810,7 +3806,7 @@ let genMemberDefn (md: MemberDefn) =
38103806

38113807
genXml node.XmlDoc
38123808
+> genAttributes node.Attributes
3813-
+> ifElse node.ThenExpr.IsSome long (expressionFitsOnRestOfLine short long)
3809+
+> expressionFitsOnRestOfLine short long
38143810
|> genNode (MemberDefn.Node md)
38153811
| MemberDefn.LetBinding node -> genBindings true node.Bindings |> genNode (MemberDefn.Node md)
38163812
| MemberDefn.Interface node ->

src/Fantomas.Core/SyntaxOak.fs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,6 +1649,14 @@ type ExprBeginEndNode(beginNode: SingleTextNode, expr: Expr, endNode: SingleText
16491649
member val Expr = expr
16501650
member val End = endNode
16511651

1652+
/// then <expr>
1653+
/// Only valid in secondary constructors, original coming from SynExpr.Sequential(trivia = { SeparatorRange = Some mThen })
1654+
type ExprExplicitConstructorThenExpr(thenNode: SingleTextNode, expr: Expr, range) =
1655+
inherit NodeBase(range)
1656+
override val Children: Node array = [| yield thenNode; yield Expr.Node expr |]
1657+
member val Then = thenNode
1658+
member val Expr = expr
1659+
16521660
[<RequireQualifiedAccess; NoEquality; NoComparison>]
16531661
type Expr =
16541662
| Lazy of ExprLazyNode
@@ -1715,6 +1723,7 @@ type Expr =
17151723
| Chain of ExprChain
17161724
| DotLambda of ExprDotLambda
17171725
| BeginEnd of ExprBeginEndNode
1726+
| ExplicitConstructorThenExpr of ExprExplicitConstructorThenExpr
17181727

17191728
static member Node(x: Expr) : Node =
17201729
match x with
@@ -1782,6 +1791,7 @@ type Expr =
17821791
| Chain n -> n
17831792
| DotLambda n -> n
17841793
| BeginEnd n -> n
1794+
| ExplicitConstructorThenExpr n -> n
17851795

17861796
member e.HasParentheses: bool =
17871797
match e with
@@ -2399,7 +2409,6 @@ type MemberDefnExplicitCtorNode
23992409
alias: SingleTextNode option,
24002410
equals: SingleTextNode,
24012411
expr: Expr,
2402-
thenExpr: Expr option,
24032412
range
24042413
) =
24052414
inherit NodeBase(range)
@@ -2412,8 +2421,7 @@ type MemberDefnExplicitCtorNode
24122421
yield Pattern.Node pat
24132422
yield! noa alias
24142423
yield equals
2415-
yield Expr.Node expr
2416-
yield! noa (Option.map Expr.Node thenExpr) |]
2424+
yield Expr.Node expr |]
24172425

24182426
member val XmlDoc = xmlDoc
24192427
member val Attributes = attributes
@@ -2423,7 +2431,6 @@ type MemberDefnExplicitCtorNode
24232431
member val Alias = alias
24242432
member val Equals = equals
24252433
member val Expr = expr
2426-
member val ThenExpr = thenExpr
24272434

24282435
type MemberDefnInterfaceNode
24292436
(interfaceNode: SingleTextNode, t: Type, withNode: SingleTextNode option, members: MemberDefn list, range) =

0 commit comments

Comments
 (0)