summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Errors.scala4
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Resolvers.scala44
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala18
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala4
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala3
5 files changed, 47 insertions, 26 deletions
diff --git a/src/compiler/scala/reflect/macros/compiler/Errors.scala b/src/compiler/scala/reflect/macros/compiler/Errors.scala
index 6ec111cf7c..9b56e417e2 100644
--- a/src/compiler/scala/reflect/macros/compiler/Errors.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Errors.scala
@@ -29,6 +29,10 @@ trait Errors extends Traces {
def MacroImplWrongNumberOfTypeArgumentsError() = implRefError(TypedApplyWrongNumberOfTpeParametersErrorMessage(macroImplRef))
+ def MacroBundleNonStaticError() = implRefError("macro bundles must be static")
+
+ def MacroBundleWrongShapeError() = implRefError("macro bundles must be monomorphic traits extending scala.reflect.macros.Macro and not implementing its `val c: Context` member")
+
// compatibility errors
// helpers
diff --git a/src/compiler/scala/reflect/macros/compiler/Resolvers.scala b/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
index 46c4e24817..f950059be4 100644
--- a/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
@@ -9,7 +9,7 @@ trait Resolvers {
import global._
import analyzer._
- import definitions._
+ import definitions.{EmptyPackageClass => _, _}
import treeInfo._
import gen._
@@ -33,7 +33,7 @@ trait Resolvers {
*/
lazy val macroImplRef: Tree = {
val (maybeBundleRef, methName, targs) = macroDdef.rhs match {
- case Applied(methRef @ Select(bundleRef @ RefTree(qual, bundleName), methName), targs, Nil) =>
+ case Applied(Select(Applied(RefTree(qual, bundleName), _, Nil), methName), targs, Nil) =>
(RefTree(qual, bundleName.toTypeName), methName, targs)
case Applied(Ident(methName), targs, Nil) =>
(Ident(context.owner.enclClass), methName, targs)
@@ -41,30 +41,36 @@ trait Resolvers {
(EmptyTree, TermName(""), Nil)
}
- val untypedImplRef = typer.silent(_.typedType(maybeBundleRef)) match {
- case SilentResultValue(result) if isMacroBundleType(result.tpe) =>
- val bundleClass = result.tpe.typeSymbol
- if (!bundleClass.owner.isPackageClass) abort(macroDef.pos, "macro bundles can only be defined as top-level classes or traits")
+ val untypedImplRef = typer.silent(_.typedTypeConstructor(maybeBundleRef)) match {
+ case SilentResultValue(result) if result.tpe.baseClasses.contains(MacroClass) =>
+ val bundleProto = result.tpe.typeSymbol
+ val bundlePkg = bundleProto.enclosingPackageClass
+ if (!isMacroBundleProtoType(bundleProto.tpe)) MacroBundleWrongShapeError()
+ if (!bundleProto.owner.isStaticOwner) MacroBundleNonStaticError()
- // synthesize the invoker, i.e. given a top-level `trait Foo extends Macro { def expand = ... } `
- // create a top-level definition `class FooInvoker(val c: Context) extends Foo` in MACRO_INVOKER_PACKAGE
- val invokerPid = gen.mkUnattributedRef(nme.MACRO_INVOKER_PACKAGE)
- val invokerName = TypeName(bundleClass.fullName.split('.').map(_.capitalize).mkString("") + nme.MACRO_INVOKER_SUFFIX)
- val invokerFullName = TypeName(s"$invokerPid.$invokerName")
- val existingInvoker = rootMirror.getClassIfDefined(invokerFullName)
- if (!currentRun.compiles(existingInvoker)) {
+ // synthesize the bundle, i.e. given a static `trait Foo extends Macro { def expand = ... } `
+ // create a top-level definition `class Foo$Bundle(val c: Context) extends Foo` in a package next to `Foo`
+ val bundlePid = gen.mkUnattributedRef(bundlePkg)
+ val bundlePrefix =
+ if (bundlePkg == EmptyPackageClass) bundleProto.fullName('$')
+ else bundleProto.fullName('$').substring(bundlePkg.fullName('$').length + 1)
+ val bundleName = TypeName(bundlePrefix + tpnme.MACRO_BUNDLE_SUFFIX)
+ val existingBundle = bundleProto.enclosingPackageClass.info.decl(bundleName)
+ if (!currentRun.compiles(existingBundle)) {
def mkContextValDef(flags: Long) = ValDef(Modifiers(flags), nme.c, TypeTree(ctxTpe), EmptyTree)
val contextField = mkContextValDef(PARAMACCESSOR)
val contextParam = mkContextValDef(PARAM | PARAMACCESSOR)
- val invokerCtor = DefDef(Modifiers(), nme.CONSTRUCTOR, Nil, List(List(contextParam)), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(()))))
- val invoker = atPos(bundleClass.pos)(ClassDef(NoMods, invokerName, Nil, Template(List(Ident(bundleClass)), noSelfType, List(contextField, invokerCtor))))
- currentRun.compileLate(PackageDef(invokerPid, List(invoker)))
+ val bundleCtor = DefDef(Modifiers(), nme.CONSTRUCTOR, Nil, List(List(contextParam)), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(()))))
+ val bundleParent = gen.mkAppliedTypeTree(Ident(bundleProto), bundleProto.typeParams.map(sym => Ident(sym.name)))
+ val bundleTemplate = Template(List(bundleParent), noSelfType, List(contextField, bundleCtor))
+ val bundle = atPos(bundleProto.pos)(ClassDef(NoMods, bundleName, bundleProto.typeParams.map(TypeDef(_)), bundleTemplate))
+ currentRun.compileLate(PackageDef(bundlePid, List(bundle)))
}
// synthesize the macro impl reference, which is going to look like:
- // `new Foo$invoker(???).expand` plus the optional type arguments
- val instanceOfInvoker = New(Select(invokerPid, invokerName), List(List(Select(scalaDot(nme.Predef), nme.???))))
- gen.mkTypeApply(Select(instanceOfInvoker, methName), targs)
+ // `new FooBundle(???).macroName` plus the optional type arguments
+ val bundleInstance = New(Select(bundlePid, bundleName), List(List(Ident(Predef_???))))
+ atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(bundleInstance, methName), targs))
case _ =>
macroDdef.rhs
}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 7555df6775..7b2e40b59c 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -541,6 +541,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val LiftableClass = getClassIfDefined("scala.reflect.api.Liftable") // defined in scala-reflect.jar, so we need to be careful
lazy val MacroClass = getClassIfDefined("scala.reflect.macros.Macro") // defined in scala-reflect.jar, so we need to be careful
+ def MacroContextValue = MacroClass.map(sym => getMemberValue(sym, nme.c))
lazy val MacroContextClass = getClassIfDefined("scala.reflect.macros.Context") // defined in scala-reflect.jar, so we need to be careful
def MacroContextPrefix = MacroContextClass.map(sym => getMemberMethod(sym, nme.prefix))
def MacroContextPrefixType = MacroContextClass.map(sym => getTypeMember(sym, tpnme.PrefixType))
@@ -640,10 +641,21 @@ trait Definitions extends api.StandardDefinitions {
def unspecializedTypeArgs(tp: Type): List[Type] =
(tp baseType unspecializedSymbol(tp.typeSymbolDirect)).typeArgs
- def isMacroBundleType(tp: Type) = {
+ def isMacroBundleType(tp: Type) = tp.baseClasses match {
+ case _ :: proto :: _ if isMacroBundleProtoType(proto.tpe) => true
+ case _ => false
+ }
+
+ def isMacroBundleProtoType(tp: Type) = {
+ val sym = tp.typeSymbol
val isNonTrivial = tp != ErrorType && tp != NothingTpe && tp != NullTpe
- val isMacroCompatible = MacroClass != NoSymbol && tp <:< MacroClass.tpe
- isNonTrivial && isMacroCompatible
+ val isMacroCompatible = MacroClass != NoSymbol && tp.baseClasses.contains(MacroClass)
+ val isBundlePrototype = sym != MacroClass && sym.isTrait && {
+ val c = sym.info.member(nme.c)
+ val cIsOk = c.overrideChain.contains(MacroContextValue) && c.isDeferred
+ cIsOk && sym.isMonomorphicType
+ }
+ isNonTrivial && isMacroCompatible && isBundlePrototype
}
def isIterableType(tp: Type) = tp <:< classExistentialType(IterableClass)
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index c1fd5b3cd6..0aee71c26e 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -214,6 +214,7 @@ trait StdNames {
final val WILDCARD_STAR: NameType = "_*"
final val REIFY_TREECREATOR_PREFIX: NameType = "$treecreator"
final val REIFY_TYPECREATOR_PREFIX: NameType = "$typecreator"
+ final val MACRO_BUNDLE_SUFFIX: NameType = "$Bundle"
final val Any: NameType = "Any"
final val AnyVal: NameType = "AnyVal"
@@ -307,9 +308,6 @@ trait StdNames {
val FAKE_LOCAL_THIS: NameType = "this$"
val LAZY_LOCAL: NameType = "$lzy"
val LAZY_SLOW_SUFFIX: NameType = "$lzycompute"
- val MACRO_INVOKER_PACKAGE: NameType = "scala.reflect.macros.synthetic"
- // TODO: if I use dollars in MACRO_INVOKER_SUFFIX, as in "$Invoker$", then Scala reflection fails to load implementations
- val MACRO_INVOKER_SUFFIX: NameType = "Invoker"
val UNIVERSE_BUILD_PREFIX: NameType = "$u.build."
val UNIVERSE_PREFIX: NameType = "$u."
val UNIVERSE_SHORT: NameType = "$u"
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index e44461f964..720d8bfe4a 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -209,7 +209,8 @@ abstract class TreeGen extends macros.TreeBuilder {
/** Builds a type application node if args.nonEmpty, returns fun otherwise. */
def mkTypeApply(fun: Tree, targs: List[Tree]): Tree =
if (targs.isEmpty) fun else TypeApply(fun, targs)
-
+ def mkAppliedTypeTree(fun: Tree, targs: List[Tree]): Tree =
+ if (targs.isEmpty) fun else AppliedTypeTree(fun, targs)
def mkAttributedTypeApply(target: Tree, method: Symbol, targs: List[Type]): Tree =
mkTypeApply(mkAttributedSelect(target, method), targs map TypeTree)