Scala макрос: получить объект-компаньон из класса - PullRequest
1 голос
/ 26 марта 2020

Мне не удается получить сопутствующий объект / синглтон из типа класса в Scala макросе / квазицитатах. Попытка следовать https://docs.scala-lang.org/overviews/quasiquotes/type-details.html#singleton -типа , данный пример работает, но он основан на литеральной строке для квазицитаты, чтобы получить объект-компаньон напрямую, чего я не могу достичь тем же путем, если я начинаю с Извлеченный тип класса param после некоторого квазицитата unlifting.

Я упростил и попытался выделить предполагаемое использование и текущую реализацию макроса ниже:

// Intended usage
package utils

sealed trait Base

object Base {
  import macros._

  @Component
  final case class X(v: XInner) extends Base
}

final case class XInner(v: Int)

Base.X(123)  // No need to do Base.X(XInner(123))

Текущая реализация макроса

package macros

import scala.reflect.macros.whitebox
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation
import scala.annotation.compileTimeOnly

class Component() extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro ComponentMacro.impl
}

private class ComponentMacro(val c: whitebox.Context) {
  import c.universe._

  // To map function result while allowing the use of params forwarding syntax like `apply _`
  // e.g. `def y = (X.apply _).mapResult(Y(_))`
  implicit class Func1Extra[I1, O1, O2](f: I1 => O1) {
    def mapResult(g: O1 => O2): I1 => O2 = (i1: I1) => g(f(i1))
  }

  def impl(annottees: Tree*): Tree = annottees match {
    case (clsDef: ClassDef) :: Nil =>
      clsDef match {
        case q"final case class $className(..$fields) extends ..$parents" if fields.length == 1 => {
          val fieldType = fields(0).tpt
          val singletonType = tq"$fieldType.type"
          val tq"$singleton.type" = singletonType
          q"""
          $clsDef
          object ${clsDef.name.toTermName} {
            def apply = (${singleton}.apply _).mapResult(new ${clsDef.name}(_))
          }
          """
        }

        case _ => c.abort(c.enclosingPosition, "Invalid annotation target")
      }

    case _ => c.abort(c.enclosingPosition, "Invalid annotation target")
  }
}

Ошибка при компиляции:

value apply is not a member of Utils.XInner

Похоже, что сообщение об ошибке указывает на то, что метод apply был выполнен для типа класса XInner, а не для объекта-компаньона XInner.

Есть идеи, как получить объект компонента с тем же именем типа? Заранее спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...