Skip to content

Improve Error Reporting: "inner" expressions inside computations expressions #2739

@isaacabraham

Description

@isaacabraham

@dsyme - as per your email w/ Dave Thomas...

What

If you create a computation expression that has a nested expression inside it bound to a value, you need to explicitly create a "child" computation expression for the nested expression.

let x =
    let text = "foo"
    async {
        let answer =
            match text with
            | "foo" ->
                let! y = y   // error FS0750: This construct may only be used within computation expressions
                y + 5
            | _ -> 0
        return answer + 10
    }

You can fix it either by explicitly wrapping the nested match expression branches in their own CEs: -

let x =
    let text = "foo"
    async {
        let! answer =
            match text with
            | "foo" ->
                async {
                    let! y = y
                    return y + 5 }
            | _ -> async { return 0 }
        return answer + 10
    }

or the entire child expression

let x =
    let text = "foo"
    async {
        let! answer = async {
            match text with
            | "foo" ->
                let! y = y
                return y + 5
            | _ -> return 0 }
        return answer + 10
    }

Why

The error message is misleading: as far are the developer is concerned, they are in an async CE; it's not clear at all that by creating a nested expression within the parent CE, the user has "left" the CE.

How

If it's possible for the compiler to detect this, the error message should be clearer e.g.

Code within a nested expressions (e.g. "if" or "match") exists outside of any parent computation expression. In order to perform actions such as let! or do!, the nested expression must be wrapped within its own computation expression.

It would also be useful (and this is something that we should consider doing with many other error messages) to give a "before / after" example (as I've done here) either directly inside the compiler error message, or somehow linking to one.

Alternatively, depending on the complexity and whether this could be determined up front, the compiler could do this "nested wrapping" for us.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-Diagnosticsmistakes and possible improvements to diagnosticsFeature ImprovementTheme-Simple-F#A cross-community initiative called "Simple F#", keeping people in the sweet spot of the language.

    Type

    No type

    Projects

    Status

    In Progress

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions