scala.reflect.macros.runtime.MacroRuntimes.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-compiler Show documentation
Show all versions of scala-compiler Show documentation
Compiler for the SubScript extension of the Scala Programming Language
The newest version!
package scala.reflect.macros
package runtime
import scala.reflect.internal.Flags._
import scala.reflect.runtime.ReflectionUtils
trait MacroRuntimes extends JavaReflectionRuntimes {
self: scala.tools.nsc.typechecker.Analyzer =>
import global._
import definitions._
/** Produces a function that can be used to invoke macro implementation for a given macro definition:
* 1) Looks up macro implementation symbol in this universe.
* 2) Loads its enclosing class from the macro classloader.
* 3) Loads the companion of that enclosing class from the macro classloader.
* 4) Resolves macro implementation within the loaded companion.
*
* @return Requested runtime if macro implementation can be loaded successfully from either of the mirrors,
* `null` otherwise.
*/
def macroRuntime(expandee: Tree): MacroRuntime = pluginsMacroRuntime(expandee)
/** Default implementation of `macroRuntime`.
* Can be overridden by analyzer plugins (see AnalyzerPlugins.pluginsMacroRuntime for more details)
*/
private val macroRuntimesCache = perRunCaches.newWeakMap[Symbol, MacroRuntime]
def standardMacroRuntime(expandee: Tree): MacroRuntime = {
val macroDef = expandee.symbol
macroLogVerbose(s"looking for macro implementation: $macroDef")
if (fastTrack contains macroDef) {
macroLogVerbose("macro expansion is serviced by a fast track")
fastTrack(macroDef)
} else {
macroRuntimesCache.getOrElseUpdate(macroDef, new MacroRuntimeResolver(macroDef).resolveRuntime())
}
}
/** Macro classloader that is used to resolve and run macro implementations.
* Loads classes from from -cp (aka the library classpath).
* Is also capable of detecting REPL and reusing its classloader.
*
* When -Xmacro-jit is enabled, we sometimes fallback to on-the-fly compilation of macro implementations,
* which compiles implementations into a virtual directory (very much like REPL does) and then conjures
* a classloader mapped to that virtual directory.
*/
lazy val defaultMacroClassloader: ClassLoader = findMacroClassLoader()
/** Abstracts away resolution of macro runtimes.
*/
type MacroRuntime = MacroArgs => Any
class MacroRuntimeResolver(val macroDef: Symbol) extends JavaReflectionResolvers {
val binding = loadMacroImplBinding(macroDef).get
val isBundle = binding.isBundle
val className = binding.className
val methName = binding.methName
def resolveRuntime(): MacroRuntime = {
if (className == Predef_???.owner.javaClassName && methName == Predef_???.name.encoded) {
args => throw new AbortMacroException(args.c.enclosingPosition, "macro implementation is missing")
} else {
try {
macroLogVerbose(s"resolving macro implementation as $className.$methName (isBundle = $isBundle)")
macroLogVerbose(s"classloader is: ${ReflectionUtils.show(defaultMacroClassloader)}")
resolveJavaReflectionRuntime(defaultMacroClassloader)
} catch {
case ex: Exception =>
macroLogVerbose(s"macro runtime failed to load: ${ex.toString}")
macroDef setFlag IS_ERROR
null
}
}
}
}
}