use macros in presentation compiler - scala

I am using macros to add synthetic companion objects (with apply method and other stuff) to annotated classes. Such as
#myTransform class Foo(i: Int)
that will output
object Foo {
def apply(i: Int): Foo = new Foo(i)
}
class Foo(i: Int)
Now if I write in the source code of a sub-project that depends on these macros, Foo(1234), this is highlighted as error by IntelliJ IDEA.
Is it possible to configure the presentation compiler of IntelliJ IDEA to respect these kind of macros and invoke them to operate on the properly transformed code, avoiding these highlighting errors?

The IntelliJ Scala plugin now has an API for macro support: https://blog.jetbrains.com/scala/2015/10/14/intellij-api-to-build-scala-macros-support/

Related

Materialize implementation within package

When using a macro to materialize an implementation of a trait, I'd like to create the implementation within a package so that it has access to other package-private classes.
trait MyTrait[T]
object MyTrait {
implicit def materialize[T]: MyTrait[T] = macro materializeImpl[T]
def materializeImpl[T : c.WeakTypeTag](c: blackbox.Context): c.Expr[MyTrait[T]] = {
val tt = weakTypeTag[T]
c.Expr[MyTrait[T]](q"new MyTrait[$tt] {}")
}
}
Is it possible to materialize new MyTrait[$tt] {} within a particular package?
A macro has to expand into an AST which would compile in the place the macro call is in. Since package declarations are only allowed at top-level, and method calls aren't allowed there, the expanded tree can't create anything in another package.
As Alexey Romanov pointed out this is not possible directly. Still if you call only a few methods (and if you use macro, most probably this is so), one possible (but not perfect) workaround might be creating a public abstract class or trait that extends the target trait and "publishes" all the required package private methods as protected proxies. So you can create instances in your macro from inheriting from that abstract class rather than trait. Obviously this trick effectively "leaks" those methods to anyone but thanks to reflection anyone can call any method if he really wants. And abusing this trick will show as deliberate effort to circumvent your separation as the usage of the reflection.

How to find implicit function(s) using Scala metaprogramming?

In scala language, the implicit scope of a class is erased in runtime, e.g. if defining:
case class A(i: Int)
object A {
implicit def toInt(a: A) = a.i
}
Then for an array:
val arr = Array[Any](A(1), 2)
it is impossible to write:
arr.map(_ + 3)
as type A and its implicit scope is removed after being inserted to Array[Any].
This makes some design patterns (e.g. type class lookup) impossible to be applied in runtime (when type information is still partially available). In my case, I would like to write the above program without explicitly stating A in type matching (as in real case the number of classes like A can be countless). Is any scala metaprogramming package (scalameta preferred) capable of doing this in one project? What should I do to tell the Java runtime bytecode to "look for implicit for a runtime class, if not found do something else"?

"dynamically" creating case classes with macros

I would like to create a macro generated hierarchy of sealed abstract and case classes. There was an example similar to this with http://docs.scala-lang.org/overviews/macros/typemacros.html but is is now obsolete. Is this still possible?
I think it would be incredibly powerful to generate a type safe AST for some specified grammar. Ideally with an IDE able to resolve all the classes.
First for some shameless self-promotion: Eugene Burmako and I are giving a talk on type providers, a closely related topic, at Scalar 2014 tomorrow, and I encourage you to take a look at the example project we put together for the talk if you're interested in this kind of thing.
While type macros are no longer supported, you can accomplish essentially the same thing with macro annotations from macro paradise (which is available as a plugin for Scala 2.10 and 2.11):
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.Context
// Add constructor arguments here.
class expand extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro Expander.expand_impl
}
object Expander {
def expand_impl(c: Context)(annottees: c.Expr[Any]*) = {
import c.universe._
annottees.map(_.tree) match {
case List(q"trait $name") => c.Expr[Any](
// Add your own logic here, possibly using arguments on the annotation.
q"""
sealed trait $name
case class Foo(i: Int) extends $name
case class Bar(s: String) extends $name
case object Baz extends $name
"""
)
// Add validation and error handling here.
}
}
}
And then:
scala> #expand trait MyADT
defined trait MyADT
defined class Foo
defined class Bar
defined module Baz
You can add arguments to the annotation that will be available at compile time, allowing you to parse an external resource that you can use to generate the implementation of the ADT, for example.
Macro annotations are very experimental and their status is still up in the air—there's no guarantee that they'll ship with Scala 2.12, for example. Something similar (although not quite so clean) is possible using plain old def macros and structural types—see the example project linked above for more detail and some demonstrations. In any case, this kind of mechanism is of interest to many people, including the developers of Scala's macro system, so even if macro annotations disappear at some point down the road, there's likely to be some way to accomplish what you've described here.

