1

how to generate a private parameterless constructor on a class (at compile time) when it annotated with @entity annotation - in scala 3 macros

class entity extends scala.annotation.StaticAnnotation

@entity
class Student(val id: Long, val name: String) {
  //??? at compile time generates: private def this() = this(0, null)
}
Golden
  • 33
  • 4
  • Scala 3 macros are `def` macros, not annotations. You can't *generate* code with them. https://stackoverflow.com/questions/67770927/macro-annotations-in-scala-3 https://stackoverflow.com/questions/59473523/how-to-generate-a-class-in-dotty-with-macro https://contributors.scala-lang.org/t/scala-3-macro-annotations-and-code-generation/6035 https://users.scala-lang.org/t/macro-annotations-replacement-in-scala-3/7374 – Dmytro Mitin Jan 18 '23 at 13:00
  • 1
    You can generate code at pre-compile time with Scalameta/SemanticDB/Scalafix or at compile time with compiler plugin. – Dmytro Mitin Jan 18 '23 at 13:02
  • 3
    Macro annotations in Scala 3 can be considered WIP at the moment (see: https://contributors.scala-lang.org/t/scala-3-macro-annotations-and-code-generation/6035) but they aren't released, so you can either wait an indefinite time, or use some other approach (type class generation, scalafix rewrites, etc). – Mateusz Kubuszok Jan 19 '23 at 13:20

1 Answers1

0

Starting from Scala 3.3.0-RC2, there appeared macro annotations (implemented by Nicolas Stucki).

Macro annotation (part 1) https://github.com/lampepfl/dotty/pull/16392

Macro annotations class modifications (part 2) https://github.com/lampepfl/dotty/pull/16454

Enable returning classes from MacroAnnotations (part 3) https://github.com/lampepfl/dotty/pull/16534

New definitions are not visible from outside the macro expansion.

The macro annotation adding auxiliary constructor should be the following:

build.sbt

scalaVersion := "3.3.0-RC3"
import scala.annotation.{MacroAnnotation, experimental}
import scala.quoted.*

object Macros:
  @experimental
  class entity extends MacroAnnotation:
    def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] =
      import quotes.reflect.*

      tree match
        case ClassDef(name, constr, parents, selfOpt, body) =>
          val constrSym = Symbol.newMethod(tree.symbol, "<init>", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Unit]))
          val constrDef = DefDef(constrSym, _ => Some(
            Apply(Select.unique(New(Inferred(tree.symbol.typeRef)), "<init>"), List('{0}.asTerm, '{null}.asTerm))
          ))

          val res = List(ClassDef.copy(tree)(name, constr, parents, selfOpt, body :+ constrDef))
          println(res.map(_.show))
          res

        case _ => report.errorAndAbort("@entity can annotate only classes")
import Macros.entity
import scala.annotation.experimental

object App:
  @entity @experimental
  class Student(val id: Long, val name: String)

//scalac: List(@scala.annotation.experimental @Macros.entity class Student(val id: scala.Long, val name: scala.Predef.String) {
//  def this() = new App.Student(0, null)
//})

Macro Annotations in Scala 3

How to generate a class in Dotty with macro?

Scala 3 macro to create enum

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