Skip to content

Commit ce67870

Browse files
committed
brings macros up to speed
Before reflection refactoring, macro contexts only exposed a mirror. Now it's time to expose both a universe (the compiler instance) and a mirror (a macro-specific symbol resolver). By the way, speaking of mirrors. Macro contexts have their own mirror, which is different from compiler's rootMirror. This is done because macros need to be able to resolve stuff from empty package. Reflection refactoring brought major changes to runtime evaluation, which got dropped from universes and now requires scala-compiler.jar. However there are macro users, who would like to do eval inside macros. To help them we expose `libraryClassLoader` to manually build toolboxes, and also a simple-to-use `c.eval` method. I've also sneakily introduced `c.parse`, because it's something that has also been frequently requested. Moreover, it might help Scaladoc. So I decided that it might be worth it to add this new functionality.
1 parent bdff66e commit ce67870

30 files changed

+293
-119
lines changed

src/compiler/scala/reflect/internal/Definitions.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ trait Definitions extends api.StandardDefinitions {
477477
lazy val MacroContextClass = getClassIfDefined("scala.reflect.makro.Context") // defined in scala-reflect.jar, so we need to be careful
478478
def MacroContextPrefix = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.prefix) else NoSymbol
479479
def MacroContextPrefixType = if (MacroContextClass != NoSymbol) getMemberType(MacroContextClass, tpnme.PrefixType) else NoSymbol
480+
def MacroContextUniverse = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.universe) else NoSymbol
480481
def MacroContextMirror = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.mirror) else NoSymbol
481482
def MacroContextReify = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.reify) else NoSymbol
482483
lazy val MacroImplAnnotation = requiredClass[scala.reflect.makro.internal.macroImpl]

src/compiler/scala/reflect/makro/runtime/Aliases.scala

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,24 @@ package runtime
44
trait Aliases {
55
self: Context =>
66

7-
/** Aliases of mirror types */
8-
override type Symbol = mirror.Symbol
9-
override type Type = mirror.Type
10-
override type Name = mirror.Name
11-
override type Tree = mirror.Tree
12-
// override type Position = mirror.Position
13-
override type Scope = mirror.Scope
14-
override type Modifiers = mirror.Modifiers
15-
override type Expr[+T] = mirror.Expr[T]
16-
override type TypeTag[T] = mirror.TypeTag[T]
17-
override type ConcreteTypeTag[T] = mirror.ConcreteTypeTag[T]
7+
override type Symbol = universe.Symbol
8+
override type Type = universe.Type
9+
override type Name = universe.Name
10+
override type TermName = universe.TermName
11+
override type TypeName = universe.TypeName
12+
override type Tree = universe.Tree
13+
// override type Position = universe.Position
14+
override type Scope = universe.Scope
15+
override type Modifiers = universe.Modifiers
1816

19-
/** Creator/extractor objects for Expr and TypeTag values */
20-
override val TypeTag = mirror.TypeTag
21-
override val ConcreteTypeTag = mirror.ConcreteTypeTag
22-
override val Expr = mirror.Expr
17+
override type Expr[+T] = universe.Expr[T]
18+
override val Expr = universe.Expr
19+
20+
override type TypeTag[T] = universe.TypeTag[T]
21+
override type ConcreteTypeTag[T] = universe.ConcreteTypeTag[T]
22+
override val TypeTag = universe.TypeTag
23+
override val ConcreteTypeTag = universe.ConcreteTypeTag
24+
override def typeTag[T](implicit ttag: TypeTag[T]) = ttag
25+
override def concreteTypeTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag
26+
override def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
2327
}

src/compiler/scala/reflect/makro/runtime/CapturedVariables.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ trait CapturedVariables {
55
self: Context =>
66

77
import mirror._
8+
import universe._
89

9-
def captureVariable(vble: Symbol): Unit = mirror.captureVariable(vble)
10+
def captureVariable(vble: Symbol): Unit = universe.captureVariable(vble)
1011

11-
def referenceCapturedVariable(vble: Symbol): Tree = mirror.referenceCapturedVariable(vble)
12+
def referenceCapturedVariable(vble: Symbol): Tree = universe.referenceCapturedVariable(vble)
1213

13-
def capturedVariableType(vble: Symbol): Type = mirror.capturedVariableType(vble)
14+
def capturedVariableType(vble: Symbol): Type = universe.capturedVariableType(vble)
1415
}

