Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support of SynExpr.DotLambda and SynType.Intersection #2920

Merged
merged 5 commits into from
Aug 28, 2023
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## [Unreleased]

### Changed
* Update FCS to 'Included get,set in range of AutoProperty', commit d508186f510681d1261291474e3f9f25485999a8

### Added
* Initial support for `SynExpr.DotLambda` [#2920](https://github.com/fsprojects/fantomas/pull/2920) (See [dotnet/fsharp#13907](https://github.com/dotnet/fsharp/pull/13907))
* Initial support for `SynType.Intersection` [#2920](https://github.com/fsprojects/fantomas/pull/2920) (See [dotnet/fsharp#15413](https://github.com/dotnet/fsharp/pull/15413))

### Fixed
* Comment no longer attached to autoproperty. [#2948](https://github.com/fsprojects/fantomas/issues/2948)

## 6.1.3 - 2023-08-25

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

<!-- Versions -->
<PropertyGroup>
<FCSCommitHash>6ed38fcb360a0015828973b1f32cd2ea6b58c6ad</FCSCommitHash>
<FCSCommitHash>d508186f510681d1261291474e3f9f25485999a8</FCSCommitHash>
<StreamJsonRpcVersion>2.8.28</StreamJsonRpcVersion>
<FSharpCoreVersion>6.0.1</FSharpCoreVersion>
</PropertyGroup>
Expand Down
26 changes: 26 additions & 0 deletions src/Fantomas.Core.Tests/ClassTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1355,3 +1355,29 @@ type Foo =
with get (i: int, j: char): string = ""
and set (i: int, j: char) (x: string) = printfn "%i %c" i j
"""

[<Test>]
let ``trivia above with get/set in autoproperty, 2948`` () =
formatSourceString
false
"""
module A

type X() =
member val Y: int = 7
// some comment
with get,set
"""
config
|> prepend newline
|> should
equal
"""
module A

type X() =
member val Y: int =
7
// some comment
with get, set
"""
52 changes: 52 additions & 0 deletions src/Fantomas.Core.Tests/ConstraintIntersectionTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
module Fantomas.Core.Tests.ConstraintIntersectionTests

open NUnit.Framework
open FsUnit
open Fantomas.Core.Tests.TestHelpers

[<Test>]
let ``constraint intersection in type annotation`` () =
formatSourceString
false
"""
let y (f: #I & #Task<int> & #seq<string>) = ()
"""
config
|> prepend newline
|> should
equal
"""
let y (f: #I & #Task<int> & #seq<string>) = ()
"""

[<Test>]
let ``constraint intersection with leading typar`` () =
formatSourceString
false
"""
let y (f: 't & #I & #IDisposable & #seq<int> & #I2) = ()
"""
config
|> prepend newline
|> should
equal
"""
let y (f: 't & #I & #IDisposable & #seq<int> & #I2) = ()
"""

[<Test>]
let ``usage in member`` () =
formatSourceString
false
"""
type I =
abstract h: #IDisposable & #seq<int> & #I -> unit
"""
config
|> prepend newline
|> should
equal
"""
type I =
abstract h: #IDisposable & #seq<int> & #I -> unit
"""
65 changes: 65 additions & 0 deletions src/Fantomas.Core.Tests/DotLambdaTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
module Fantomas.Core.Tests.DotLambdaTests

open NUnit.Framework
open FsUnit
open Fantomas.Core.Tests.TestHelpers

[<Test>]
let ``function call`` () =
formatSourceString
false
"""
let x = "a" |> _.ToString()
"""
config
|> prepend newline
|> should
equal
"""
let x = "a" |> _.ToString()
"""

[<Test>]
let ``property call`` () =
formatSourceString
false
"""
let x = "a" |> _.Length
"""
config
|> prepend newline
|> should
equal
"""
let x = "a" |> _.Length
"""

[<Test>]
let ``property of method invocation`` () =
formatSourceString
false
"""
let c = _.ToString().Length
"""
config
|> prepend newline
|> should
equal
"""
let c = _.ToString().Length
"""

[<Test>]
let ``property of function invocation`` () =
formatSourceString
false
"""
let c = _.foo().Length
"""
config
|> prepend newline
|> should
equal
"""
let c = _.foo().Length
"""
2 changes: 2 additions & 0 deletions src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@
<Compile Include="CursorTests.fs" />
<Compile Include="MultipleDefineCombinationsTests.fs" />
<Compile Include="ParenthesesTests.fs" />
<Compile Include="DotLambdaTests.fs" />
<Compile Include="ConstraintIntersectionTests.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Fantomas.Core\Fantomas.Core.fsproj" />
Expand Down
28 changes: 27 additions & 1 deletion src/Fantomas.Core/ASTTransformer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1570,6 +1570,12 @@ let mkExpr (creationAide: CreationAide) (e: SynExpr) : Expr =
|> Expr.IndexRange
| SynExpr.IndexFromEnd(e, _) -> ExprIndexFromEndNode(mkExpr creationAide e, exprRange) |> Expr.IndexFromEnd
| SynExpr.Typar(typar, _) -> mkSynTypar typar |> Expr.Typar
| SynExpr.DotLambda(
expr = e
trivia = { DotRange = mDot
UnderscoreRange = mUnderscore }) ->
ExprDotLambda(stn "_" mUnderscore, stn "." mDot, mkExpr creationAide e, exprRange)
|> Expr.DotLambda
| _ -> failwithf "todo for %A" e

let mkExprQuote creationAide isRaw e range : ExprQuoteNode =
Expand Down Expand Up @@ -1976,7 +1982,7 @@ let mkModuleDecl (creationAide: CreationAide) (decl: SynModuleDecl) =
|> ModuleDecl.NestedModule
| decl -> failwithf $"Failed to create ModuleDecl for %A{decl}"

let mkSynTyparDecl (creationAide: CreationAide) (SynTyparDecl(attrs, typar)) =
let mkSynTyparDecl (creationAide: CreationAide) (SynTyparDecl(attributes = attrs; typar = typar)) =
let m =
match List.tryHead attrs with
| None -> typar.Range
Expand Down Expand Up @@ -2199,6 +2205,26 @@ let mkType (creationAide: CreationAide) (t: SynType) : Type =
| SynType.Or(lhs, rhs, _, trivia) ->
TypeOrNode(mkType creationAide lhs, stn "or" trivia.OrKeyword, mkType creationAide rhs, typeRange)
|> Type.Or
| SynType.Intersection(optTypar, ts, m, trivia) ->
let typesAndSeparators =
let headNode, ts =
match optTypar with
| Some typar ->
// We model the typar as Type.Var out of convenience
Type.Var(mkSynTypar typar), ts
| None ->
match ts with
| [] -> failwith "SynType.Intersection does not contain typar or any intersectionConstraints"
| head :: tail -> mkType creationAide head, tail

assert (ts.Length = trivia.AmpersandRanges.Length)

[ yield Choice1Of2 headNode
for t, mAmp in List.zip ts trivia.AmpersandRanges do
yield Choice2Of2(stn "&" mAmp)
yield Choice1Of2(mkType creationAide t) ]

TypeIntersectionNode(typesAndSeparators, m) |> Type.Intersection
| t -> failwith $"unexpected type: {t}"

let rec (|OpenL|_|) =
Expand Down
11 changes: 11 additions & 0 deletions src/Fantomas.Core/CodePrinter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,11 @@ let genExpr (e: Expr) =
|> genNode node
| Expr.IndexFromEnd node -> !- "^" +> genExpr node.Expr |> genNode node
| Expr.Typar node -> genSingleTextNode node
| Expr.DotLambda node ->
genSingleTextNode node.Underscore
+> genSingleTextNode node.Dot
+> genExpr node.Expr
|> genNode node

let genQuoteExpr (node: ExprQuoteNode) =
genSingleTextNode node.OpenToken
Expand Down Expand Up @@ -2469,6 +2474,7 @@ let genAppWithLambda sep (node: ExprAppWithLambdaNode) =

let sepSpaceBeforeParenInFuncInvocation (functionExpr: Expr) (argExpr: Expr) ctx =
match functionExpr, argExpr with
| Expr.DotLambda _, _ -> ctx
| Expr.Constant _, _ -> sepSpace ctx
| ParenExpr _, _ -> sepSpace ctx
| UppercaseExpr, ParenExpr _ -> onlyIf ctx.Config.SpaceBeforeUppercaseInvocation sepSpace ctx
Expand Down Expand Up @@ -3167,6 +3173,11 @@ let genType (t: Type) =
| Type.LongIdentApp node ->
genType node.AppType +> sepDot +> genIdentListNode node.LongIdent
|> genNode node
| Type.Intersection node ->
col sepSpace node.TypesAndSeparators (function
| Choice1Of2 t -> genType t
| Choice2Of2 amp -> genSingleTextNode amp)
|> genNode node

let genSynTupleTypeSegments (path: Choice<Type, SingleTextNode> list) =
let genTs addNewline =
Expand Down
22 changes: 22 additions & 0 deletions src/Fantomas.Core/SyntaxOak.fs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,17 @@ type TypeLongIdentAppNode(appType: Type, longIdent: IdentListNode, range) =
member val AppType = appType
member val LongIdent = longIdent

type TypeIntersectionNode(typesAndSeparators: Choice<Type, SingleTextNode> list, range) =
inherit NodeBase(range)

override val Children: Node array =
[| for t in typesAndSeparators do
match t with
| Choice1Of2 t -> Type.Node t
| Choice2Of2 amp -> amp |]

member val TypesAndSeparators = typesAndSeparators

[<RequireQualifiedAccess; NoEquality; NoComparison>]
type Type =
| Funs of TypeFunsNode
Expand All @@ -355,6 +366,7 @@ type Type =
| SignatureParameter of TypeSignatureParameterNode
| Or of TypeOrNode
| LongIdentApp of TypeLongIdentAppNode
| Intersection of TypeIntersectionNode

static member Node(x: Type) : Node =
match x with
Expand All @@ -379,6 +391,7 @@ type Type =
| SignatureParameter n -> n
| Or n -> n
| LongIdentApp n -> n
| Intersection n -> n

/// A pattern composed from a left hand-side pattern, a single text token/operator and a right hand-side pattern.
type PatLeftMiddleRight(lhs: Pattern, middle: Choice<SingleTextNode, string>, rhs: Pattern, range) =
Expand Down Expand Up @@ -1604,6 +1617,13 @@ type ExprIndexFromEndNode(expr: Expr, range) =
override val Children: Node array = [| Expr.Node expr |]
member val Expr = expr

type ExprDotLambda(underscore: SingleTextNode, dot: SingleTextNode, expr: Expr, range: range) =
inherit NodeBase(range)
override val Children: Node array = [| underscore; dot; Expr.Node expr |]
member val Underscore = underscore
member val Dot = dot
member val Expr = expr

[<RequireQualifiedAccess; NoEquality; NoComparison>]
type Expr =
| Lazy of ExprLazyNode
Expand Down Expand Up @@ -1668,6 +1688,7 @@ type Expr =
| IndexFromEnd of ExprIndexFromEndNode
| Typar of SingleTextNode
| Chain of ExprChain
| DotLambda of ExprDotLambda

static member Node(x: Expr) : Node =
match x with
Expand Down Expand Up @@ -1733,6 +1754,7 @@ type Expr =
| IndexFromEnd n -> n
| Typar n -> n
| Chain n -> n
| DotLambda n -> n

member e.HasParentheses: bool =
match e with
Expand Down