Skip to content

Annotation macros in Dotty #1694

Closed
Closed
@liufengyun

Description

@liufengyun

We had a discussion before about annotation macros, the idea then was to transform the following annotation macros:

class main extends scala.annotation.StaticAnnotation {
    inline def apply(defn: Any): Any = meta {
       body
    }
}

to:

class main extends scala.annotation.StaticAnnotation {
    inline def apply(defn: Any): Any =  meta {
       main$inline.meta3(defn)
    }
}

object main$inline {
    def meta3(prefix:scala.meta.Stat)(defn: scala.meta.Stat): scala.meta.Stat = body
}

There are some problems with the scheme above. For example, given the code:

@main
class Test {
  println("hello, world!")
}

The namer has a difficulty to determine whether @main is a macros or not and how to expand it. It needs to do as least follows:

  • resolve the name main to a symbol (typedIndent)
    • problem 1: it doesn't work reliably if main is defined in the same compilation run
  • check if main extends scala.annotation.StaticAnnotation
  • check if main has a member inline def apply(defn: Any): Any, and rhs begins with meta.
    • problem 2: Inspect syntactic tree to know some info about a compiled symbol is counter-intuitive, the info should be part of the symbol. Also, ASTs are not always available if @main is defined without tasty (e.g. Scala2).
  • inspect the body of meta to get the implementation method.
    • problem 3: This seems to incur unnecessary complexity, a simpler convention can be that the implementation is defined in main$inline.meta, thus no need to inspect ASTs, which can impose a performance penalty by deserializing tasty.

It seems that annotation macros are somewhat special, different from def macros, inlining never happens for annotation macros. It seems to me that current paradise implementation of annotation macros is simpler (avoids problem 2 & 3), it translates the code:

class main extends scala.annotation.StaticAnnotation {
    inline def apply(defn: Any): Any = meta {
       body
    }
}

to:

class main extends scala.annotation.StaticAnnotation {
    inline def apply(defn: Any): Any =  ???
}

object main$inline {
    def apply(prefix:scala.meta.Stat)(defn: scala.meta.Stat): scala.meta.Stat = body
}

My question is:

  • Can we assume annotation macros are always compiled in a different run (problem 1)?
  • Can we follow paradise's way of handling annotation macros (simpler, avoids problem 2 & 3)?
  • During annotation macros transform, can we only transform inline def apply(defn: Any): Any = meta {...}, and ignore other possible inline/meta methods, as they don't make sense for annotation macros?

WDYT @odersky @xeno-by @DarkDimius ?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions