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

纵饮孤独 提交于 2020-01-13 00:07:01

问题


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:

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:

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.


回答1:


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.




回答2:


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:



来源:https://stackoverflow.com/questions/41382408/how-can-i-locate-where-an-implicit-comes-from-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!