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

Mutual Recursion with Async Workflow Possible Compiler Issue #3326

Closed
psantoro opened this issue Jul 12, 2017 · 6 comments
Closed

Mutual Recursion with Async Workflow Possible Compiler Issue #3326

psantoro opened this issue Jul 12, 2017 · 6 comments
Labels
Bug Impact-Medium (Internal MS Team use only) Describes an issue with moderate impact on existing code.
Milestone

Comments

@psantoro
Copy link

psantoro commented Jul 12, 2017

The placement of a mutually recursive async workflow's ending curly brace seems to impact compilation success when it probably shouldn't. The sample code with comments demonstrates the issue. If I'm mistaken, I'd appreciate an explanation (i.e. some offside issue that I'm not seeing).

Repro steps

  1. Step A - Compile the sample code in the attached zip and note the errors related to climateControl3.
    main.zip

Expected behavior

I would have expected that the placement of the ending curly brace in climateControl3, which is the same as in the non-mutual recursive function climateControl2, would not generate compiler errors.

Actual behavior

The above sample code will generate climateControl3 compiler errors when compiled:

main.fs(45,5): error FS0588: The block following this 'let' is unfinished. Every code block is an expression and must have a result. 'let' cannot be the final code element in a block. Consider giving this block an explicit result.

main.fs(53,5): error FS0010: Unexpected keyword 'and' in lambda expression. Expected incomplete structured construct at or before this point or other token.

main.fs(62,5): error FS0010: Incomplete structured construct at or before this point in binding. Expected incomplete str uctured construct at or before this point or other token.
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft SDKs\F#\4.1\Framework\v4.0\fsc.EXE"' : return code '0x1'
Stop.

Known workarounds

The placement of the ending brace should follow the example in climateControl1.

Related information

Provide any related information

  • Operating system - Windows 7 with updates
  • Branch
  • .NET Runtime, CoreCLR or Mono Version 4.5-4.7
  • Editing Tools (e.g. Visual Studio Version) VS2017 with updates, F# 4.1, and VIM
  • Links to F# RFCs or entries on https://github.com/fsharp/fslang-suggestions
  • Links to performance testing scripts
  • Indications of severity
@chillitom
Copy link
Contributor

The repro code in case anyone doesn't want to download the zip.

#light
module app.main

open System
open System.IO

type message =
    | HeatUp
    | CoolDown
 
let climateControl1 = MailboxProcessor.Start( fun inbox ->
    // NOTE compiles
    let rec heating() = async {
        printfn "Heating"
        let! msg = inbox.Receive()
        match msg with
        | CoolDown -> return! cooling()
        | _ -> return! heating()} // NOTE placement of }
 
    and cooling() = async {
        printfn "Cooling"
        let! msg = inbox.Receive()
        match msg with
        | HeatUp -> return! heating()
        | _ -> return! cooling()} // NOTE placement of }
 
    heating()
    )

let climateControl2 = MailboxProcessor.Start( fun inbox ->
    // NOTE compiles
    let rec heating() = async {
        printfn "Heating"
        let! msg = inbox.Receive()
        match msg with
        | CoolDown -> return ()
        | _ -> return! heating()
    } // NOTE placement of }
 
    heating()
    )

let climateControl3 = MailboxProcessor.Start( fun inbox ->
    // NOTE does not compile
    let rec heating() = async {
        printfn "Heating"
        let! msg = inbox.Receive()
        match msg with
        | CoolDown -> return! cooling()
        | _ -> return! heating()
    } // NOTE placement of }
 
    and cooling() = async {
        printfn "Cooling"
        let! msg = inbox.Receive()
        match msg with
        | HeatUp -> return! heating()
        | _ -> return! cooling()
    } // NOTE placement of }
 
    heating()
    )

[<EntryPoint>]
let main argv =
    printfn "test"
    0

@dsyme
Copy link
Contributor

dsyme commented Jul 13, 2017

We will treat this by design, though please feel free to add an issure at http://github.com/fsharp/fslang-suggestions. Just indent the closing } where necessary, e.g. by 2-spaces or as you've shown.

@cartermp
Copy link
Contributor

@dsyme What is the rationale for by-designing this? I think it's fairly reasonable to expect people to want to put the closing brace as the example shows.

Currently, the auto de-indentation feature in VS will auto de-indent to the same indentation level as the let binding, which I consider correct:

ce-same-line

After all, it's valid already, and given that the async declaration is on the same line as the let declaration, it makes sense to me that the closing brace can be at that same indentation level.

@dsyme
Copy link
Contributor

dsyme commented Jan 12, 2018

@cartermp OK, I try to take a look next week at what it would take to fix this.

@dsyme dsyme added Bug Area-Compiler Impact-Medium (Internal MS Team use only) Describes an issue with moderate impact on existing code. and removed Resolution-By Design labels Jan 12, 2018
@cartermp
Copy link
Contributor

Thanks!

@dsyme
Copy link
Contributor

dsyme commented Aug 24, 2021

Fixed in preview #11772

@dsyme dsyme closed this as completed Aug 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Impact-Medium (Internal MS Team use only) Describes an issue with moderate impact on existing code.
Projects
None yet
Development

No branches or pull requests

4 participants