Generating constructor in Scala in IntelliJ IDEA

In Java it's possible to just select "create constructor matching super" (or something pretty similar) and it automatically creates constructor. Is something like that available for Scala?
Example:
class Foo(a:Int, b:Int)
class Bar extends Foo
I'd just hit some hotkey on Bar and it would generate this:
class Bar(a:Int, b:Int) extends Foo(a:Int, b:Int)
As per the IntelliJ IDEA scala plugin version 0.22.302 nothing has changed in code generation functionality. It has only got override & implement methods, companion object and toString options under code generation and no construction generation support yet.

How to create annotations and get them in scala

I want to define some annotations and use them in Scala.
I looked into the source of Scala, found in scala.annotation package, there are some annotations like tailrec, switch, elidable, and so on. So I defined some annotations as them do:
class A extends StaticAnnotation
#A
class X {
#A
def aa() {}
}
Then I write a test:
object Main {
def main(args: Array[String]) {
val x = new X
println(x.getClass.getAnnotations.length)
x.getClass.getAnnotations map { println }
}
}
It prints some strange messages:
1
#scala.reflect.ScalaSignature(bytes=u1" !1* 1!AbCaE
9"a!Q!! 1gn!!.<b iBPE*,7
Ii#)1oY1mC&1'G.Y(cUGCa#=S:LGO/AA!A 1mI!)
Seems I can't get the annotation aaa.A.
How can I create annotations in Scala correctly? And how to use and get them?
FWIW, you can now define scala annotation in scala 2.10 and use reflection to read them back.
Here are some examples:
Reflecting Annotations in Scala 2.10
Could it have something to do with retention? I bet #tailrec is not included in the bytecode getting generated.
If I try to extend ClassfileAnnotation (in order to have runtime retention), Scala tells me that it can't be done, and it has to be done in Java:
./test.scala:1: warning: implementation restriction: subclassing Classfile does not
make your annotation visible at runtime. If that is what
you want, you must write the annotation class in Java.
class A extends ClassfileAnnotation
^
I think you can only define annotations in Java now.
http://www.scala-lang.org/node/106
You can find a nice description of how annotations are to be used in Scala in Programming Scala.
So you can define or use annotations in scala. However there is at least one limitation:
Runtime retention is not quite possible. In theory you should subclass ClassFileAnnotation to achieve this, but currently scalac reports the following warning if you do it:
"implementation restriction: subclassing Classfile does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java."
It also means that your code is fine as it is (at least as fine as it is currently possible in Scala), but the annotation is on the class only during compile time. So you could use it e.g. in compiler plugins, but you will not be able to access it runtime.
With scala 2.11.6, this works to extract values of a annotation:
case class MyAnnotationClass(id: String) extends scala.annotation.StaticAnnotation
val myAnnotatedClass: ClassSymbol = u.runtimeMirror(Thread.currentThread().getContextClassLoader).staticClass("MyAnnotatedClass")
val annotation: Option[Annotation] = myAnnotatedClass.annotations.find(_.tree.tpe =:= u.typeOf[MyAnnotationClass])
val result = annotation.flatMap { a =>
a.tree.children.tail.collect({ case Literal(Constant(id: String)) => doSomething(id) }).headOption
}