Skip to content

Commit

Permalink
Initial support of SynExpr.DotLambda and SynType.Intersection (#2920)
Browse files Browse the repository at this point in the history
* Initial support of SynExpr.DotLambda.

* Update tests

* Add initial support for SynType.Intersection

* Add regression test for corrected range.

* Add changelog entries.
  • Loading branch information
nojaf authored Aug 28, 2023
1 parent a1b141e commit 0f1f762
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 2 deletions.
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

0 comments on commit 0f1f762

Please sign in to comment.