How can I locate where an implicit comes from in Scala?
Asked Answered
D

3

5

Short question:

Is there a way to ask the scala compiler to tell me where a certain implicit used at a given point in a program was declared ?

If not, is there an algorithm that I can follow manually to find out myself where an implicit was declared ?

Long question:

I am following simple spray crud tutorial.

In the code snippet below (coming the this repo for the tutorial):

pathEnd {
  post {
    entity(as[Question]) { question =>
      completeWithLocationHeader(
        resourceId = questionService.createQuestion(question),
        ifDefinedStatus = 201, ifEmptyStatus = 409)
      }
    }
} ~

as takes an implicit of type FromRequestUnmarshaller[T] (full source here):

  def as[T](implicit um: FromRequestUnmarshaller[T]) = um

and when I ask IntelliJ where this implicit comes from (using CMD+SHIFT+P), I get:

enter image description here and when I follow the first hint I get this:

trait UnmarshallerLifting {

  implicit def fromRequestUnmarshaller[T](implicit um: FromMessageUnmarshaller[T]): FromRequestUnmarshaller[T] =
    new FromRequestUnmarshaller[T] {
      def apply(request: HttpRequest): Deserialized[T] = um(request)
    }
...

this does not help me to figure out where the implicit FromRequestUnmarshaller[T] comes from because I cannot figure out how the trait UnmarshallerLifting gets mixed into QuestionResource if I inspect the class hierarchy:

enter image description here

I inspect the traits that look like they might contain this implict, for example this trait,but it does not contain the implicit:

trait MarshallingDirectives {
  import BasicDirectives._
  import MiscDirectives._
  import RouteDirectives._

  /**
   * Unmarshalls the requests entity to the given type passes it to its inner Route.
   * If there is a problem with unmarshalling the request is rejected with the [[spray.routing.Rejection]]
   * produced by the unmarshaller.
   */
  def entity[T](um: FromRequestUnmarshaller[T]): Directive1[T] =
    extract(_.request.as(um)).flatMap[T :: HNil] {
      case Right(value)                            ⇒ provide(value)
      case Left(ContentExpected)                   ⇒ reject(RequestEntityExpectedRejection)
      case Left(UnsupportedContentType(supported)) ⇒ reject(UnsupportedRequestContentTypeRejection(supported))
      case Left(MalformedContent(errorMsg, cause)) ⇒ reject(MalformedRequestContentRejection(errorMsg, cause))
    } & cancelAllRejections(ofTypes(RequestEntityExpectedRejection.getClass, classOf[UnsupportedRequestContentTypeRejection]))

  /**
   * Returns the in-scope FromRequestUnmarshaller for the given type.
   */
  def as[T](implicit um: FromRequestUnmarshaller[T]) = um

  /**
   * Uses the marshaller for the given type to produce a completion function that is passed to its inner route.
   * You can use it do decouple marshaller resolution from request completion.
   */
  def produce[T](marshaller: ToResponseMarshaller[T]): Directive[(T ⇒ Unit) :: HNil] =
    extract { ctx ⇒ (value: T) ⇒ ctx.complete(value)(marshaller) } & cancelAllRejections(ofType[UnacceptedResponseContentTypeRejection])

  /**
   * Returns the in-scope Marshaller for the given type.
   */
  def instanceOf[T](implicit m: ToResponseMarshaller[T]) = m

  /**
   * Completes the request using the given function. The input to the function is produced with the in-scope
   * entity unmarshaller and the result value of the function is marshalled with the in-scope marshaller.
   */
  def handleWith[A, B](f: A ⇒ B)(implicit um: FromRequestUnmarshaller[A], m: ToResponseMarshaller[B]): Route =
    entity(um) { a ⇒ RouteDirectives.complete(f(a)) }
}

object MarshallingDirectives extends MarshallingDirectives

after looking at 20 different places I become frustrated.

Is there a way to ask the scala compiler to tell me where a certain implicit (in this example FromRequestUnmarshaller[T]) used at a given point in a program (in this example here) was declared ?

If not, is there an algorithm that I can follow manually to find out myself where an implicit was declared ?

I looked for this question on Google/SOF but the hints I found did not help. I also went through this and I still don't know where the FromRequestUnmarshaller[T] comes from.

Dander answered 29/12, 2016 at 15:14 Comment(2)
Perhaps you're looking for: #34904020 ?Moonfish
Nice, thanks, I have a look into that.Dander
H
4

Typically I enable -Xlog-implicits in compiler to see what's going on with implicits.

Also spray is deprecated in favor of akka-http. I recommend to switch.

Heptastich answered 29/12, 2016 at 15:51 Comment(1)
I tried it, It does not tell me where the implicit is coming from, it only complains about implicits that are tried and not worked :(Dander
D
4

I did this (as suggested in Michael's comment):

    import scala.reflect.runtime.universe.reify
    println(reify(entity(as[Question])))

It printed:

Expr[spray.routing.Directive1[spray_examples.plain_rest.danielasfregola.quiz.management.entities.Question]](QuestionResource.entity(QuestionResource.as[Question](Deserializer.fromRequestUnmarshaller(Deserializer.fromMessageUnmarshaller(QuestionResource.json4sUnmarshaller(ManifestFactory.classType(classOf[spray_examples.plain_rest.danielasfregola.quiz.management.entities.Question])))))))

This tells directly where the implicit is coming from : Deserializer.fromRequestUnmarshaller

Also, here is an other way, by using InteliJ's search usage function:

enter image description here

Dander answered 29/12, 2016 at 20:35 Comment(0)
P
0

Odersky's recommended method of debugging implicits from his book is running scalac with -Xprint:typer, which you can see in detail here.

Reproducing here:

    object Mocha extends Application {
  
      class PreferredDrink(val preference: String)
  
      implicit val pref = new PreferredDrink("mocha")
  
      def enjoy(name: String)(implicit drink: PreferredDrink) {
        print("Welcome, "+ name)
        print(". Enjoy a ")
        print(drink.preference)
        println("!")
      }
  
      enjoy("reader")
    }
  $ scalac -Xprint:typer mocha.scala
  [[syntax trees at end of typer]]
// Scala source: mocha.scala
  package <empty> {
    final object Mocha extends java.lang.Object with Application
        with ScalaObject {
  
      
// ...
  
      private[this] val pref: Mocha.PreferredDrink =
        new Mocha.this.PreferredDrink("mocha");
      implicit <stable> <accessor>
        def pref: Mocha.PreferredDrink = Mocha.this.pref;
      def enjoy(name: String)
          (implicit drink: Mocha.PreferredDrink): Unit = {
        scala.this.Predef.print("Welcome, ".+(name));
        scala.this.Predef.print(". Enjoy a ");
        scala.this.Predef.print(drink.preference);
        scala.this.Predef.println("!")
      };
      Mocha.this.enjoy("reader")(Mocha.this.pref)
    }
  }

Again credit to Odersky: https://www.artima.com/pins1ed/implicit-conversions-and-parameters.html#21.7

Parlor answered 21/10, 2020 at 15:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.