Scala macro - enter an implicit value with `c.prefix`

c.inferImplicitValuedisplays implicit values ​​in the call site area. Is it possible to derive implications using the field c.prefix?

This is invalid code, but expresses what I need:

c.prefix.inferImplicitValue

Currently, I am using a naive implementation for this purpose [1], but it has some limitations, such as not deriving implicit values ​​from defand finding duplicate / ambiguous implicit values.

[1] https://github.com/getquill/quill/blob/9a28d4e6c901d3fa07e7d5838e2f4c1f3c16732b/quill-core/src/main/scala/io/getquill/util/InferImplicitValueWithFallback.scala#12

+4
source share
1 answer

() , implicitly, :

q"""{import ${c.prefix}._; _root_.scala.Predef.implicitly[$T] }

T - Type, .

, , Context.typeCheck silent=true , .

, infer, None, Some.

import scala.reflect.macros.Context
import scala.language.experimental.macros

def inferImplicitInPrefixContext[T:c.WeakTypeTag](c: Context): c.Tree = {
  import c.universe._
  val T = weakTypeOf[T]
  c.typeCheck(
    q"""{
      import ${c.prefix}._
      _root_.scala.Predef.implicitly[$T]
    }""",
    silent = true
  )
}

def infer_impl[T:c.WeakTypeTag](c: Context): c.Expr[Option[T]] = {
  import c.universe._
  c.Expr[Option[T]](
    inferImplicitInPrefixContext[T](c) match {
      case EmptyTree => q"_root_.scala.None"
      case tree => q"_root_.scala.Some($tree)"
    }
  )
}

trait InferOp {
  def infer[T]: Option[T] = macro infer_impl[T]
}

:

object Foo extends InferOp {
  implicit val s = "hello"
}

Foo.infer[String] // res0: Some[String] = Some(hello)

Foo.infer[Int] // res1: None.type = None

implicit val lng: Long = 123L

Foo.infer[Long] // res2: Some[Long] = Some(123)
+5

Source: https://habr.com/ru/post/1607611/


All Articles