1

I have a parameterized class like

class Test[T]{
    //...
}

object Test{
    implicit def materializeTest[T]: Test[T] = macro impl[T]

    def impl[T: c.WeakTypeTag](c: blackbox.Context) = //...
}

If using the materialized implicit from the same module it throws an error:

macro implementation not found

But the problem is extracting a single class into a separate module looks absolutely ugly and cumbersome. Maybe there is some "well-known workaround" to avoid that? Maybe shapeless can be helpful here?

UPD:

scalaVersion in ThisBuild := "2.13.2"

Here is my minimal example:

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

object Main {
  sealed trait Adt
  case object Adt1 extends Adt
  case object Adt2 extends Adt

  trait Test[Adtt <: Adt] {
    def restrict(restrictions: List[Int]): List[Int]
  }

  object Test {
    def apply[Adtt <: Adt](implicit ev: Test[Adtt]): Test[Adtt] = ev

    implicit def implicitMaterializer[
        Adtt <: Adt
    ]: Test[Adtt] = macro impl[Adtt]

    def impl[Adtt <: Adt: c.WeakTypeTag](
        c: blackbox.Context
    ): c.Expr[Test[Adtt]] = {

      import c.universe._
      c.Expr[Test[Adtt]](q"""???""")
    }
  }

  def main(args: Array[String]): Unit = {
    Test[Adt1.type].restrict(List(1, 2, 3))
  }
}

which results in the following error:

[error] Main.scala:32:9: macro implementation not found: implicitMaterializer
[error] (the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
Some Name
  • 8,555
  • 5
  • 27
  • 77
  • Why did you make implicit macro blackbox? https://stackoverflow.com/questions/64538997/what-should-a-scala-implicit-macro-have-to-return-to-tell-the-compiler-forget-m/ https://stackoverflow.com/questions/64122310/implicit-macro-default-implicit-value-how – Dmytro Mitin Dec 15 '20 at 14:27
  • 1
    @DmytroMitin I made it blackbox to provide better error messages without silently ignoring it. – Some Name Dec 15 '20 at 14:29
  • 1
    @DmytroMitin I added the MCVE I got this error. – Some Name Dec 15 '20 at 14:42

1 Answers1

3

You can extract to a separate module not Test but TestMacro

core

import scala.language.experimental.macros

class Test[T]

object Test {
  implicit def materializeTest[T]: Test[T] = macro TestMacro.impl[T]
}

implicitly[Test[Int]] // compiles

macros

import scala.reflect.macros.blackbox

object TestMacro {
  def impl[T: c.WeakTypeTag](c: blackbox.Context) = {
    import c.universe._
    q"new Test[${weakTypeOf[T]}]"
  }
}

Ugly or not but macro implementations must be compiled before they are applied (but Is there any trick to use macros in the same file they are defined?).

This is improved in Scala 3

http://dotty.epfl.ch/docs/reference/metaprogramming/macros.html#defining-a-macro-and-using-it-in-a-single-project

Shapeless just hides some predefined set of standard macros, it can't help with your own macros.

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66