Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 6.3.2 - 2024-04-12

### Changed
* Update FCS to 'Add SynExprSequentialTrivia', commit 050271d631956a4e0d0484a583d38236b727a46d [#3075](https://github.com/fsprojects/fantomas/pull/3075)

### Fixed
* Fantomas corrupts an explicit constructor with then clause. [#3074](https://github.com/fsprojects/fantomas/issues/3074)

## 6.3.1 - 2024-03-30

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Some common use cases include:

<!-- Versions -->
<PropertyGroup>
<FCSCommitHash>1da032a64321c77782e8d125afd3bf29863c3d9c</FCSCommitHash>
<FCSCommitHash>050271d631956a4e0d0484a583d38236b727a46d</FCSCommitHash>
</PropertyGroup>

<PropertyGroup>
Expand Down
3 changes: 2 additions & 1 deletion src/Fantomas.Core.Tests/ASTTransformerTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ let ``avoid stack-overflow in long array/list, 2485`` () =
true,
mkStringExpr (),
childExpr,
Range.Zero
Range.Zero,
SynExprSequentialTrivia.Zero
))

SynExpr.ArrayOrListComputed(true, mkArray 0 (mkStringExpr ()), Range.Zero)
Expand Down
37 changes: 37 additions & 0 deletions src/Fantomas.Core.Tests/ConstructorTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,40 @@ type StateMachine
=
StateMachine()
"""

[<Test>]
let ``explicit constructor with then keyword, 3074`` () =
formatSourceString
"""
type CreateBuildingViewModel =
new (items) as vm
=
let p = ""
{
inherit ResizeArray(seq {
yield p
yield! items
})
}
then
vm.program <- p
"""
config
|> prepend newline
|> should
equal
"""
type CreateBuildingViewModel =
new(items) as vm =
let p = ""

{ inherit
ResizeArray(
seq {
yield p
yield! items
}
) }

