summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2013-10-02 16:34:59 +0200
committerEugene Burmako <xeno.by@gmail.com>2013-10-02 22:45:58 +0200
commitd627672ec4a10861a659bfaacfaf86aa4b5b4e6e (patch)
treefd8e9af80295bac892e9e684ef4945d9761a3352 /src
parent8aae23ed47c4e38a465ff3373392484ca82473d1 (diff)
downloadscala-d627672ec4a10861a659bfaacfaf86aa4b5b4e6e.tar.gz
scala-d627672ec4a10861a659bfaacfaf86aa4b5b4e6e.tar.bz2
scala-d627672ec4a10861a659bfaacfaf86aa4b5b4e6e.zip
clearly establishes what macro bundles are
Previously it was enough to just extend scala.reflect.macros.Macro, which created some loopholes, but now scalac enforces that bundles: 1) Are static (not necessarily top-level, but just static) 2) Are traits (objects shouldn't be bundles anyway, and classes bring complications with their ctors which require special treatment in generated classes, so why support them if they don't bring anything new to the table?) 3) Are monomorphic (again, this brings unnecessary complications wrt auxiliary code generation, so I don't see merit in supporting polymorphic bundles, whatever that a polymorphic bundle could mean) 4) Don't provide concrete implementation for Macro.c (if they do then what is the point?)
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)