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

Add missing implicit parameter #105

Open
kubukoz opened this issue Apr 17, 2020 · 1 comment
Open

Add missing implicit parameter #105

kubukoz opened this issue Apr 17, 2020 · 1 comment

Comments

@kubukoz
Copy link

kubukoz commented Apr 17, 2020

Is your feature request related to a problem? Please describe.
When working in a codebase with lots of implicits, e.g. using the tagless final technique, you find yourself adding implicit parameters or context bounds quite often when trying to use an interface you haven't used before.

Currently, when you make a call to such an interface, Metals will happily help you with an import on completion / in the quick fix, but you'll only have the type, not the value. The type needs to be added manually to the implicit parameter list (if there is one in the surrounding definitions) or the context bounds (if the missing implicit contains any of the type parameters of the surrounding definitions).

Describe the solution you'd like
A quick fix available on positions with missing implicits.

Let's have an example:

trait Execution

trait Alg[F[_]] {
  def pure[A](x: A)(implicit e: Execution): F[A]
}

object Alg {
  def apply[F[_]](implicit F: Alg[F]): Alg[F] = F
}

trait Monoid[A] { def empty: A }

object Monoid {
  def empty[A](implicit A: Monoid[A]): A = A.empty
}

class Example[F[_]] {

  def instance[A]: F[A] =
    ???
}

This complies fine. Let's replace the placeholder with some references to some implicits:

-    ???
+    Alg[F].pure(Monoid.empty[A])

Now we get errors in two positions: at Alg[F] (missing implicit) and empty[A] (missing implicit):

image

If we add the necessary constraints, we'll also get an error due to the missing implicit Execution.

Some of the ways an inspection could help:

  • Quick fix on Alg[F]:

    • Add an implicit Alg[F] parameter to Example's primary constructor
    • Same, but using context bound syntax
    • Add Alg[F] to a new implicit parameter list in instance (adding to an existing list if present)
  • Quick fix on empty[A]:

    • Add an implicit Monoid[A] parameter in instance
    • Same, but using context bound syntax

Ideally, the specifics on where to insert the parameter would be some sort of context menu separate from the short list of quick fixes (much like creating new Scala files in vscode), so that it's not polluted with too many options at once. Ideally, with a preview, but I underestand that might be much harder to implement.

Describe alternatives you've considered
Manually adding required parameters to the desired location.

Additional context
Some implicits might be harder to define as context bounds, for example MonadError[*[_], Throwable] (using kind-projector syntax). For these, we could start by only adding them as normal implicit parameters.

Search terms:
Context bounds, type class constraints, effect polymorphic, cats-effect

@tgodzik
Copy link
Contributor

tgodzik commented Apr 20, 2020

Thanks for reporting! I agree that it would be useful indeed, but not sure how difficult it will be. If anyone wants to take a shot at this, we can try to help out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants