2

I'm investigating the possibility to make the following kind of imports compile in Scala:

def helpers[T] = new { def foo: T = ??? }
import helpers[Int]._

This arose as an idea to pin down some types that Scala could not infer on its own. A manually expanded version works:

val m = helpers[Int]
import m._
(foo: Int)

However, my naive attempt at a macro failed:

import scala.reflect.macros.blackbox.Context

object Open {
  def open[T](m: Any)(t: T): T = macro open_impl[T]

  def open_impl[T](c: Context)(m: c.Tree)(t: c.Tree): c.Tree = {
    import c.universe._
    val freshName = TermName(c.freshName("import$"))
    q"{ val $freshName = $m; import $freshName._; $t }"
  }
}

The syntax I had in mind was the let open M in-syntax from OCaml. Problem being that the binding of variables seems to happen before the macro expansion:

import Open._
object Foo { val x = 7 }
open(Foo) { println(x) }

fails in the REPL with:

<console>:16: error: not found: value x
       open(Foo) { println(x) }

Any ideas how to work around this? Is it at all possible with macros? Or perhaps with a compiler plugin?

  • the `import $freshName._` is expanded inside internal subscope. You can think of whole def macro result as of bunch of code, defined inside the `{...}` – Odomontois Aug 18 '17 at 11:41
  • Knowing that all the expressions are defined inside `class`es, `trait`s, `object`s or `def`s you can define macro annotation that will take some names as parameters and rewrite annotated body, importing content of named things as soon as they defined – Odomontois Aug 18 '17 at 11:48
  • @Odomontois Incorrect. This is a blackbox macro, what you said is only *sort-of* true for whitebox macros. The macro takes as argument the expression to "open" in, so that argument is inside the macro's purview, and your complaint wouldn't be a problem even if the macro was whitebox. The real issue is that macros have to run after the typer. The typer tries to type `{ println(x) }`, notices `x` doesn't exist because macros haven't run yet, and then dies. You can see it if you add `-Ybrowse:all` or `-Xprint:all` to the compiler args. – HTNW Aug 18 '17 at 12:51

0 Answers0