dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.92k stars 785 forks source link

Improve error reporting: Missing "else" branch for if expression with elif #6873

Open isaacabraham opened 5 years ago

isaacabraham commented 5 years ago

Related to #1104. Indeed in that issue there was actually a comment:

This should also apply to if / elif / elif with a missing "else".

What

Exactly the same old error message shows as soon as you add an elif branch e.g.

let x = 10
let y =
   if x > 10 then "test"
   elif x > 2 then "blah"

gives the error:

error FS0001: This expression was expected to have type
    'unit'    
but here has type
    'string'   

Why

Same as #1104.

How

Same as #1104.

cartermp commented 5 years ago

Thanks for filing 🙂

isaacabraham commented 4 years ago

@forki would you be interested in working with me on this one? Maybe a co-driver screenshare or something to show me a bit more how I can do this?

KathleenDollard commented 3 years ago

Do you always need the else? For example, you don't need it in a list comprehension do you?

What do we need to discuss prior to moving this out of "needs discussion"?

isaacabraham commented 2 years ago

@KathleenDollard that's true re: list comprehension, although that's a somewhat specific case that (I believe) is really only because F# now supports implicit yield. In reality, such code would really be as follows:

Newer F#

let y = 1
let x = [
    if y = 2 then "a" // branch looks like it returns a string
    elif y = 3 then "b" // branch looks like it returns a string
]

is in reality this:

let y = 1
let x = [
    if y = 2 then yield "a" // branch returns unit
    elif y = 3 then yield "b" // branch returns unit
]

Since the expression is actually only returning unit you can omit the else branch. This rule also applies in F# outside of list comprehensions:

let x =
    if y = 2 then printfn "a" // branch returns unit
    elif y = 3 then printfn "b" // branch returns unit

But for anything non-unit, as far as I'm aware, you must always return an else case. So, yes, I think that this should be approved as "up for grabs" :-)