then vm.program <- p
"""
33 changes: 23 additions & 10 deletions src/Fantomas.Core/ASTTransformer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,18 @@ let mkAttributes (creationAide: CreationAide) (al: SynAttributeList list) : Mult
let range = attributeLists |> List.map (fun al -> al.Range) |> combineRanges
Some(MultipleAttributeListNode(attributeLists, range))

/// Only used to get items of SynExpr.ArrayOrListComputed
/// We can safely assume the SequentialTrivia.SeparatorRange is not going to be `then`.
let (|Sequentials|_|) e =
let rec visit (e: SynExpr) (finalContinuation: SynExpr list -> SynExpr list) : SynExpr list =
match e with
| SynExpr.Sequential(_, _, e1, e2, _) -> visit e2 (fun xs -> e1 :: xs |> finalContinuation)
| SynExpr.Sequential(expr1 = e1; expr2 = e2) ->

visit e2 (fun xs -> e1 :: xs |> finalContinuation)
| e -> finalContinuation [ e ]

match e with
| SynExpr.Sequential(_, _, e1, e2, _) ->
| SynExpr.Sequential(expr1 = e1; expr2 = e2) ->
let xs = visit e2 id
Some(e1 :: xs)
| _ -> None
Expand Down Expand Up @@ -332,12 +336,25 @@ let rec collectComputationExpressionStatements

collectComputationExpressionStatements creationAide body (fun bodyStatements ->
[ letOrUseBang; yield! andBangs; yield! bodyStatements ] |> finalContinuation)
| SynExpr.Sequential(_, _, e1, e2, _) ->
| SynExpr.Sequential(expr1 = e1; expr2 = e2; trivia = trivia) ->
let continuations
: ((ComputationExpressionStatement list -> ComputationExpressionStatement list)
-> ComputationExpressionStatement list) list =
[ collectComputationExpressionStatements creationAide e1
collectComputationExpressionStatements creationAide e2 ]
let c2 =
match trivia.SeparatorRange with
// detect then keyword in explicit constructor
| Some mThen when mThen.StartColumn + 4 = mThen.EndColumn ->
let thenNode = stn "then" mThen
let expr = mkExpr creationAide e2
let m = unionRanges mThen e2.Range
let node = ExprExplicitConstructorThenExpr(thenNode, expr, m)

fun finalContinuation ->
finalContinuation
[ ComputationExpressionStatement.OtherStatement(Expr.ExplicitConstructorThenExpr node) ]
| _ -> collectComputationExpressionStatements creationAide e2

[ collectComputationExpressionStatements creationAide e1; c2 ]

let finalContinuation (nodes: ComputationExpressionStatement list list) : ComputationExpressionStatement list =
List.collect id nodes |> finalContinuation
Expand Down Expand Up @@ -2732,10 +2749,7 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
accessibility = ao)
expr = expr
trivia = { EqualsRange = Some mEq })) when (newIdent.idText = "new") ->
let exprNode, thenExprNode =
match expr with
| SynExpr.Sequential(_, false, e1, e2, _) -> mkExpr creationAide e1, Some(mkExpr creationAide e2)
| e -> mkExpr creationAide e, None
let exprNode = mkExpr creationAide expr

MemberDefnExplicitCtorNode(
mkXmlDoc px,
Expand All @@ -2746,7 +2760,6 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
Option.map mkIdent ido,
stn "=" mEq,
exprNode,
thenExprNode,
memberDefinitionRange
)
|> MemberDefn.ExplicitCtor
Expand Down
16 changes: 6 additions & 10 deletions src/Fantomas.Core/CodePrinter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,10 @@ let genExpr (e: Expr) =
+> genSingleTextNode node.End

expressionFitsOnRestOfLine short long |> genNode node
| Expr.ExplicitConstructorThenExpr node ->
genSingleTextNode node.Then
+> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr node.Expr)
|> genNode node

let genQuoteExpr (node: ExprQuoteNode) =
genSingleTextNode node.OpenToken
Expand Down Expand Up @@ -3786,15 +3790,7 @@ let genMemberDefn (md: MemberDefn) =
+> autoIndentAndNlnIfExpressionExceedsPageWidth (genLongParenPatParameter node.Pattern)
+> optSingle (fun alias -> sepSpace +> !- "as" +> sepSpace +> genSingleTextNode alias) node.Alias)
(fun isMultiline ctx ->
let genExpr =
genExpr node.Expr
+> optSingle
(fun thenExpr ->
sepNln
+> !- "then"
+> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr thenExpr))
node.ThenExpr

let genExpr = genExpr node.Expr
let short = genSingleTextNode node.Equals +> sepSpace +> genExpr

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

genXml node.XmlDoc
+> genAttributes node.Attributes
+> ifElse node.ThenExpr.IsSome long (expressionFitsOnRestOfLine short long)
+> expressionFitsOnRestOfLine short long
|> genNode (MemberDefn.Node md)
| MemberDefn.LetBinding node -> genBindings true node.Bindings |> genNode (MemberDefn.Node md)
| MemberDefn.Interface node ->
Expand Down
15 changes: 11 additions & 4 deletions src/Fantomas.Core/SyntaxOak.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,14 @@ type ExprBeginEndNode(beginNode: SingleTextNode, expr: Expr, endNode: SingleText
member val Expr = expr
member val End = endNode

/// then <expr>
/// Only valid in secondary constructors, original coming from SynExpr.Sequential(trivia = { SeparatorRange = Some mThen })
type ExprExplicitConstructorThenExpr(thenNode: SingleTextNode, expr: Expr, range) =
inherit NodeBase(range)
override val Children: Node array = [| yield thenNode; yield Expr.Node expr |]
member val Then = thenNode
member val Expr = expr

[<RequireQualifiedAccess; NoEquality; NoComparison>]
type Expr =
| Lazy of ExprLazyNode
Expand Down Expand Up @@ -1715,6 +1723,7 @@ type Expr =
| Chain of ExprChain
| DotLambda of ExprDotLambda
| BeginEnd of ExprBeginEndNode
| ExplicitConstructorThenExpr of ExprExplicitConstructorThenExpr

static member Node(x: Expr) : Node =
match x with
Expand Down Expand Up @@ -1782,6 +1791,7 @@ type Expr =
| Chain n -> n
| DotLambda n -> n
| BeginEnd n -> n
| ExplicitConstructorThenExpr n -> n

member e.HasParentheses: bool =
match e with
Expand Down Expand Up @@ -2399,7 +2409,6 @@ type MemberDefnExplicitCtorNode
alias: SingleTextNode option,
equals: SingleTextNode,
expr: Expr,
thenExpr: Expr option,
range
) =
inherit NodeBase(range)
Expand All @@ -2412,8 +2421,7 @@ type MemberDefnExplicitCtorNode
yield Pattern.Node pat
yield! noa alias
yield equals
yield Expr.Node expr
yield! noa (Option.map Expr.Node thenExpr) |]
yield Expr.Node expr |]

member val XmlDoc = xmlDoc
member val Attributes = attributes
Expand All @@ -2423,7 +2431,6 @@ type MemberDefnExplicitCtorNode
member val Alias = alias
member val Equals = equals
member val Expr = expr
member val ThenExpr = thenExpr

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