diff options
4 files changed, 34 insertions, 25 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 4d1ab98fa0..6ed879af14 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -546,6 +546,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { /** Calculate the arguments to pass to a macro implementation when expanding the provided tree. */ case class MacroArgs(c: MacroContext, others: List[Any]) + private def macroArgs(typer: Typer, expandee: Tree): MacroArgs = { val macroDef = expandee.symbol val prefixTree = expandee.collect{ case Select(qual, name) => qual }.headOption.getOrElse(EmptyTree) @@ -574,9 +575,11 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { val preparedArgss: List[List[Any]] = if (fastTrack contains macroDef) { - if (fastTrack(macroDef) validate context) argss + // Take a dry run of the fast track implementation + if (fastTrack(macroDef) validate expandee) argss else typer.TyperErrorGen.MacroPartialApplicationError(expandee) - } else { + } + else { // if paramss have typetag context bounds, add an arglist to argss if necessary and instantiate the corresponding evidences // consider the following example: // diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala index 792a659ad6..039fec8605 100644 --- a/src/compiler/scala/tools/nsc/util/package.scala +++ b/src/compiler/scala/tools/nsc/util/package.scala @@ -69,7 +69,7 @@ package object util { * (to exclude assert, require, etc.) */ def stackTraceHeadString(ex: Throwable): String = { - val frame = ex.getStackTrace.dropWhile(_.getClassName contains "Predef").head + val frame = ex.getStackTrace.dropWhile(_.getClassName contains "Predef") take 1 mkString "" val msg = ex.getMessage match { case null | "" => "" ; case s => s"""("$s")""" } val clazz = ex.getClass.getName.split('.').last diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala index d35ac43424..ac50324fa9 100644 --- a/src/compiler/scala/tools/reflect/FastTrack.scala +++ b/src/compiler/scala/tools/reflect/FastTrack.scala @@ -2,7 +2,9 @@ package scala.tools package reflect import scala.reflect.reify.Taggers -import scala.tools.nsc.typechecker.{Analyzer, Macros} +import scala.tools.nsc.typechecker.{ Analyzer, Macros } +import scala.reflect.runtime.Macros.currentMirror +import scala.reflect.api.Universe /** Optimizes system macro expansions by hardwiring them directly to their implementations * bypassing standard reflective load and invoke to avoid the overhead of Java/Scala reflection. @@ -12,30 +14,32 @@ trait FastTrack { import global._ import definitions._ - import scala.language.implicitConversions - private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers - private implicit def context2macroimplementations(c0: MacroContext): MacroImplementations { val c: c0.type } = new { val c: c0.type = c0 } with MacroImplementations + import treeInfo.Applied + + private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } = + new { val c: c0.type = c0 } with Taggers + private implicit def context2macroimplementations(c0: MacroContext): MacroImplementations { val c: c0.type } = + new { val c: c0.type = c0 } with MacroImplementations + private def make(sym: Symbol)(pf: PartialFunction[Applied, MacroContext => Tree]) = + sym -> new FastTrackEntry(pf) - implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args.c) - type FastTrackExpander = PartialFunction[(MacroContext, Tree), Tree] - case class FastTrackEntry(sym: Symbol, expander: FastTrackExpander) { - def validate(c: MacroContext): Boolean = expander.isDefinedAt((c, c.expandee)) - def run(c: MacroContext): Any = { - val result = expander((c, c.expandee)) - c.Expr[Nothing](result)(c.WeakTypeTag.Nothing) + final class FastTrackEntry(pf: PartialFunction[Applied, MacroContext => Tree]) extends (MacroArgs => Any) { + def validate(tree: Tree) = pf isDefinedAt Applied(tree) + def apply(margs: MacroArgs) = { + val MacroArgs(c, args) = margs + // Macros validated that the pf is defined here - and there's not much we could do if it weren't. + c.Expr[Nothing](pf(Applied(c.expandee))(c))(c.WeakTypeTag.Nothing) } } - lazy val fastTrack: Map[Symbol, FastTrackEntry] = { - var registry = Map[Symbol, FastTrackEntry]() - implicit class BindTo(sym: Symbol) { def bindTo(expander: FastTrackExpander): Unit = if (sym != NoSymbol) registry += sym -> FastTrackEntry(sym, expander) } - materializeClassTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List())) => c.materializeClassTag(tt.tpe) } - materializeWeakTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = false) } - materializeTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = true) } - ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, EmptyTree, expr) } - ReflectRuntimeCurrentMirror bindTo { case (c, _) => scala.reflect.runtime.Macros.currentMirror(c).tree } - StringContext_f bindTo { case (c, app@Apply(Select(Apply(_, parts), _), args)) => c.macro_StringInterpolation_f(parts, args, app.pos) } - registry - } + /** A map from a set of pre-established macro symbols to their implementations. */ + lazy val fastTrack = Map[Symbol, FastTrackEntry]( + make( materializeClassTag) { case Applied(_, ttag :: Nil, _) => _.materializeClassTag(ttag.tpe) }, + make( materializeWeakTypeTag) { case Applied(_, ttag :: Nil, (u :: _) :: _) => _.materializeTypeTag(u, EmptyTree, ttag.tpe, concrete = false) }, + make( materializeTypeTag) { case Applied(_, ttag :: Nil, (u :: _) :: _) => _.materializeTypeTag(u, EmptyTree, ttag.tpe, concrete = true) }, + make( ApiUniverseReify) { case Applied(_, ttag :: Nil, (expr :: _) :: _) => c => c.materializeExpr(c.prefix.tree, EmptyTree, expr) }, + make( StringContext_f) { case Applied(Select(Apply(_, ps), _), _, args) => c => c.macro_StringInterpolation_f(ps, args.flatten, c.expandee.pos) }, + make(ReflectRuntimeCurrentMirror) { case _ => c => currentMirror(c).tree } + ) } diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 13b761086c..9614513458 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -621,6 +621,8 @@ abstract class TreeInfo { * For advanced use, call `dissectApplied` explicitly and use its methods instead of pattern matching. */ object Applied { + def apply(tree: Tree): Applied = new Applied(tree) + def unapply(applied: Applied): Option[(Tree, List[Tree], List[List[Tree]])] = Some((applied.core, applied.targs, applied.argss)) |