haskell / haskell-language-server

Official haskell ide support via language server (LSP). Successor of ghcide & haskell-ide-engine.
Apache License 2.0
2.65k stars 355 forks source link

Search and insert orphan instances #2957

Open thomasbach-dev opened 2 years ago

thomasbach-dev commented 2 years ago

Is your feature request related to a problem? Please describe.

The overall goal is to find packages where orphan instances are defined and include them automatically into the project. For example, using the cereal package and deriving an instance for a record with a field of type Text:

data Request 
  = Req { msg :: Text }
  deriving (Generic, Serialize)

ghc will give us an error message like this:

    • No instance for (Serialize Text)
        arising from the 'deriving' clause of a data type declaration
      Possible fix:
        use a standalone 'deriving instance' declaration,
          so you can specify the instance context yourself
    • When deriving the instance for (Serialize Request)
   |
18 |   deriving (Generic, Serialize)
   |                      ^^^^^^^^^

Searching for the error message does not get you very far, hoogle (at this moment) does not give you an answer either. So you have to navigate through Hackage in the right way to find a package which defines the instance (in this case that's cereal-text), alter the cabal/stack file to get the dependency and import the correct module.

Describe the solution you'd like

Ideally, HLS goes on to search for the orphan instance, if it finds a suitable one it provides a code-action to add the package to the project and add the import statement to the module.

Describe alternatives you've considered

The biggest problem here seems to be the lookup from (TypeClass, DataType) -> package. We need to explore if we can fetch this information somehow somewhere first. These options are currently on the table:

  1. Hoogle,
  2. hackage-index,
  3. searching through hackage somehow.

For (1) and (2) we are not sure if the data is in the given database at all nor if it's possible to query the data. I talked to an HLS contributor suggesting (3) without really knowing how.

Additional context

@benjaminweb, @dispanser and me came up with this idea on ZuriHac 2022. @fendor gave some first advices.

July541 commented 2 years ago

Something like #2718?

fendor commented 2 years ago

@July541 I feel like this is related, but not entirely. The main difference being that we help the user to discover what package might implement the orphan instance for them, and telling them exactly what they need to do to implement it.

thomasbach-dev commented 2 years ago

@July541 on first sight #2718 looks like an additional code action in a similar situation. #2718 is about data types defined in the current code base. This feature request is about searching orphan instances (i.e. neither the type-class nor data type is defined in the current code base) in third-party packages and providing an easy way to insert the results.

Anyways, I thought about the proposal by @michaelpj to have a “code action that just inserts an instance declaration for you to fill in”. In case of a search miss that would be really nice.

July541 commented 2 years ago

It would be excellent if we can have it, but not easy I think... Especially for type info.

thomasbach-dev commented 2 years ago

Yeah, the more I look into this the harder it seems to be. I'm (still) a nix user and therefor I can't really evaluate hackage-index at the moment. (But I actually doubt that the information we need is in there.) All the documentation I read on Hoogle indicates that it's only about searching types and that it's not indexing instances.

The only option I see at the moment is to create a new database which sounds like a lot of work.

benjaminweb commented 2 years ago

Isn’t it “just” to grep through the files selecting those blocks that start with “instance”? What do I overlook? What would be the smallest scope to begin with? To me a single package like cereal-text. Once we have solved the problem for that, we could proceed to solve it for a big number of packages. @thomasbach-dev https://github.com/noteed/nginx-hackage

fendor commented 2 years ago

Is there a reason why we can't have hoogle index instances as well? Did you create an issue for it, maybe?

benjaminweb commented 2 years ago

Did you see this one? https://github.com/ndmitchell/hoogle/issues/387

thomasbach-dev commented 2 years ago

@fendor I just browsed over the documentation, possible query strings and briefly looked into the source code of Hoogle. From this I got the sense that it would require lots of changes in Hoogle itself. But I might be wrong. :pray:

@benjaminweb Yeah, correct it shouldn't be too difficult to fetch the instance implementations of a package. A lot of questions arise after that. You are probably right though, we should first try to get this step done and then see how to proceed from that.

benjaminweb commented 2 years ago

@fendor is there already some interfacing between hoogle and hls? I remember - but are not sure - that you said it wasn’t.

fendor commented 2 years ago

There is none at the moment, there used to be one for Haskell-IDE-Engine: https://github.com/haskell/haskell-ide-engine/blob/master/src/Haskell/Ide/Engine/Support/Hoogle.hs I am not sure how applicable that is.