src/compiler/scala/reflect/makro/runtime/Context.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,26 @@ abstract class Context extends scala.reflect.makro.Context
88
with CapturedVariables
99
with Infrastructure
1010
with Enclosures
11+
with Mirrors
1112
with Names
1213
with Reifiers
1314
with FrontEnds
1415
with Settings
1516
with Typers
17+
with Parsers
1618
with Exprs
1719
with TypeTags
20+
with Evals
1821
with Util
1922
with Traces {
2023

21-
val mirror: Global
24+
val universe: Global
2225

23-
val callsiteTyper: mirror.analyzer.Typer
26+
val mirror: MirrorOf[universe.type] = new ContextMirror
27+
28+
val callsiteTyper: universe.analyzer.Typer
2429

2530
val prefix: Expr[PrefixType]
2631

2732
val expandee: Tree
28-
}
33+
}

src/compiler/scala/reflect/makro/runtime/Enclosures.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package runtime
44
trait Enclosures {
55
self: Context =>
66

7+
import universe._
78
import mirror._
89

910
private def site = callsiteTyper.context
@@ -16,7 +17,7 @@ trait Enclosures {
1617
val enclosingApplication: Tree = enclTrees collectFirst { case t: Apply => t } getOrElse EmptyTree
1718
val enclosingClass: Tree = site.enclClass.tree
1819
val enclosingImplicits: List[(Type, Tree)] = site.openImplicits
19-
val enclosingMacros: List[Context] = this :: mirror.analyzer.openMacros // include self
20+
val enclosingMacros: List[Context] = this :: universe.analyzer.openMacros // include self
2021
val enclosingMethod: Tree = site.enclMethod.tree
2122
val enclosingPosition: Position = if (enclPoses.isEmpty) NoPosition else enclPoses.head.pos
2223
val enclosingUnit: CompilationUnit = currentRun.currentUnit
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package scala.reflect.makro
2+
package runtime
3+
4+
import scala.reflect.runtime.{universe => ru}
5+
import scala.tools.reflect.ToolBox
6+
7+
trait Evals {
8+
self: Context =>
9+
10+
private lazy val evalMirror = ru.runtimeMirror(libraryClassLoader)
11+
private lazy val evalToolBox = evalMirror.mkToolBox()
12+
private lazy val evalImporter = ru.mkImporter(universe).asInstanceOf[ru.Importer { val from: universe.type }]
13+
14+
def eval[T](expr: Expr[T]): T = {
15+
val imported = evalImporter.importTree(expr.tree)
16+
evalToolBox.runExpr(imported).asInstanceOf[T]
17+
}
18+
}

src/compiler/scala/reflect/makro/runtime/Exprs.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ package runtime
44
trait Exprs {
55
self: Context =>
66

7-
def Expr[T: TypeTag](tree: Tree): Expr[T] = mirror.Expr[T](mirror.rootMirror, mirror.FixedMirrorTreeCreator(mirror.rootMirror, tree))
7+
def Expr[T: TypeTag](tree: Tree): Expr[T] = universe.Expr[T](mirror, universe.FixedMirrorTreeCreator(mirror, tree))
88
}

src/compiler/scala/reflect/makro/runtime/FrontEnds.scala

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,32 @@ package runtime
44
trait FrontEnds extends scala.tools.reflect.FrontEnds {
55
self: Context =>
66

7+
import universe._
78
import mirror._
89

9-
override type Position = mirror.Position
10+
override type Position = universe.Position
1011

11-
def frontEnd: FrontEnd = wrapReporter(mirror.reporter)
12+
def frontEnd: FrontEnd = wrapReporter(universe.reporter)
1213

1314
def setFrontEnd(frontEnd: FrontEnd): this.type = {
14-
mirror.reporter = wrapFrontEnd(frontEnd)
15+
universe.reporter = wrapFrontEnd(frontEnd)
1516
this
1617
}
1718

1819
def withFrontEnd[T](frontEnd: FrontEnd)(op: => T): T = {
19-
val old = mirror.reporter
20+
val old = universe.reporter
2021
setFrontEnd(frontEnd)
2122
try op
22-
finally mirror.reporter = old
23+
finally universe.reporter = old
2324
}
2425

25-
def echo(pos: Position, msg: String): Unit = mirror.reporter.echo(pos, msg)
26+
def echo(pos: Position, msg: String): Unit = universe.reporter.echo(pos, msg)
2627

27-
def info(pos: Position, msg: String, force: Boolean): Unit = mirror.reporter.info(pos, msg, force)
28+
def info(pos: Position, msg: String, force: Boolean): Unit = universe.reporter.info(pos, msg, force)
2829

29-
def hasWarnings: Boolean = mirror.reporter.hasErrors
30+
def hasWarnings: Boolean = universe.reporter.hasErrors
3031

31-
def hasErrors: Boolean = mirror.reporter.hasErrors
32+
def hasErrors: Boolean = universe.reporter.hasErrors
3233

3334
def warning(pos: Position, msg: String): Unit = callsiteTyper.context.warning(pos, msg)
3435

@@ -39,7 +40,7 @@ trait FrontEnds extends scala.tools.reflect.FrontEnds {
3940
throw new AbortMacroException(pos, msg)
4041
}
4142

42-
def interactive(): Unit = mirror.reporter match {
43+
def interactive(): Unit = universe.reporter match {
4344
case reporter: tools.nsc.reporters.AbstractReporter => reporter.displayPrompt()
4445
case _ => ()
4546
}
Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,52 @@
11
package scala.reflect.makro
22
package runtime
33

4+
import scala.tools.nsc.util.ScalaClassLoader
5+
46
trait Infrastructure {
57
self: Context =>
68

7-
val forJVM: Boolean = mirror.forJVM
9+
val forJVM: Boolean = universe.forJVM
10+
11+
val forMSIL: Boolean = universe.forMSIL
12+
13+
val forInteractive: Boolean = universe.forInteractive
814

9-
val forMSIL: Boolean = mirror.forMSIL
15+
val forScaladoc: Boolean = universe.forScaladoc
1016

11-
val forInteractive: Boolean = mirror.forInteractive
17+
val currentRun: Run = universe.currentRun
1218

13-
val forScaladoc: Boolean = mirror.forScaladoc
19+
val libraryClassPath: List[java.net.URL] = universe.classPath.asURLs
1420

15-
val currentRun: Run = mirror.currentRun
21+
lazy val libraryClassLoader: ClassLoader = {
22+
val classpath = libraryClassPath
23+
var loader: ClassLoader = ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
24+
25+
// [Eugene] a heuristic to detect REPL
26+
if (universe.settings.exposeEmptyPackage.value) {
27+
import scala.tools.nsc.interpreter._
28+
val virtualDirectory = universe.settings.outputDirs.getSingleOutput.get
29+
loader = new AbstractFileClassLoader(virtualDirectory, loader) {}
30+
}
31+
32+
loader
33+
}
1634

17-
type Run = mirror.Run
35+
type Run = universe.Run
1836

1937
object Run extends RunExtractor {
2038
def unapply(run: Run): Option[(CompilationUnit, List[CompilationUnit])] = Some(run.currentUnit, run.units.toList)
2139
}
2240

23-
type CompilationUnit = mirror.CompilationUnit
41+
type CompilationUnit = universe.CompilationUnit
2442

2543
object CompilationUnit extends CompilationUnitExtractor {
2644
def unapply(compilationUnit: CompilationUnit): Option[(java.io.File, Array[Char], Tree)] = Some(compilationUnit.source.file.file, compilationUnit.source.content, compilationUnit.body)
2745
}
2846

2947
val currentMacro: Symbol = expandee.symbol
3048

31-
val globalCache: collection.mutable.Map[Any, Any] = mirror.analyzer.globalMacroCache
49+
val globalCache: collection.mutable.Map[Any, Any] = universe.analyzer.globalMacroCache
3250

33-
val cache: collection.mutable.Map[Any, Any] = mirror.analyzer.perRunMacroCache.getOrElseUpdate(currentMacro, collection.mutable.Map[Any, Any]())
51+
val cache: collection.mutable.Map[Any, Any] = universe.analyzer.perRunMacroCache.getOrElseUpdate(currentMacro, collection.mutable.Map[Any, Any]())
3452
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package scala.reflect.makro
2+
package runtime
3+
4+
import scala.tools.nsc.util.ScalaClassLoader
5+
6+
trait Mirrors {
7+
self: Context =>
8+
9+
import universe._
10+
import definitions._
11+
12+
class ContextMirror extends RootsBase(NoSymbol) {
13+
val universe: self.universe.type = self.universe
14+
def rootLoader: LazyType = rootMirror.rootLoader
15+
16+
val RootPackage = rootMirror.RootPackage
17+
val RootClass = rootMirror.RootClass
18+
val EmptyPackage = rootMirror.EmptyPackage
19+
val EmptyPackageClass = rootMirror.EmptyPackageClass
20+
21+
// [Eugene++] this still doesn't solve the problem of invoking `c.typeCheck` on the code that refers to packageless symbols
22+
override protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = {
23+
if (owner.isRoot && isJavaClass(name.toString)) EmptyPackageClass.info decl name
24+
else NoSymbol
25+
}
26+
27+
private def isJavaClass(path: String): Boolean =
28+
try {
29+
val classpath = platform.classPath.asURLs
30+
var classLoader = ScalaClassLoader.fromURLs(classpath)
31+
Class.forName(path, true, classLoader)
32+
true
33+
} catch {
34+
case (_: ClassNotFoundException) | (_: NoClassDefFoundError) | (_: IncompatibleClassChangeError) =>
35+
false
36+
}
37+
38+
override def toString = "macro context mirror"
39+
}
40+
}

0 commit comments

Comments
 (0)