summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-06-06 02:05:10 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-06-08 15:23:11 +0200
commit1708a7fffdb653a638927c2b4ff30a7a0be0f3fe (patch)
tree1d270cc0b3c4a7424f2444a4d1dca460699abb6a /src/compiler/scala/tools
parentfb67a1d3aea159fd39e5c0fad14ffa089a5d6ba5 (diff)
downloadscala-1708a7fffdb653a638927c2b4ff30a7a0be0f3fe.tar.gz
scala-1708a7fffdb653a638927c2b4ff30a7a0be0f3fe.tar.bz2
scala-1708a7fffdb653a638927c2b4ff30a7a0be0f3fe.zip
macros: refactoring of fast track infrastructure
As a result, hardwired macros don't need implementation stubs. This is very important, because in a few commits scala.reflect.makro.Context will move out from scala-library.jar. Also adding fast track entries doesn't require jumping through hoops with PDTs. It's as simple as defining PartialFunction[Tree, Any].
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala245
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala3
-rw-r--r--src/compiler/scala/tools/reflect/FastTrack.scala46
5 files changed, 173 insertions, 135 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index d43dceca58..8895642893 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -7,7 +7,6 @@ import scala.tools.nsc.util.ClassPath._
import scala.reflect.ReflectionUtils
import scala.collection.mutable.ListBuffer
import scala.compat.Platform.EOL
-import scala.reflect.makro.runtime.{Context => MacroContext}
import util.Statistics._
import scala.reflect.makro.util._
import java.lang.{Class => jClass}
@@ -38,7 +37,7 @@ import java.lang.reflect.{Array => jArray, Method => jMethod}
* (Expr(elems))
* (TypeTag(Int))
*/
-trait Macros extends Traces {
+trait Macros extends scala.tools.reflect.FastTrack with Traces {
self: Analyzer =>
import global._
@@ -186,6 +185,12 @@ trait Macros extends Traces {
import typer.context
macroLogVerbose("typechecking macro def %s at %s".format(ddef.symbol, ddef.pos))
+ if (fastTrack contains ddef.symbol) {
+ macroLogVerbose("typecheck terminated unexpectedly: macro is hardwired")
+ assert(!ddef.tpt.isEmpty, "hardwired macros must provide result type")
+ return EmptyTree
+ }
+
if (!typer.checkFeature(ddef.pos, MacrosFeature, immediate = true)) {
macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled")
ddef.symbol setFlag IS_ERROR
@@ -635,39 +640,8 @@ trait Macros extends Traces {
* @return Some(runtime) if macro implementation can be loaded successfully from either of the mirrors,
* None otherwise.
*/
- private type MacroRuntime = List[Any] => Any
+ type MacroRuntime = List[Any] => Any
private val macroRuntimesCache = perRunCaches.newWeakMap[Symbol, Option[MacroRuntime]]
- private lazy val fastTrack: Map[Symbol, MacroRuntime] = {
- import scala.reflect.api.Universe
- import scala.reflect.makro.internal._
- Map( // challenge: how can we factor out the common code? Does not seem to be easy.
- MacroInternal_materializeArrayTag -> (args => {
- assert(args.length == 3, args)
- val c = args(0).asInstanceOf[MacroContext]
- materializeArrayTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]])
- }),
- MacroInternal_materializeErasureTag -> (args => {
- assert(args.length == 3, args)
- val c = args(0).asInstanceOf[MacroContext]
- materializeErasureTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]])
- }),
- MacroInternal_materializeClassTag -> (args => {
- assert(args.length == 3, args)
- val c = args(0).asInstanceOf[MacroContext]
- materializeClassTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]])
- }),
- MacroInternal_materializeTypeTag -> (args => {
- assert(args.length == 3, args)
- val c = args(0).asInstanceOf[MacroContext]
- materializeTypeTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]])
- }),
- MacroInternal_materializeConcreteTypeTag -> (args => {
- assert(args.length == 3, args)
- val c = args(0).asInstanceOf[MacroContext]
- materializeConcreteTypeTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]])
- })
- )
- }
private def macroRuntime(macroDef: Symbol): Option[MacroRuntime] = {
macroTraceVerbose("looking for macro implementation: ")(macroDef)
if (fastTrack contains macroDef) {
@@ -794,15 +768,14 @@ trait Macros extends Traces {
}
}
- /** Should become private again once we're done with migrating typetag generation from implicits */
- def macroContext(typer: Typer, prefixTree: Tree, expandeeTree: Tree): MacroContext { val mirror: global.type } =
+ private def macroContext(typer: Typer, prefixTree: Tree, expandeeTree: Tree): MacroContext =
new {
- val mirror: global.type = global
+ val mirror: self.global.type = self.global
val callsiteTyper: mirror.analyzer.Typer = typer.asInstanceOf[global.analyzer.Typer]
- // todo. infer precise typetag for this Expr, namely the PrefixType member of the Context refinement
- val prefix = Expr(prefixTree)(TypeTag.Nothing)
val expandee = expandeeTree
- } with MacroContext {
+ } with UnaffiliatedMacroContext {
+ // todo. infer precise typetag for this Expr, namely the PrefixType member of the Context refinement
+ val prefix = Expr[Nothing](prefixTree)(TypeTag.Nothing)
override def toString = "MacroContext(%s@%s +%d)".format(expandee.symbol.name, expandee.pos, enclosingMacros.length - 1 /* exclude myself */)
}
@@ -836,96 +809,111 @@ trait Macros extends Traces {
val context = expandee.attachmentOpt[MacroAttachment].flatMap(_.macroContext).getOrElse(macroContext(typer, prefixTree, expandee))
var argss: List[List[Any]] = List(context) :: exprArgs.toList
macroTraceVerbose("argss: ")(argss)
+ val rawArgss =
+ if (fastTrack contains macroDef) {
+ if (fastTrack(macroDef) validate argss) argss
+ else {
+ // if you're getting here, it's not necessarily partial application that is at fault
+ // for example, if a signature of a hardwired macro has been changed without updated FastTrack
+ // then the corresponding partial function in FastTrack will refuse to process the expandee
+ // validation will return false, and control flow will end up here
+ // however, for simplicity sake, I didn't introduce the notion of error handling to FastTrack
+ // so all kinds of validation errors produce `MacroPartialApplicationError`
+ typer.TyperErrorGen.MacroPartialApplicationError(expandee)
+ return None
+ }
+ } else {
+ val ann = macroDef.getAnnotation(MacroImplAnnotation).getOrElse(throw new Error("assertion failed. %s: %s".format(macroDef, macroDef.annotations)))
+ val macroImpl = ann.args(0).symbol
+ var paramss = macroImpl.paramss
+ val tparams = macroImpl.typeParams
+ macroTraceVerbose("paramss: ")(paramss)
+
+ // we need to take care of all possible combos of nullary/empty-paramlist macro defs vs nullary/empty-arglist invocations
+ // nullary def + nullary invocation => paramss and argss match, everything is okay
+ // nullary def + empty-arglist invocation => illegal Scala code, impossible, everything is okay
+ // empty-paramlist def + nullary invocation => uh-oh, we need to append a List() to argss
+ // empty-paramlist def + empty-arglist invocation => paramss and argss match, everything is okay
+ // that's almost it, but we need to account for the fact that paramss might have context bounds that mask the empty last paramlist
+ val paramss_without_evidences = transformTypeTagEvidenceParams(paramss, (param, tparam) => None)
+ val isEmptyParamlistDef = paramss_without_evidences.nonEmpty && paramss_without_evidences.last.isEmpty
+ val isEmptyArglistInvocation = argss.nonEmpty && argss.last.isEmpty
+ if (isEmptyParamlistDef && !isEmptyArglistInvocation) {
+ macroLogVerbose("isEmptyParamlistDef && !isEmptyArglistInvocation: appending a List() to argss")
+ argss = argss :+ Nil
+ }
- val ann = macroDef.getAnnotation(MacroImplAnnotation).getOrElse(throw new Error("assertion failed. %s: %s".format(macroDef, macroDef.annotations)))
- val macroImpl = ann.args(0).symbol
- var paramss = macroImpl.paramss
- val tparams = macroImpl.typeParams
- macroTraceVerbose("paramss: ")(paramss)
-
- // we need to take care of all possible combos of nullary/empty-paramlist macro defs vs nullary/empty-arglist invocations
- // nullary def + nullary invocation => paramss and argss match, everything is okay
- // nullary def + empty-arglist invocation => illegal Scala code, impossible, everything is okay
- // empty-paramlist def + nullary invocation => uh-oh, we need to append a List() to argss
- // empty-paramlist def + empty-arglist invocation => paramss and argss match, everything is okay
- // that's almost it, but we need to account for the fact that paramss might have context bounds that mask the empty last paramlist
- val paramss_without_evidences = transformTypeTagEvidenceParams(paramss, (param, tparam) => None)
- val isEmptyParamlistDef = paramss_without_evidences.nonEmpty && paramss_without_evidences.last.isEmpty
- val isEmptyArglistInvocation = argss.nonEmpty && argss.last.isEmpty
- if (isEmptyParamlistDef && !isEmptyArglistInvocation) {
- macroLogVerbose("isEmptyParamlistDef && !isEmptyArglistInvocation: appending a List() to argss")
- argss = argss :+ Nil
- }
+ // nb! check partial application against paramss without evidences
+ val numParamLists = paramss_without_evidences.length
+ val numArgLists = argss.length
+ if (numParamLists != numArgLists) {
+ typer.TyperErrorGen.MacroPartialApplicationError(expandee)
+ return None
+ }
- // nb! check partial application against paramss without evidences
- val numParamLists = paramss_without_evidences.length
- val numArgLists = argss.length
- if (numParamLists != numArgLists) {
- typer.TyperErrorGen.MacroPartialApplicationError(expandee)
- return None
- }
+ // if paramss have typetag context bounds, add an arglist to argss if necessary and instantiate the corresponding evidences
+ // consider the following example:
+ //
+ // class D[T] {
+ // class C[U] {
+ // def foo[V] = macro Impls.foo[T, U, V]
+ // }
+ // }
+ //
+ // val outer1 = new D[Int]
+ // val outer2 = new outer1.C[String]
+ // outer2.foo[Boolean]
+ //
+ // then T and U need to be inferred from the lexical scope of the call using ``asSeenFrom''
+ // whereas V won't be resolved by asSeenFrom and need to be loaded directly from ``expandee'' which needs to contain a TypeApply node
+ // also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim
+ val resolved = collection.mutable.Map[Symbol, Type]()
+ paramss = transformTypeTagEvidenceParams(paramss, (param, tparam) => {
+ val TypeApply(_, implRefTargs) = ann.args(0)
+ var implRefTarg = implRefTargs(tparam.paramPos).tpe.typeSymbol
+ val tpe = if (implRefTarg.isTypeParameterOrSkolem) {
+ if (implRefTarg.owner == macroDef) {
+ // [Eugene] doesn't work when macro def is compiled separately from its usages
+ // then implRefTarg is not a skolem and isn't equal to any of macroDef.typeParams
+ // val paramPos = implRefTarg.deSkolemize.paramPos
+ val paramPos = macroDef.typeParams.indexWhere(_.name == implRefTarg.name)
+ typeArgs(paramPos).tpe
+ } else
+ implRefTarg.tpe.asSeenFrom(
+ if (prefixTree == EmptyTree) macroDef.owner.tpe else prefixTree.tpe,
+ macroDef.owner)
+ } else
+ implRefTarg.tpe
+ macroLogVerbose("resolved tparam %s as %s".format(tparam, tpe))
+ resolved(tparam) = tpe
+ param.tpe.typeSymbol match {
+ case definitions.TypeTagClass =>
+ // do nothing
+ case definitions.ConcreteTypeTagClass =>
+ if (!tpe.isConcrete) context.abort(context.enclosingPosition, "cannot create ConcreteTypeTag from a type %s having unresolved type parameters".format(tpe))
+ // otherwise do nothing
+ case _ =>
+ throw new Error("unsupported tpe: " + tpe)
+ }
+ Some(tparam)
+ })
+ val tags = paramss.last takeWhile (_.isType) map (resolved(_)) map (tpe => {
+ // generally speaking, it's impossible to calculate erasure from a tpe here
+ // the tpe might be compiled by this run, so its jClass might not exist yet
+ // hence I just pass `null` instead and leave this puzzle to macro programmers
+ val ttag = TypeTag(tpe, null)
+ if (ttag.isConcrete) ttag.toConcrete else ttag
+ })
+ if (paramss.lastOption map (params => !params.isEmpty && params.forall(_.isType)) getOrElse false) argss = argss :+ Nil
+ argss = argss.dropRight(1) :+ (tags ++ argss.last) // todo. add support for context bounds in argss
- // if paramss have typetag context bounds, add an arglist to argss if necessary and instantiate the corresponding evidences
- // consider the following example:
- //
- // class D[T] {
- // class C[U] {
- // def foo[V] = macro Impls.foo[T, U, V]
- // }
- // }
- //
- // val outer1 = new D[Int]
- // val outer2 = new outer1.C[String]
- // outer2.foo[Boolean]
- //
- // then T and U need to be inferred from the lexical scope of the call using ``asSeenFrom''
- // whereas V won't be resolved by asSeenFrom and need to be loaded directly from ``expandee'' which needs to contain a TypeApply node
- // also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim
- val resolved = collection.mutable.Map[Symbol, Type]()
- paramss = transformTypeTagEvidenceParams(paramss, (param, tparam) => {
- val TypeApply(_, implRefTargs) = ann.args(0)
- var implRefTarg = implRefTargs(tparam.paramPos).tpe.typeSymbol
- val tpe = if (implRefTarg.isTypeParameterOrSkolem) {
- if (implRefTarg.owner == macroDef) {
- // [Eugene] doesn't work when macro def is compiled separately from its usages
- // then implRefTarg is not a skolem and isn't equal to any of macroDef.typeParams
-// val paramPos = implRefTarg.deSkolemize.paramPos
- val paramPos = macroDef.typeParams.indexWhere(_.name == implRefTarg.name)
- typeArgs(paramPos).tpe
- } else
- implRefTarg.tpe.asSeenFrom(
- if (prefixTree == EmptyTree) macroDef.owner.tpe else prefixTree.tpe,
- macroDef.owner)
- } else
- implRefTarg.tpe
- macroLogVerbose("resolved tparam %s as %s".format(tparam, tpe))
- resolved(tparam) = tpe
- param.tpe.typeSymbol match {
- case definitions.TypeTagClass =>
- // do nothing
- case definitions.ConcreteTypeTagClass =>
- if (!tpe.isConcrete) context.abort(context.enclosingPosition, "cannot create ConcreteTypeTag from a type %s having unresolved type parameters".format(tpe))
- // otherwise do nothing
- case _ =>
- throw new Error("unsupported tpe: " + tpe)
+ assert(argss.length == paramss.length, "argss: %s, paramss: %s".format(argss, paramss))
+ val rawArgss = for ((as, ps) <- argss zip paramss) yield {
+ if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1)
+ else as
+ }
+ rawArgss
}
- Some(tparam)
- })
- val tags = paramss.last takeWhile (_.isType) map (resolved(_)) map (tpe => {
- // generally speaking, it's impossible to calculate erasure from a tpe here
- // the tpe might be compiled by this run, so its jClass might not exist yet
- // hence I just pass `null` instead and leave this puzzle to macro programmers
- val ttag = TypeTag(tpe, null)
- if (ttag.isConcrete) ttag.toConcrete else ttag
- })
- if (paramss.lastOption map (params => !params.isEmpty && params.forall(_.isType)) getOrElse false) argss = argss :+ Nil
- argss = argss.dropRight(1) :+ (tags ++ argss.last) // todo. add support for context bounds in argss
-
- assert(argss.length == paramss.length, "argss: %s, paramss: %s".format(argss, paramss))
- val rawArgss = for ((as, ps) <- argss zip paramss) yield {
- if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1)
- else as
- }
val rawArgs = rawArgss.flatten
macroTraceVerbose("rawArgs: ")(rawArgs)
Some(rawArgs)
@@ -1124,7 +1112,10 @@ trait Macros extends Traces {
else {
macroLogLite("typechecking macro expansion %s at %s".format(expandee, expandee.pos))
macroArgs(typer, expandee).fold(failExpansion(): MacroExpansionResult) {
- case args @ ((context: MacroContext) :: _) =>
+ // [Eugene++] crashes virtpatmat:
+ // case args @ ((context: MacroContext) :: _) =>
+ case args @ (context0 :: _) =>
+ val context = context0.asInstanceOf[MacroContext]
if (nowDelayed) {
macroLogLite("macro expansion is delayed: %s".format(expandee))
delayed += expandee -> undetparams
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 6d9c9c4ce8..553294d0fe 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1309,9 +1309,9 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
}
List(tree1)
}
- case Import(_, _) => Nil
- case DefDef(mods, _, _, _, _, _) if (mods hasFlag MACRO) => Nil
- case _ => List(transform(tree))
+ case Import(_, _) => Nil
+ case DefDef(mods, _, _, _, _, _) if (mods hasFlag MACRO) || (tree.symbol hasFlag MACRO) => Nil
+ case _ => List(transform(tree))
}
/* Check whether argument types conform to bounds of type parameters */
@@ -1496,7 +1496,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
private def transformCaseApply(tree: Tree, ifNot: => Unit) = {
val sym = tree.symbol
-
+
def isClassTypeAccessible(tree: Tree): Boolean = tree match {
case TypeApply(fun, targs) =>
isClassTypeAccessible(fun)
@@ -1505,7 +1505,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
// the companion class is actually not a ClassSymbol, but a reference to an abstract type.
module.symbol.companionClass.isClass
}
-
+
val doTransform =
sym.isSourceMethod &&
sym.isCase &&
diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
index 329a247106..3033230603 100644
--- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
@@ -1,10 +1,10 @@
package scala.tools.nsc
package typechecker
-import scala.reflect.makro.runtime.{Context => MacroContext}
-
trait StdAttachments {
self: Analyzer =>
+ type UnaffiliatedMacroContext = scala.reflect.makro.runtime.Context
+ type MacroContext = UnaffiliatedMacroContext { val mirror: self.global.type }
case class MacroAttachment(delayed: Boolean, typerContext: Context, macroContext: Option[MacroContext])
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 88118adbe5..a2ef06fe38 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -5213,7 +5213,8 @@ trait Typers extends Modes with Adaptations with Taggings {
}
val isMacroBodyOkay = !tree.symbol.isErroneous && !(tree1 exists (_.isErroneous))
- if (isMacroBodyOkay) computeMacroDefTypeFromMacroImpl(ddef, tree.symbol, tree1.symbol) else AnyClass.tpe
+ val shouldInheritMacroImplReturnType = ddef.tpt.isEmpty
+ if (isMacroBodyOkay && shouldInheritMacroImplReturnType) computeMacroDefTypeFromMacroImpl(ddef, tree.symbol, tree1.symbol) else AnyClass.tpe
}
def transformedOr(tree: Tree, op: => Tree): Tree = transformed.get(tree) match {
diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala
new file mode 100644
index 0000000000..738bcd01a7
--- /dev/null
+++ b/src/compiler/scala/tools/reflect/FastTrack.scala
@@ -0,0 +1,46 @@
+package scala.tools
+package reflect
+
+import scala.reflect.reify.Taggers
+import scala.tools.nsc.typechecker.{Analyzer, Macros}
+
+/** 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.
+ */
+trait FastTrack {
+ self: Macros with Analyzer =>
+
+ import global._
+ import definitions._
+
+ import language.implicitConversions
+ private implicit def context2taggers(c0: MacroContext) : Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers
+
+ implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args)
+ type FastTrackExpander = PartialFunction[(MacroContext, Tree), Tree]
+ case class FastTrackEntry(sym: Symbol, expander: FastTrackExpander) {
+ def validate(argss: List[List[Any]]): Boolean = {
+ val c = argss.flatten.apply(0).asInstanceOf[MacroContext]
+ val isValid = expander isDefinedAt (c, c.expandee)
+ isValid
+ }
+ def run(args: List[Any]): Any = {
+ val c = args(0).asInstanceOf[MacroContext]
+ val result = expander((c, c.expandee))
+ c.Expr[Nothing](result)(c.TypeTag.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) }
+ MacroInternal_materializeArrayTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeArrayTag(u, tt.tpe) }
+ MacroInternal_materializeErasureTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeErasureTag(u, tt.tpe, concrete = false) }
+ MacroInternal_materializeClassTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeClassTag(u, tt.tpe) }
+ MacroInternal_materializeTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, tt.tpe, concrete = false) }
+ MacroInternal_materializeConcreteTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, tt.tpe, concrete = true) }
+ ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, expr) }
+ MacroContextReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, expr) }
+ registry
+ }
+} \ No newline at end of file