Search code examples
scalascala-macrosscala-catsscala-macro-paradise

Cats-tagless - Scala macro annotation error


I have created a simple trait using cats-tagless lib:

@finalAlg
@autoFunctorK(true)
trait MyService[F[_]] {

  def put(element: Element): F[Element]

  def get(elementId: Id): F[Element]

  def all(): F[List[Element]]

  def delete(elementId: Id): F[Unit]
}

but when I tried to compile it, I got an error:

Error:(8, 7) macro annotation could not be expanded (the most common reason for that is that you need to enable the macro paradise plugin; another possibility is that you try to use macro annotation in the same compilation run that defines it)

I also added addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full) into plugins.sbt file and build.sbt but it did not help. Can you help me to solve it?

My build.sbt file looks like:

addCompilerPlugin(("org.scalameta" % "paradise" % "3.0.0-M11").cross(CrossVersion.full))

lazy val commonSettings = Seq(
  libraryDependencies ++= Seq(
    "org.typelevel" %% "cats-core" % CatsVersion,
    "org.typelevel" %% "cats-effect" % "1.2.0",
    "org.typelevel" %% "cats-tagless-macros" % "0.5",
    "org.typelevel" %% "cats-tagless-legacy-macros" % "0.5",
    "org.typelevel" %% "cats-mtl-core" % "0.5.0",
  )
)

Solution

  • In an empty new project with this build.sbt:

    scalaVersion := "2.12.8"
    
    libraryDependencies ++= Seq(
      "org.typelevel" %% "cats-tagless-macros" % "0.5",
      "org.typelevel" %% "cats-tagless-legacy-macros" % "0.5"
    )
    
    addCompilerPlugin(
      "org.scalameta" % "paradise" % "3.0.0-M11" cross CrossVersion.full
    )
    

    this code:

    import cats.tagless._
    
    case class Element()
    case class Id()
    
    @finalAlg
    @autoFunctorK(true)
    trait MyService[F[_]] {
      def put(element: Element): F[Element]
      def get(elementId: Id): F[Element]
      def all(): F[List[Element]]
      def delete(elementId: Id): F[Unit]
    }
    

    compiles just fine, as advertised here.

    If I remove addCompilerPlugin("org.scalameta" % "paradise" % "3.0.0-M11" cross CrossVersion.full), I get the same error message:

    macro annotation could not be expanded (the most common reason for that is that you need to enable the macro paradise plugin; another possibility is that you try to use macro annotation in the same compilation run that defines it)

    Again, this is as documented, the linked page says:

    The macro annotations (@finalAlg, @autoFunctorK, @autoInvariantK, etc.) still depends on scalameta, so you need to add scalameta dependencies in build.sbt.

    So it seems that you need it because of @finalAlg and @autoFunctorK.

    Note that I didn't modify anything in project/.


    EDIT

    If you have multiple subprojects, you have to add the compiler plugin to the subproject that actually needs it. Notice that

    addCompilerPlugin(foobar)
    

    is essentially just

    libraryDependencies += compilerPlugin(foobar)
    

    so in your case, you probably should try something like

      libraryDependencies ++= Seq(
        "org.typelevel" %% "cats-core" % "1.6.0",
        "org.typelevel" %% "cats-effect" % "1.2.0",
        "org.typelevel" %% "cats-tagless-macros" % "0.5",
        "org.typelevel" %% "cats-tagless-legacy-macros" % "0.5",
        "org.typelevel" %% "cats-mtl-core" % "0.5.0",
        compilerPlugin(("org.scalameta" % "paradise" % "3.0.0-M11")
          .cross(CrossVersion.full))
      )
    

    and then add this to your algebra subproject.