gleam-lang / gleam

⭐️ A friendly language for building type-safe, scalable systems!
https://gleam.run
Apache License 2.0
18.01k stars 753 forks source link

Suggest unwrapping when passing `Result(a, _)` instead of `a` #3644

Closed giacomocavalieri closed 1 month ago

giacomocavalieri commented 1 month ago

It would be nice if the compiler could suggest how to deal with a result when it's being used where the wrapped Ok value is expected instead. What I mean is:

pub fn main() {
  let response =
    request.new()
    |> request.set_host("pokeapi.co")
    |> request.set_path("api/v2/pokemon/ditto")
    |> httpc.send

  parse_response(response)
}

fn parse_response(response: Response(String)) {
  todo
}

Have an error that looks like this:

error: Type mismatch
   ┌─ /Users/giacomocavalieri/Desktop/goto/src/goto.gleam:13:18
   │
13 │   parse_response(response)
   │                  ^^^^^^^^

Expected type:

    Response(String)

Found type:

    Result(Response(String), Dynamic)

Hint: to get a value out of a `Result` you can pattern match on it

    case response {
      Ok(response) -> parse_response(response)
      Error(_) -> todo as "deal with error"
    }

We could also have a code action to apply this fix too.

lpil commented 1 month ago

Sounds good! I'm not sure this is the right place for a code action though as most the time you don't want to use case, and there's an action for expanding case

GearsDatapacks commented 1 month ago

Could this apply the other way round too? For example:

fn fallible(value: String) -> Result(Int, Nil) {
  case value {
    "1" -> 1
        // ^ The compiler could suggest wrapping this in `Ok`
    "2" -> 2
     _ -> int.parse(value)
  }
}

Rust does this, for example

lpil commented 1 month ago

I think that's a great idea but in that specific case there wouldn't be an error for that clause.

GearsDatapacks commented 1 month ago

Yes that's true, probably a bad example. Should I open a separate issue for that?

lpil commented 1 month ago

For what, sorry?

GearsDatapacks commented 1 month ago

My suggestion above

lpil commented 1 month ago

Sorry, I'm a bit confused. There's no type error on that line. How would it work?

GearsDatapacks commented 1 month ago

In a different case for example:

pub fn wibble() -> Result(Int, Nil) {
  10
//^ here for example
}

Maybe that's not particularly useful though