From 5cda99e059631849a8c581f2a50bd1e9f89f8747 Mon Sep 17 00:00:00 2001 From: Florian Verdonck Date: Sat, 30 May 2020 17:27:48 +0200 Subject: [PATCH] Correctly handle use binding follow by let bang (#877) * Correctly handle use binding follow by let bang. Fixes #876 * Corrected space after rec keyword. --- .../ComputationExpressionTests.fs | 91 +++++++++++++++++++ src/Fantomas/CodePrinter.fs | 8 +- src/Fantomas/SourceParser.fs | 6 +- 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/src/Fantomas.Tests/ComputationExpressionTests.fs b/src/Fantomas.Tests/ComputationExpressionTests.fs index 1df2da6139..4873870aed 100644 --- a/src/Fantomas.Tests/ComputationExpressionTests.fs +++ b/src/Fantomas.Tests/ComputationExpressionTests.fs @@ -1224,4 +1224,95 @@ let valueTwo = do! d return! getE () } +""" + +[] +let ``use and let bang, 876`` () = + formatSourceString false """let private getAST log (req: HttpRequest) = + async { + use stream = new StreamReader(req.Body) + let! json = stream.ReadToEndAsync() |> Async.AwaitTask + let parseRequest = Decoders.decodeInputRequest json + + match parseRequest with + | Result.Ok input when (input.SourceCode.Length < Const.sourceSizeLimit) -> + let! astResult = parseAST log input + match astResult with + | Result.Ok ast -> + let node = + match ast with + | ParsedInput.ImplFile (ParsedImplFileInput.ParsedImplFileInput (_, _, _, _, hds, mns, _)) -> + Fantomas.AstTransformer.astToNode hds mns + + | ParsedInput.SigFile (ParsedSigFileInput.ParsedSigFileInput (_, _, _, _, mns)) -> + Fantomas.AstTransformer.sigAstToNode mns + |> Encoders.nodeEncoder + + let responseJson = + Encoders.encodeResponse node (sprintf "%A" ast) + |> Thoth.Json.Net.Encode.toString 2 + + return sendJson responseJson + + | Error error -> return sendBadRequest (sprintf "%A" error) + + | Result.Ok _ -> return sendTooLargeError () + + | Error err -> return sendInternalError (sprintf "%A" err) + } +""" config + |> prepend newline + |> should equal """ +let private getAST log (req: HttpRequest) = + async { + use stream = new StreamReader(req.Body) + let! json = stream.ReadToEndAsync() |> Async.AwaitTask + let parseRequest = Decoders.decodeInputRequest json + + match parseRequest with + | Result.Ok input when (input.SourceCode.Length < Const.sourceSizeLimit) -> + let! astResult = parseAST log input + + match astResult with + | Result.Ok ast -> + let node = + match ast with + | ParsedInput.ImplFile (ParsedImplFileInput.ParsedImplFileInput (_, _, _, _, hds, mns, _)) -> + Fantomas.AstTransformer.astToNode hds mns + + | ParsedInput.SigFile (ParsedSigFileInput.ParsedSigFileInput (_, _, _, _, mns)) -> + Fantomas.AstTransformer.sigAstToNode mns + |> Encoders.nodeEncoder + + let responseJson = + Encoders.encodeResponse node (sprintf "%A" ast) + |> Thoth.Json.Net.Encode.toString 2 + + return sendJson responseJson + + | Error error -> return sendBadRequest (sprintf "%A" error) + + | Result.Ok _ -> return sendTooLargeError () + + | Error err -> return sendInternalError (sprintf "%A" err) + } +""" + +[] +let ``let rec + let bang`` () = + formatSourceString false """let a = + async { + let rec foo a = foo a + let! bar = async { return foo a } + return bar + } +""" config + |> prepend newline + |> should equal """ +let a = + async { + let rec foo a = foo a + let! bar = async { return foo a } + return bar + } """ \ No newline at end of file diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 22d4650d03..fcd31f808e 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -963,8 +963,10 @@ and genExpr astContext synExpr = let genCompExprStatement astContext ces = match ces with - | LetStatement(isRecursive, binding) -> - let prefix = if isRecursive then "let rec " else "let " + | LetOrUseStatement(isRecursive, isUse, binding) -> + let prefix = + sprintf "%s%s" (if isUse then "use " else "let ") (if isRecursive then "rec " else "") + genLetBinding astContext prefix binding | LetOrUseBangStatement(isUse, pat, expr, _) -> ifElse isUse (!- "use! ") (!- "let! ") @@ -977,7 +979,7 @@ and genExpr astContext synExpr = let getRangeOfCompExprStatement ces = match ces with - | LetStatement(_, binding) -> binding.RangeOfBindingSansRhs + | LetOrUseStatement(_, _, binding) -> binding.RangeOfBindingSansRhs | LetOrUseBangStatement(_, _, _, r) -> r | AndBangStatement (pat, _) -> pat.Range | OtherStatement expr -> expr.Range diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index ded321cd5c..d842e4b1aa 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -780,17 +780,17 @@ let rec (|LetOrUses|_|) = function | _ -> None type ComputationExpressionStatement = - | LetStatement of recursive:bool * SynBinding + | LetOrUseStatement of recursive:bool * isUse:bool * SynBinding | LetOrUseBangStatement of isUse:bool * SynPat * SynExpr * range | AndBangStatement of SynPat * SynExpr | OtherStatement of SynExpr let rec collectComputationExpressionStatements e : ComputationExpressionStatement list = match e with - | SynExpr.LetOrUse(isRecursive, isUse, bindings, body, _) when (not(isUse)) -> + | SynExpr.LetOrUse(isRecursive, isUse, bindings, body, _) -> let bindings = bindings - |> List.map (fun b -> LetStatement(isRecursive, b)) + |> List.map (fun b -> LetOrUseStatement(isRecursive, isUse, b)) let returnExpr = collectComputationExpressionStatements body [yield! bindings; yield! returnExpr] | SynExpr.LetOrUseBang(_,isUse,_,pat,expr, andBangs, body, r) ->